2011-04-30 24 views
13

Estaba intentando implementar la mónada de estado en OCaml (como ejercicio). Mi aplicación es el siguiente:Mónada de estado en OCaml

module type MONAD_BUILDER = 
sig 
    type 'a t 
    val return : 'a -> 'a t 
    val bind : 'a t -> ('a -> 'b t) -> 'b t 
end;; 

module MonadBuilder = functor (M: MONAD_BUILDER) -> 
struct 
    let (>>=) = M.bind 
    let return = M.return 
end;; 

module StateM = 
struct 
    type 'a state = { state: 's . 's -> ('a * 's) } 
    type 'a t = 'a state 
    let return x = { state = fun s -> (x, s) } 
    let bind m f = 
    let aux s = 
     let (x, s') = m.state s in 
     (f x).state s' 
    in { state = aux } 
    let run m x = fst (m.state x) 
end;; 

yo elegimos el tipo existencial para el campo de registro, ya que no me gusta la idea de usar un funtor y envolviendo el tipo de estado en un módulo. La implementación anterior funciona, pero I se encontró con un problema al implementar getState y setState. Intenté implementarlos como:

let getState = { state = fun s -> (s, s) } 

let setState s = { state = fun _ -> ((), s) } 

Esto no funciona dado que los tipos de campo inferidos, p. Ej. 'a -> ('a * 'a) y 'a -> (unit * 'a), son menos genéricos que el tipo declarado 's . 's -> ('a * 's). Entiendo por qué sucede esto, pero me preguntaba si hay otra forma de hacerlo funcionar utilizando el enfoque de registro.

Gracias.

Cheers, Alex

Respuesta

12

's. 's -> ('a * 's) es un tipo universal. Va a tener dificultades para implementar un estado con tipos universales ...

No hay una forma clara de encapsular un tipo existencial allí sin usar un módulo (porque los tipos abstractos son para qué tipo de resumen son).

Se podría, por supuesto, publicar el tipo de estado en su lugar:

type ('a,'s) state = { state : 's -> ('a * 's) } 

O incluso más corto,

type ('a,'s) state = 's -> 'a * 's 

Con el parámetro adicional, su código se ejecuta. Sin embargo, te encuentras con el hecho de que tu parámetro debe ser manejado por la mónada. Por lo tanto, puede ocultarlo en la construcción de la mónada:

module Monad = MonadBuilder(struct 
    include StateM 
    type 'a t = ('a,myStateType) state 
end) 

o alterar su diseño mónada incorporar un parámetro de tipo adicional que se va a utilizar para este tipo existencial:

module type MONAD_BUILDER = 
sig 
    type ('a,'param) t 
    val return : 'a -> ('a,'param) t 
    val bind : ('a,'param) t -> ('a -> ('b,'param) t) -> ('b,'param) t 
end;; 
+0

Gracias por la respuesta. – Alex

Cuestiones relacionadas