2010-07-25 10 views
8

Utknąłem z następującym problemem funktora w OCaml. Wklejam kod, abyś zrozumiał. ZasadniczoZrozumienie funktorów w OCaml

zdefiniowałem te dwa moduły w pctl.ml:

module type ProbPA = sig 
    include Hashtbl.HashedType 
    val next: t -> (t * float) list 
    val print: t -> float -> unit 
end 

module type M = sig 
    type s 
    val set_error: float -> unit 
    val check: s -> formula -> bool 
    val check_path: s -> path_formula -> float 
    val check_suite: s -> suite -> unit 
end 

i następujący funktor:

module Make(P: ProbPA): (M with type s = P.t) = struct 
    type s = P.t 
    (* implementation *) 
end 

Wtedy rzeczywiście korzystania z tych modułów I zdefiniowany nowy moduł bezpośrednio w pliku o nazwie prism.ml:

type state = value array 
type t = state 
type value = 
    | VBOOL of bool 
    | VINT of int 
    | VFLOAT of float 
    | VUNSET 
(* all the functions required *) 

Z trzeciego źródła (formulas.ml) użyłem funktor z Prism modułu:

module PrismPctl = Pctl.Make(Prism) 
open PrismPctl 

I wreszcie od main.ml

open Formulas.PrismPctl 
(* code to prepare the object *) 
PrismPctl.check_suite s.sys_state suite (* error here *) 

i kompiluje daje następujący błąd

Error: This expression has type Prism.state = Prism.value array but an expression was expected of type Formulas.PrismPctl.s

Z tego, co mogę zrozumieć jakiś rodzaj złe aliasowanie nazw, są takie same (ponieważ value array jest typem zdefiniowanym jako t i użył M with type s = P.t w funatorze), ale sprawdzanie typu nie uważa ich za takie same.

Naprawdę nie rozumiem, gdzie jest problem, czy ktoś może mi pomóc?

góry dzięki

+0

nie wiem wystarczająco dużo o OCaml pomóc, ale jest to możliwe, że to poprzednie pytanie jest podobny problem? http://stackoverflow.com/questions/640510/functors-in-ocaml – Gian

+0

@Gian: to ten sam problem, ale jeśli to zrozumiesz, jesteś już na najlepszej drodze do tego, aby nie zadawać pytania w pierwsze miejsce. – Gilles

Odpowiedz

6

(Wysyłasz kod niekompilacyjny, jest to zły pomysł, ponieważ może to utrudnić ludziom pomoc, a ponieważ zredukowanie problemu do prostego przykładu czasami wystarcza, aby go rozwiązać, ale myślę, że widzę i tak trudno.)

Wewnątrz formulas.ml, Ocaml może zobaczyć, że PrismPctl.s = Pctl.Make(Prism).t = Prism.t; pierwsza równość pochodzi z definicji PrismPctl, a druga równość pochodzi z sygnatury Pctl.Make (w szczególności z bitu with type s = P.t).

Jeśli nie napiszesz pliku mli dla Formulas, Twój kod powinien się skompilować. Problem polega więc na tym, że napisany przez ciebie plik .mli nie wspomina o równości.Nie pokazywać .mli plików (należy, że są częścią problemu), ale przypuszczalnie napisałeś

module PrismPctl : Pctl.M 

To nie wystarczy: gdy kompilator kompiluje main.ml, to nie wiem nic o PrismPctl nie określono tego w formulas.mli. Musisz określić zarówno

module PrismPctl : Pctl.M with type s = Prism.t 

albo, zakładając, że zawarte with type s = P.t w podpisaniu Make w pctl.mli

module PrismPctl : Pctl.M with type s = Pctl.Make(Prism).s 
+0

To był problem. Zdałem sobie z tego sprawę wczoraj, patrząc na odpowiedź na pytanie związane z Gianem w komentarzu. Nie wkleiłem mojego pliku '.mli', ponieważ zapomniałem go zrobić ... moja wina! Dziękuję Ci – Jack

2

Jest to problem wpadłem jak również gdy czegoś więcej o nich. Podczas tworzenia funktora ujawniasz podpis funktora, w tym przypadku M. Zawiera abstrakcyjny typ s, sparametryzowany przez funktora, a wszystko, co bardziej specyficzne, nie jest eksponowane na zewnątrz. Zatem dostęp do dowolnego elementu rekordu s (jak w przypadku sys_state) spowoduje błąd typu, jaki napotkano.

Reszta wygląda dobrze. Zdecydowanie trudno jest właściwie korzystać z funktorów, ale pamiętaj, że możesz manipulować instancjami typu sparametryzowanymi przez funktora poprzez interfejs/sygnaturę, które są eksponowane przez funktor.