2014-05-11 26 views
5

próbuję użyć parametryzowane typy w SML ale doesnt't pracy :(Parametryzowane typy w SML

W pierwszym pliku „tree.ml” zdefiniować typ:

type 'a tree = 
    | Node of ('a tree)*('a tree) 
    | Leaf of 'a 

W innym plik „intTree.ml”, używam tego typu do zdefiniowania typu T:

open Tree 
type t = int tree 

Wreszcie, chcę użyć typu T w funkcji „wielkości” w „main.ml”:

open IntTree 

type r = IntTree.t 

let rec size tree = match tree with 
    | Leaf k -> 0 
    | Node (t1,t2) -> 1 + size t1 + size t2 

Kiedy próbuję skompilować te pliki, I uzyskać następujący błąd:

type r 

val size : r -> int 

jeżeli:

File "main.ml", line 6, characters 4-8: 
Error: Unbound constructor Leaf 

Gdybym zdefiniowana "main.mli", to niczego nie zmienia Włożyłem:

let rec size (tree : r) = match tree with 
    | Leaf k -> 0 
    | Node (t1,t2) -> 1 + size t1 + size t2 

mam:

Warning 40: Leaf was selected from type Tree.tree. 
It is not visible in the current scope, and will not 
be selected if the type becomes unknown. 
... 

Wiem, że są to rozwiązania, które szybko rozwiązują ten błąd (na przykład umieszczając "otwarte drzewo typu t = int tree" w pliku main.ml zamiast "otwórz typ IntTree t = IntTree.t"), ale muszę użyj poprzedniej struktury (z innych powodów ...). Czy istnieje rozwiązanie?

Dziękuję

+0

Twój 'main.ml' otwiera' IntTree', więc otrzymuje wszystkie zdefiniowane tam nazwy. Jednakże 'Leaf' nie jest tam zdefiniowany; jest zdefiniowany w 'Tree'. Tak więc, jak mówi Kadaku, powinieneś otworzyć 'Tree' w twoim' main.ml'. Wydaje się, że jest dużo kłopotów, ale to dlatego, że twoje moduły są tak małe.W prawdziwym projekcie masz do kontrolowania więcej nazw. –

+2

Ponadto, zamiast otwierać, osobiście uważam, że bardziej przydatne w dużym projekcie jest użycie w pełni kwalifikowanej nazwy "Tree.Leaf". – nlucaroni

Odpowiedz

5

Trzeba open Tree w main.ml. Nie trzeba kopiować i wklejać deklaracji typu. W twoim kodzie kompilator próbuje odgadnąć, co masz na myśli. Dlatego ręczne dodawanie adnotacji typu częściowo rozwiązuje problem.

kompilator widzi, że można oczekiwać tree być typu r, wygląda na typ r z modułu IntTree (który jest otwierany przez Ciebie) i nie rozumie, że prawdopodobnie mamy to konstruktorów w module Tree. Otwiera go z ostrzeżeniem. Ta funkcja została wprowadzona całkiem niedawno, więc nie daj się przesadzić, że nie jesteś tego świadomy.

4

Innym rozwiązaniem jest, aby to zmienić:

open Tree 

do tego:

include Tree 

w intTree.ml. Pomysł polega na tym, że intTree staje się samowystarczalny, włączając wszystkie definicje z Tree.

0

Podczas dodawania open Tree w „main.ml” rozwiąże problem, może to być korzystne, aby napisać następujące czynności, aby uniknąć zanieczyszczających „main.ml” z ewentualnych nieistotnych definicji z „Tree.mli”:

let rec size tree = match tree with 
    | Tree.Leaf k -> 0 
    | Tree.Node (t1,t2) -> 1 + size t1 + size t2