2016-02-03 11 views
9

Ich versuche herauszufinden, wie eine Funktion in Abhängigkeit von einem Modul mit einem parametrischen Typ schreiben, aber ich kann nirgends etwas ähnliches finden. Ich habe versucht, das Problem so weit wie möglich zu reduzieren und endete mit diesem Dummy-Beispiel.Parametric vor Ort abstrakten Typ

module type Mappable = sig 
    type 'a t 
    val map : ('a -> 'b) -> 'a t -> 'b t 
end 

let plus (type m) (module M : Mappable with type 'a t = 'a m) (xs : int m) = 
    M.map (fun x -> x + 1) xs 

, was den Fehler Error: Syntax error: module-expr expected ergibt.

Wenn ich die 'a ablege, erhalte ich den folgenden Fehler.

Error: In this `with' constraint, the new definition of t 
     does not match its original definition in the constrained signature: 
     Type declarations do not match: type t is not included in type 'a t 
     They have different arities. 

Was ist die richtige Syntax, um dies zu tun?

Antwort

7

Ich glaube, was Sie hier tun möchten, ist unmöglich in OCaml 4.02.3. Lassen Sie sehen eine vereinfachte Version ohne die Variable vom Typ:

module type Mappable = sig 
    type t 
    val map : ('a -> 'b) -> t -> t 
end 

let plus (type m) (module M : Mappable with type t = m) (xs : m) = 
    M.map (fun x -> x + 1) xs 

Die oben ist typisierbaren und plus hat den folgenden Typ:

val plus : (module Mappable with type t = 'm) -> 'm -> 'm 

der Typ m in seiner Definition abstrahiert auf eine Variable 'm.

Nun, zurück zu Ihrem ursprünglichen Code und denken Sie, was der Typ plus haben soll. Da Sie zu abstrahieren m von (type m) versuchen, sollte es sein:

val plus : (module Mappable with type 'a t = 'a 'm) -> 'a 'm -> 'a 'm 

Leider hat OCaml nicht den höheren kinded Polymorphismus unterstützen, die 'a 'm diese Form der Art ermöglicht. Es scheint, dass die erste Klasse der Typisierung sorgfältig implementiert wurde, um sie nicht einzuführen.

Sie können das folgende kurze Papier sehen, das den gegenwärtigen (unglücklichen) Status des höheren kinded Polymorphismus in OCaml erklärt. Dies erklärt, eine Abhilfe: Wie es mit Kosten von expliziten coersions im aktuellen OCaml Rahmen zu kodieren:

https://ocamllabs.github.io/higher/lightweight-higher-kinded-polymorphism.pdf

Ich habe noch nie von mir versucht, aber die gleichen Abhilfe zu Ihrem Beispiel angewandt werden könnte.

6

Es ist nicht möglich, in OCaml, da die Typeinschränkung keine reguläre Modultyp Einschränkung ist, sondern ein spezielles syntactic construct, das nicht polymorphe Typen erlaubt:

Die Paket-Typ syntaktische Klasse erscheint in Der Ausdruck vom Typ (Modul-Paket-Typ) und in den annotierten Formularen repräsentiert eine Teilmenge von Modultypen. Diese Teilmenge besteht aus benannten Modultypen mit optionalen Einschränkungen einer begrenzten Form: Es können nur nicht parametrisierte Typen angegeben werden.

Eine übliche Abhilfe, ein Modul zu schaffen sein würde, der alle Variablen vom Typ zu konkreten Typen bindet:

module type Mapper = sig 
    type a 
    type b 
    type src 
    type dst 
    val map : (a -> b) -> src -> dst 
end 

let plus (type src) (type dst) 
    (module M : Mapper with type dst = dst 
         and type src = src 
         and type a = int 
         and type b = int) (xs : src) : dst = 
    M.map (fun x -> x + 1) xs 

In Ihrem speziellen Beispiel gibt es keine Notwendigkeit, 'a und 'b zu binden, da sie sind im wesentlichen nicht verwendet, so kann es zu vereinfachen:

module type Mapper = sig 
    type src 
    type dst 
    val map : ('a -> 'b) -> src -> dst 
end 

let plus (type src) (type dst) 
    (module M : Mapper with type dst = dst 
         and type src = src) (xs : src) : dst = 
    M.map (fun x -> x + 1) xs 

natürlich ist dies sehr einschränkend ist, aber das ist, was mit dem Tag möglich ist.

2

Wenn Sie Module an Funktionen übergeben möchten, sollten Sie verwenden functors statt:

module F (M : Mappable) = struct 
    let plus xs = M.map (fun x -> x + 1) xs 
end 
Verwandte Themen