2010-04-07 22 views
9

Acabo de aferrarme a las mónadas (al menos me gustaría pensar que las tengo) y más específicamente a la mónada estatal, que algunas personas que son mucho más inteligentes que yo descubrieron, así que probablemente sea una forma de hacerlo. esta pregunta.State Monad, ¿por qué no una tupla?

De todos modos, la mónada estado se lleva a cabo generalmente con un M < 'a> como algo parecido a esto (F #):

type State<'a, 'state> = State of ('state -> 'a * 'state) 

Ahora mi pregunta: ¿Hay alguna razón por la cual no se podía usar una tupla ¿aquí? Aparte de la posible ambigüedad entre MonadA<'a, 'b> y MonadB<'a, 'b> que se convertiría en la tupla equivalente ('a * 'b).

Editar: Añadido ejemplo para mayor claridad

type StateMonad() = 
    member m.Return a = (fun s -> a, s) 
    member m.Bind(x, f) = (fun s -> let a, s_ = x s in f a s_) 

let state = new StateMonad() 
let getState = (fun s -> s, s) 
let setState s = (fun _ ->(), s) 
let execute m s = m s |> fst 
+0

¿Cuál es la pregunta? Usa una tupla donde? El tipo de devolución de la función es una tupla. – Brian

+0

No use una tupla en lugar del tipo de estado y simplemente devuelva una función en lugar de un estado. – thr

Respuesta

12

La mónada Estado esencialmente funciona con un tipo de 'state -> 'res * 'state, lo que representa un cálculo que toma algo de estado inicial y produce resultado (junto con un nuevo valor del estado).

Si nos pregunta si hace alguna diferencia si damos algún nombre especial a este tipo (por ejemplo, State<'state, 'res>), entonces la respuesta es que realmente no importa. El único propósito de dar un nombre especial al tipo es que hace que el código sea más legible. Por ejemplo, veamos los dos posibles firmas de tipos del siguiente ejemplo:

let foo n = state { 
    let! m = getState() 
    do! setState(m + 1) 
    return sprintf "Result: %d" (n * m) } 

// Using State<'state, 'res> type: 
val foo : int -> State<int, string> 

// Using the underlying representation: 
val foo : int -> int -> int * state 

El primer tipo de firma más claramente dice que estamos escribiendo la función de alguna mónada. El segundo ejemplo es simplemente una función que toma dos valores de int. Creo que el principal beneficio de la primera es que puede darse cuenta más fácilmente de que el tipo puede usarse desde otro cálculo monádico (escrito usando state { ... }).

Sin embargo, como ya he mencionado, este no es un requisito técnico. La gente probablemente utilizan este estilo, ya que muchas mónadas vienen de Haskell, donde mónadas están asociados con el tipo (como State<'state, 'res>) y no un constructor cómputo (como state), por lo que suena como una buena idea para definir una nuevo tipo para cada mónada en Haskell.

+0

Gracias, sí, no tengo ninguna intención de utilizar la versión de tupla, simplemente estábamos discutiendo sobre IRC (## fsharp @ freenode) y ninguno de nosotros podía ver una razón técnica para el tipo de estado. – thr

5

Ah, sí, si la pregunta es: ¿debo utilizar una sola etiqueta discriminado Unión que lleva un valor de datos de tipo T, o me usa T, entonces puedes usar cualquiera.

En Haskell, debe utilizar una etiqueta de datos con mónadas, ya que la sintaxis Haskell do infiere el tipo de mónada según los tipos de valores (una representación tupla podría ser una instancia de como máximo una única Mónada). Mientras que en F #, las expresiones de cálculo son explícitas sobre el tipo de mónada (por ejemplo, state { ... } o async { ... } o lo que sea) por lo que esta restricción no es necesaria, el mismo tipo de representación podría usarse para múltiples mónadas.

6

El tipo del valor monádico en su ejemplo no es sólo una tupla - es una tupla de regresar función:

'state -> 'res * 'state 

Si estás preguntando si puede utilizar simplemente 'state * 'res como el tipo de la cómputo monádico, entonces la respuesta es no.Eso no funcionaría, porque no hay forma de (de forma segura) implementar la operación de devolución, que debería tener la siguiente firma de tipo:

// how would we get a value of type 'state in the implementation? 
val return : 'a -> 'state * 'a