que - Haskell: intentando desugar la simple mónada de estado ponerse y ponerse
que es una monada programacion funcional (1)
Para estudiar los detalles de la mónada de estado, estoy tratando de crear una versión completa desambiguada de una función de mónada de estado simple, completando el pensamiento iniciado en ¿Cómo ''obtener'' realmente / obtener / el estado inicial en Haskell? , en la respuesta de J Cooper.
La función de mónada de estado de ejemplo simplemente intercambia el estado y el valor de entrada, de modo que (conceptualmente) si la entrada es (v, s), entonces la salida es (s, v). Muestro tres traducciones, primero de notación do a desagrupado >> = y >>, luego colocando esos operadores en posición de función, y finalmente intentando reemplazarlos y poner / poner con sus definiciones.
La versión ''do'' y las primeras dos traducciones funcionan, pero la traducción final no. Problemas:
- Al cargar el módulo, GHCi informa que z1 no está dentro del alcance.
- No he resuelto exactamente cómo representar omitir el argumento que pasa en la >> traducción.
¿Cómo deberían ser arreglados?
FWIW, plataforma Haskell actual (GHC 7.4.2).
¡Gracias!
-- simpleswap
import Control.Monad.State
-- =============================================
-- ''Do'' version
simpleswap1 :: String -> State String String
simpleswap1 inp = do
z1 <- get
put inp
return z1
-- =============================================
-- Desugared to >>= and >>
simpleswap2 :: String -> State String String
simpleswap2 inp =
get >>=
/z1 -> put inp >>
return z1
-- =============================================
-- >>= and >> changed to function position
simpleswap3 :: String -> State String String
simpleswap3 inp =
(>>=) get
(/z1 -> (>>) (put inp) (return z1) )
-- =============================================
-- Attempt to translate >>=, >>, get and put
simpleswap4 :: String -> State String String
simpleswap4 inp =
state $ /s1 ->
-- (>>=)
let (a2, s2) = runState ( {- get -} state $ /sg -> (sg,sg) ) s1
in runState (rhs1 a2) s2
where
rhs1 a2 = /z1 ->
-- (>>)
state $ /s3 ->
let (a4, s4) = runState ( {- put inp -} state $ /_ -> (inp, ()) ) s3
in runState (rhs2 a4) s4
where
rhs2 a4 = return z1
-- =============================================
main = do
putStrLn "version 1004"
let v = "vvv"
let s = "sss"
putStrLn ("Before val: " ++ v ++ " state: " ++ s)
let (v2, s2) = runState (simpleswap4 v) s
putStrLn ("After val: " ++ v2 ++ " state: " ++ s2)
-- =============================================
Hay algunos errores menores en simpleswap4
. Aquí hay una versión corregida:
simpleswap4 :: String -> State String String
simpleswap4 inp =
state $ /s1 ->
-- (>>=)
let (z1, s2) = runState ( {- get -} state $ /sg -> (sg,sg) ) s1
in runState (rhs1 z1) s2
where
rhs1 z1 =
-- (>>)
state $ /s3 ->
let (_, s4) = runState ( {- put inp -} state $ /_ -> ((), inp) ) s3
in runState rhs2 s4
where
rhs2 = return z1
a2
nombre de a2
a z1
(en las líneas 5 y 6). Esto no cambia la semántica, pero enfatizó que el primer componente del par devuelto por la llamada get
desacralizada es en realidad el resultado que se une a z1
en las versiones anteriores de simpleswap
.
El tipo de rhs1
debe ser String -> State String String
. En su versión, obtiene una variable adicional vinculada a lambda. No está claro cuál debería ser la diferencia entre a2
y z1
en su versión. La eliminación de la lambda (en la línea 8) también tiene la ventaja de solucionar su problema de alcance. Está utilizando z1
en la cláusula- where
anidada, pero where
solo puede ver variables vinculadas en el lado izquierdo de la declaración a la que está adjuntado.
En la línea 11, he reemplazado a4
con _
. Esto es para enfatizar que (>>)
descarta el resultado de la primera acción. Como consecuencia, rhs2
tampoco se parametriza sobre este resultado.