2016-09-23 2 views
0

Supposons que j'ai ces signatures:foncteurs paramétrées

module type CharS = sig 
type c 
    type t = BoW | C of c | EoW 

    val compare : t -> t -> int 

    val print : Format.formatter -> t -> unit 
end 

module type GraphemS = sig 

    type c 
    type t 

    val compare : t -> t -> int 
    val print : Format.formatter -> t -> unit 
end 

Et ces deux foncteurs:

module MakeDiGraphem (C : CharS) : GraphemS with type c = C.t = struct 

    type c = C.t 
    type t = c * c 

    let compare (cb1, ce1) (cb2, ce2) = 
    let r1 = C.compare cb1 cb2 in 
    if r1 = 0 then 
     C.compare ce1 ce2 
    else r1 

    let print fmt (cb, ce) = 
    Format.fprintf fmt "@[%a%[email protected]]@," C.print cb C.print ce 

end 

module MakeMonoGraphem (C : CharS) : GraphemS with type c = C.t = struct 

    type c = C.t 
    type t = c 

    let compare c1 c2 = C.compare c1 c2 

    let print fmt c = 
    Format.fprintf fmt "@[%[email protected]]@," C.print c 

end 

Maintenant, je voudrais avoir un foncteur qui me permettrait de créer un module de type GraphemS avec le premier foncteur ou le second. Ce que je fait est la suivante:

module type SizeS = sig 
    type t = int 

    val param : int 
end 

module MakeGraphem (C : CharS) (I : SizeS) : GraphemS with type c = C.t = struct 
    module MonoGraphem = MakeMonoGraphem(C) 
    module DiGraphem = MakeDiGraphem(C) 

    let select_graphem = 
    if I.param = 1 then 
     (module MonoGraphem : GraphemS) 
    else 
     (module DiGraphem : GraphemS) 

    include (val select_graphem) 

end 

Mais malheureusement je me suis:

Error: This expression creates fresh types.

It is not allowed inside applicative functors.

Ma question est donc, est-il possible de faire ce que je veux faire et qu'est-ce que cela signifie erreur?

Répondre

2

Fondamentalement, vous n'êtes pas autorisé à faire des calculs de première classe dans une application applicative de foncteur. Fondamentalement, le système de frappe n'a aucune garantie que I.param est une constante, donc il ne peut pas garantir que le foncteur retournera toujours le même type. Un foncteur applicatif (la valeur par défaut dans OCaml) doit toujours retourner le même type pour la même expression (dans un sens, c'est pur).

Si vous êtes sur OCaml 4.02 ou plus, vous pouvez déclarer votre foncteur Generative par un unit argument:

module MakeGraphem (C : CharS) (I : SizeS)() : 
      GraphemS with type c = C.t = struct 

Ma façon préférée de faire le tour serait d'obtenir le foncteur d'appliquer comme argument à la place de I.

+0

Désolé pour la réponse tardive, j'essayais de le faire fonctionner parce que j'avais beaucoup de problème de signature. J'ai utilisé le foncteur comme argument (je voulais le faire mais je ne pensais pas que c'était possible, d'où ma triche avec ce "paramètre"). – Lhooq