Monad
Monad
tiene como superclase Applicative
(provee <*>
)Applicative
tiene como superclase Functor
(provee fmap
, ie <$>
)A veces uno quiere combinar dos mónadas, por ejemplo IO
con Maybe
o IO
con Either
, etc.
Para hacer eso se usan “monad transformers”.
El transformador de mónadas WriterT (agrega la capacidad de loguear a una mónada):
https://blog.infinitenegativeutility.com/2016/7/writer-monads-and-space-leaks
Tutorial recomendado para explorar la combinación IO
+ Either
:
https://github.com/kqr/gists/blob/master/articles/gentle-introduction-monad-transformers.md
mtl
Ahí se usan clases de tipos múltiples con functional dependencies.
Son clases de tipos (multiples) que generalizan monad transformers.
¿Qué son monad transformers?
La biblioteca mtl
propone clases que generalizan patrones de monad transformers: http://book.realworldhaskell.org/read/monad-transformers.htm
Generalización de las clases de tipos a más de un tipo
class (Real a, Fractional b) => RealToFrac a b where
realToFrac :: a -> b
instance (Real a, Fractional a) => RealToFrac a a where
realToFrac = id
Del package logfloat http://hackage.haskell.org/package/logfloat/docs/Data-Number-RealToFrac.html
class Eq e => Collection c e where
insert :: c -> e -> c
member :: c -> e -> Bool
instance Eq a => Collection [a] a where
insert xs x = x:xs
member = flip elem
class Monad m => Store store m where
new :: a -> m (store a)
get :: store a -> m a
put :: store a -> a -> m ()
¿Tipo de ex
?
No menciona IO
. ¿Debería?
Tiene solucion: especificar el tipo de ins2
.
Sorprendiente, pero no grave.
Si le agregamos la funcion empty :: c
, ¿qué pasa?
error:
• Could not deduce (Collection c e0)
from the context: Collection c e
bound by the type signature for:
empty :: forall c e. Collection c e => c
The type variable ‘e0’ is ambiguous
• In the ambiguity check for ‘empty’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method:
empty :: forall c e. Collection c e => c
In the class declaration for ‘Collection’
|
| empty :: c
| ^^^^^^^^^^
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleInstances #-}
class Eq e => Collection c e where
empty :: c
instance Collection [Int] Int where
empty = []
En GHCi:
¿Andará?
> empty :: [Int]
<interactive> error:
• Ambiguous type variable ‘e0’ arising from a use of ‘empty’
prevents the constraint ‘(Collection [Int] e0)’ from being solved.
Probable fix: use a type annotation to specify what ‘e0’ should be.
These potential instance exist:
instance [safe] Collection [Int] Int
• In the expression: empty :: [Int]
In an equation for ‘it’: it = empty :: [Int]
Una multiclase define una relación, pero a menudo, lo que queremos realmente es una función.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
class Eq e => Collection c e | c -> e where
empty :: c
insert :: c -> e -> c
member :: c -> e -> Bool
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
class Monad m => Store store m | store -> m where
new :: a -> m (store a)
get :: store a -> m a
put :: store a -> a -> m ()
¿Porqué las multiclases y las funcional dependencies no son parte del sistema de tipos por defecto de Haskell?
Respuesta de unos de los autores de GHC:
Functional dependencies are very, very tricky. Simon Peyton Jones
https://prime.haskell.org/wiki/MultiParamTypeClassesDilemma
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/jfp06.pdf
class Mul a b c | a b -> c where
mul :: a -> b -> c
type Vec b = [b]
instance Mul a b c => Mul a (Vec b) (Vec c) where
mul a bs = map (mul a) bs
f b x y = if b then mul x [y] else y
Consecuencia:
error:
• Reduction stack overflow; size = 201
When simplifying the following type: Mul a0 [Vec c] (Vec c)
En general, funcional dependencies no son sound, complete y decidibles.
Habria que restringirlas.
Práctico: codificar enteros al nivel de los tipos (codificacion unaria) y definir la suma y la multiplicación, listas y ordenamiento de listas:
Fun with functional dependencies (pdf) http://www.cse.chalmers.se/~hallgren/Papers/hallgren.pdf