Bonjour,
Ce post est à peu près mon dernier espoir avant d’envoyer un mail sur la ML d’OCaml en espérant que je puisse trouver une réponse positive à mon problème.
Mon problème vient d’une idée toute bête, mais est basée sur le $\lambda$-calcul : comment implémenter un $\lambda$-calcul simple et non typé, qui si je l’étends par exemple avec les constructeurs du produit, je puisse réutiliser un maximum l’implémentation que j’ai de mon $\lambda$-calcul simple.
La solution que j’ai pour le moment est la suivante :
1 2 3 4 5 6 7 8 9 10 11 12 | type 'a _t = [`App of 'a * 'a | `Lam of ('a -> 'a)] type t = t _t let rec step (t:[> `App of 'a * 'a | `Lam of ('a -> 'a)]) (k:'a -> 'a) : 'a = match t with | `App(`Lam f, x) -> f x | `App(t,u) -> `App(step t k, step u k) | `Lam f -> `Lam f | _ -> k t let view_step : t -> t = fun t -> step t (fun x -> assert false) |
On se donne un type polymorphe _t
qu’on implémente par des variants polymorphes afin de l’étendre ensuite. Notre vrai type pour notre $\lambda$-calcul sera t
. Sans variants polymorphes, l’implémentation de t
rquiert d’utiliser l’option rectypes
du compilateur mais avec les variants polymorphes, l’option semble être automatique.
Ensuite, on se donne une fonction step
qui calcule une étape de $\beta$-reduction avec une stratégie similaire à celle d’OCaml (on ne réduit pas sous les abstractions).
Afin de pouvoir l’étendre par la suite, notre fonction prend une fonction qui sera appelée pour les constructeurs qu’elle ne sait pas traiter.
Si on souhaite une fonction step
juste pour notre simple langage, on peut remplacer k
par un assert false
.
Ensuite, on peut étendre notre langage avec des produits de la façon suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | type 'a _u = ['a _t | `Fst of 'a | `Snd of 'a | `Prod of 'a * 'a] type u = u _u let rec step' t k = match t with | `Fst (`Prod(l,r)) -> step' l k | `Snd (`Prod(l,r)) -> step' r k | `Fst t -> begin match step' t k with | `Prod(t,u) -> t | _ as t-> `Fst t end | `Snd t -> begin match step' t k with | `Prod(t,u) -> t | _ as t-> `Fst t end | `Lam _ | `App _ as t-> step t (fun x -> step' x k) | _ -> k t let view_step' : u -> u = fun t -> step' t (fun x -> assert false) |
Pour le moment, les types sont inutiles en fait, pour le moment ils sont là seulement à titre d’indication. Mon problème est le suivant : J’aimerai écrire la signature de module suivante (la signature n’est pas fixe) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | module type View = sig type view val step : view -> view end module type Sig = sig type 'a t val step : 'a t -> ('a -> 'a) -> 'a module View:View end |
De telle sorte à ce que je puisse encapsuler notre premier calcul dans un module de type Sig
, et le second dans un foncteur de type Sig -> Sig
.
La question est donc la suivante : est-il possible d’écrire la signature du module Sig
?
Avec la signature que j’ai donnée plus haut, OCaml se plaint car le type de step n’est pas bon :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Error: Signature mismatch: Modules do not match: sig type 'a t = [ `App of 'a * 'a | `Lam of 'a -> 'a ] val step : ([> `App of 'a * 'a | `Lam of 'a -> 'a ] as 'a) -> ('a -> 'a) -> 'a end is not included in Sig Values do not match: val step : ([> `App of 'a * 'a | `Lam of 'a -> 'a ] as 'a) -> ('a -> 'a) -> 'a is not included in val step : 'a t -> ('a -> 'a) -> 'a |
En fait, j’aimerai indiqué à OCaml que la fonction puisse prendre au moins du ’a t :
1 2 3 4 5 6 7 8 | module type Sig = sig type 'a t val step : [>'a t] -> ('a -> 'a) -> 'a module View:View end |
Mais ce n’est pas permi car il ne sait pas que 'a t
est un variant polymorphe. Et je ne souhaite pas expliciter le type de 'a t
sinon je ne peux pas avoir un foncteur pour le produit par exemple.
Je suis à l’écoute de toutes vos solutions, y compris changer initialement mes types tant que je peux avoir une signature Sig
qui représente ma théorie de base et rajouter le produit serait un foncteur en OCaml de Sig -> Sig
.