2009-12-31 12 views
23

można następujące funkcje polimorficznewyższego rzędu konstruktorów typu i funktory w SML

let id x = x;; 
let compose f g x = f (g x);; 
let rec fix f = f (fix f);;  (*laziness aside*) 

być napisane dla typów/konstruktorów typu lub modułów/funktorów? Próbowałem dla niektórych typów, ale nie działa.

Oto wersja Haskell dla typów:

data Id x = Id x 
data Compose f g x = Compose (f (g x)) 
data Fix f = Fix (f (Fix f)) 

-- examples: 
l = Compose [Just 'a'] :: Compose [] Maybe Char 

type Natural = Fix Maybe -- natural numbers are fixpoint of Maybe 
n = Fix (Just (Fix (Just (Fix Nothing)))) :: Natural -- n is 2 

-- up to isomorphism composition of identity and f is f: 
iso :: Compose Id f x -> f x 
iso (Compose (Id a)) = a 
+1

ja "nie jestem w 100% pewien, ponieważ nie wiem, Haskell i jestem jasne, na co Skomponuj FGX = ... faktycznie oznacza w Haskell, ale może być zainteresowany, aby wiedzieć, że wersja rozwojowa OCAML ma moduły pierwszej klasy – nlucaroni

+1

Jestem prawie pewny, że nie możesz tego zrobić w ML, ponieważ potrzebujesz polimorfizmu o wyższym czynniku, czy możesz podać przykłady tego, jak używałbyś tych typów w Haskell? –

+0

nlucaroni, bardzo interesujące! (Link jest http://caml.inria.fr/cgi-bin/viewcvs.cgi/ocaml/branches/fstclassmod/ Wierzę) Chris Conway, dodałem kilka przykładów: – sdcvvc

Odpowiedz

29

Haskell pozwala wpisać zmienne wyższego rodzaju. Dialekty ML, w tym Caml, dopuszczają tylko zmienne typu "*". Tłumaczone na prostym języku angielskim,

  • W Haskell, typ zmiennej g może odpowiadać „konstruktora typu” jak Maybe lub IO lub list. Tak więc g x w twoim przykładzie Haskell byłoby OK (żargon: "dobrze-dopieszczony"), jeśli na przykład g jest Maybe i x jest Integer.

  • w ml, typ zmiennej 'g mogą odpowiadać jedynie do „rodzaju gruntu” jak int lub string, nigdy do konstruktora typu jak option lub list. Dlatego jest to prawidłowe, aby próbować zastosować zmienną typu do innego typu.

O ile mi wiadomo, nie ma głębokiej przyczyny tego ograniczenia w ML. Najbardziej prawdopodobnym wyjaśnieniem jest historyczny przypadek. Kiedy Milner początkowo wymyślił swoje koncepcje dotyczące polimorfizmu, pracował z bardzo prostymi zmiennymi typu stojącymi tylko za monotypami rodzaju *. Wczesne wersje Haskella robiły to samo, a potem Mark Jones odkrył, że wnioskowanie o rodzajach zmiennych jest całkiem proste. Haskell został szybko zmieniony, aby umożliwić zmienne typu wyższego rodzaju, ale ML nigdy go nie dogonił.

Ludzie z INRII wprowadzili wiele innych zmian w ML i jestem nieco zaskoczony, że nigdy tego nie zrobili. Kiedy programuję w ML, może mi się podobać posiadanie zmiennych o wyższych parametrach. Ale ich tam nie ma i nie znam żadnego sposobu na zakodowanie przykładów, o których mówisz, chyba że używasz functors.

+0

Cóż, Ocaml został po raz pierwszy wydany w 1996 r., kiedy to ograniczenie polimorfizmu letniego było łatwym sposobem na zapewnienie pełnego wnioskowania o typie i zasadności świst. Nie wiem, jakie jest twoje odniesienie do "dość łatwego", ale rekonstrukcja typu dla polimorfizmu rangowego 2 została znaleziona tylko w [1999] (http://dx.doi.org/10.1145/292540.292556). I oczywiście jest to nierozstrzygalne dla rangi 3 i wyższych (tamże). – huitseeker

+3

@huitseeker: Pytanie nie dotyczy typów rang-2 (gdzie zagnieżdżasz kwantyfikator 'forall' w Haskell), ale o typach wyższego rzędu (gdzie zagnieżdżasz' -> '). – sdcvvc

+0

Wyjaśnienie "głębokiego powodu" [tutaj] (https://news.ycombinator.com/item?id=12331905), [tutaj] (http://lambda-the-ultimate.org/node/5391), oraz w sekcji _1.1. Problem dotyczący aliasu na stronie [2] (https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf#page=2) _Lekki Polimorfizm wyższej jakości. Udoskonalenie (typu abstrakcyjnego) modelu HKT w DOT Scala, również [wystawił] (http://archive.is/KbljQ#selection-8135.21-8147.41) problem z wnioskiem. Abstrakcyjne typy zależne [obejmują typ podpisu] (http://lambda-the-ultimate.org/node/5121#comment-84669). –

17

Możesz zrobić coś podobnego w OCaml, używając modułów zamiast typów i funktorów (moduły wyższego rzędu) zamiast typów wyższego rzędu. Wygląda jednak o wiele brzydiej i nie ma zdolności do wnioskowania o typ, więc musisz ręcznie określić wiele rzeczy.

module type Type = sig 
    type t 
end 

module Char = struct 
    type t = char 
end 

module List (X:Type) = struct 
    type t = X.t list 
end 

module Maybe (X:Type) = struct 
    type t = X.t option 
end 

(* In the following, I decided to omit the redundant 
    single constructors "Id of ...", "Compose of ...", since 
    they don't help in OCaml since we can't use inference *) 

module Id (X:Type) = X 

module Compose 
    (F:functor(Z:Type)->Type) 
    (G:functor(Y:Type)->Type) 
    (X:Type) = F(G(X)) 

let l : Compose(List)(Maybe)(Char).t = [Some 'a'] 

module Example2 (F:functor(Y:Type)->Type) (X:Type) = struct 
    (* unlike types, "free" module variables are not allowed, 
    so we have to put it inside another functor in order 
    to scope F and X *) 
    let iso (a:Compose(Id)(F)(X).t) : F(X).t = a 
end 
+0

Dodaj moduł odpowiadający konstruktorowi typu Fix pytania. – Romildo

0

Cóż ... Nie jestem ekspertem od typów wyższego rzędu ani programowaniem Haskella. Ale to wydaje się być ok dla F # (co jest OCaml), można pracować z nich:

type 'x id = Id of 'x;; 
type 'f fix = Fix of ('f fix -> 'f);; 
type ('f,'g,'x) compose = Compose of ('f ->'g -> 'x);; 

ostatni I zawinięte do krotki jak nie wymyślić nic lepszego ...

+0

Jednak miałem na myśli coś w rodzaju '(list, option, int) compose', które byłoby równoważne z' (lista opcji int '). – sdcvvc

+0

Myślę, że można to zrobić za pomocą typów opcji. W F # można również w .NET-sposób używać wielu typów params: type compose <'f, 'g, 'x> = Compose of ('f ->' g -> 'x) ;; ale może to nie być prawdziwa składnia OCaml. –

-1

Można to zrobić, ale trzeba zrobić trochę trick:

newtype Fix f = In{out:: f (Fix f)} 

Można zdefiniować Cata potem:

Cata :: (Functor f) => (f a -> a) -> Fix f -> a 
Cata f = f.(fmap (cata f)).out 

To będzie określić ogólny catamorphism dla wszystkich funktorów, które możesz użyć do budowania własnych rzeczy. Przykład:

data ListFix a b = Nil | Cons a b 
data List a = Fix (ListFix a) 
instance functor (ListFix a) where 
fmap f Nil = Nil 
fmap f (Cons a lst) = Cons a (f lst) 
+2

Pytanie dotyczy funktorów Ocaml (innych niż funktory Haskella). – sdcvvc

+0

Przepraszamy, błędnie przeczytałem pytanie. W każdym razie, miej nadzieję, że to pomaga każdemu, kto zetknie się z tym –

Powiązane problemy