La cosa importante da capire qui è che OCaml esegue l'inferenza di tipo in modo compositivo, cioè, prima dedurrà il tipo di struct ... end
e solo allora corrisponderà ai tipi desunti contro sig ... end
per verificare che la struttura implementa realmente la firma.
Ad esempio, se si scrive
module Monkey : sig val f : int -> int end =
struct
let f x = x
end
poi OCaml saranno felici, come si vedrà che f
ha un tipo polimorfico 'a -> 'a
che può essere specializzata per il tipo richiesto int -> int
. Dato che lo2 rende Monkey
opaco, ovvero la firma nasconde l'implementazione, ti dirà che f
ha il tipo int -> int
, anche se l'implementazione effettiva ha un tipo polimorfico.
Nel vostro caso particolare OCaml prima ne deduce che g
è di tipo 'a -> 'a
, e quindi che il tipo di h
è 'a -> 'a
pure. Quindi conclude che la struttura ha il tipo
sig val g : 'a -> 'a val h : 'a -> 'a end
Successivamente, la firma viene confrontata con quella data. Poiché una funzione di tipo 'a -> 'a
può essere specializzata in int -> int
e string -> string
OCaml conclude che tutto va bene. Naturalmente, l'intero punto di utilizzo di sig ... end
consiste nel rendere la struttura opaca (l'implementazione è nascosta), motivo per cui il numero massimo non espone il tipo polimorfico di g
e h
.
Ecco un altro esempio che mostra come funziona OCaml:
module Cow =
struct
let f x = x
let g x = f [x]
let a = f "hi"
end
module Bull : sig
val f : int -> int
val g : 'b * 'c -> ('b * 'c) list
val a : string
end = Cow
La risposta è
module Cow :
sig
val f : 'a -> 'a
val g : 'a -> 'a list
val a : string
end
module Bull :
sig
val f : int -> int
val g : 'a * 'b -> ('a * 'b) list
val a : string end
end
fonte
2012-06-19 21:03:19
La tua risposta è perfettamente corretto. – gasche
Eccellente, grazie! :-) –