Es posible representar casi cualquier tipo que desee. Pero como las operaciones monádicas se implementan de manera diferente para cada tipo, es no posible escribir >>=
una vez y hacer que funcione para cada instancia.
Sin embargo, usted puede escribir funciones genéricas que dependen de pruebas de la instancia de la clase de tipos. Considere e
aquí para ser una tupla, donde fst e
contiene una definición de "enlace" y snd e
contiene una definición de "retorno".
bind = λe. fst e -- after applying evidence, bind looks like λmf. ___
return = λe. snd e -- after applying evidence, return looks like λx. ___
fst = λt. t true
snd = λt. t false
-- join x = x >>= id
join = λex. bind e x (λz. z)
-- liftM f m1 = do { x1 <- m1; return (f x1) }
-- m1 >>= \x1 -> return (f x1)
liftM = λefm. bind e m (λx. return e (f x))
Debería entonces definir una "tupla de pruebas" para cada instancia de Monad. Tenga en cuenta que de la forma en que definimos bind
y return
: funcionan igual que los otros métodos Monad "genéricos" que hemos definido: primero se les debe dar evidencia de Monad-ness, y luego funcionan como se esperaba.
Podemos representar Maybe
como una función que toma 2 entradas, la primera es una función para realizar si es Just x
, y la segunda es un valor para reemplazarla si es Nada.
just = λxfz. f x
nothing = λfz. z
-- bind and return for maybes
bindMaybe = λmf. m f nothing
returnMaybe = just
maybeMonadEvidence = tuple bindMaybe returnMaybe
Las listas son similares, representan una lista como su función de plegado. Por lo tanto, una lista es una función que toma 2 entradas, una "contra" y una "vacía". A continuación, realiza foldr myCons myEmpty
en la lista.
nil = λcz. z
cons = λhtcz. c h (t c z)
bindList = λmf. concat (map f m)
returnList = λx. cons x nil
listMonadEvidence = tuple bindList returnList
-- concat = foldr (++) []
concat = λl. l append nil
-- append xs ys = foldr (:) ys xs
append = λxy. x cons y
-- map f = foldr ((:) . f) []
map = λfl. l (λx. cons (f x)) nil
Either
es también sencillo. Representar un tipo cualquiera como una función que toma dos funciones: una para aplicar si es un Left
, y otra para aplicar si es un Right
.
left = λlfg. f l
right = λrfg. g r
-- Left l >>= f = Left l
-- Right r >>= f = f r
bindEither = λmf. m left f
returnEither = right
eitherMonadEvidence = tuple bindEither returnEither
No se olvide, funciones mismos(a ->)
forma una mónada. Y todo en el cálculo lambda es una función ... así que ... no lo pienses demasiado. ;) Inspirado directamente de la fuente de Control.Monad.Instances
-- f >>= k = \ r -> k (f r) r
bindFunc = λfkr. k (f r) r
-- return = const
returnFunc = λxy. x
funcMonadEvidence = tuple bindFunc returnFunc
Desde cálculo lambda es Turing Completa es posible codificar cualquier proceso computacional en ella. Supongo que la pregunta es exactamente sobre la codificación. Por supuesto, el cálculo sin tipo no tiene tipos, pero es posible codificar algunos objetos que se comportan como tipos y mecanismos de tipeo. Del mismo modo que no tiene bools y números, pero hay codificaciones correspondientes citadas en la pregunta. La [respuesta de Dan] (https://stackoverflow.com/a/8936209/707926) está más en línea con este entendimiento. –