36 votes

Comment utiliser (->) les instances de Monad et la confusion à propos de (->)

À différentes questions, j'ai trouvé des astuces dans les commentaires concernant l'utilisation de (->) les instances de Monades par exemple pour la réalisation de point de style libre.

Comme pour moi, c'est un peu trop abstrait. Ok, j'ai vu la Flèche instances sur (->) et il me semble que (->) peut être utilisé dans l'exemple notations, mais pas dans les déclarations de type (qui serait seul trucs pour une autre question).

Quelqu'un a des exemples d'utilisation (->) comme instance de Monad? Ou un bon Lien?

Désolé si cette question a déjà été discuté ici, mais de la recherche pour "(->) Monade exemple" vous donne de nombreux de nombreux hits comme vous pouvez l'imaginer ... depuis près de chaque question à propos de haskell quelque part implique (->) ou de "Monade".

31voto

Cactus Points 2028

Pour un type donné, r, la fonction de type r -> a peut être considéré comme un calcul de livrer un a à l'aide d'un environnement typé r. Étant donné deux fonctions r -> a et a -> (r -> b), il est facile d'imaginer que l'on peut composer ces lorsque l'environnement (de nouveau, de type r).

Mais attendez! C'est exactement ce que les monades sont sur le!

Nous pouvons donc créer une instance de Monad pour (->) r qui implémente f >>= g en passant de l' r deux f et g. C'est ce que la Monade exemple pour (->) r n'.

Pour accéder à l'environnement, vous pouvez utiliser id :: r -> r, que vous pouvez maintenant penser comme un calcul exécute dans un environnement r et la réalisation d'un r. Pour créer des sous-environnements, vous pouvez utiliser les éléments suivants:

inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a)
inLocalEnvironment xform f = \env -> f (xform env)

Ce modèle de disposer d'un environnement passé de calculs qui peuvent ensuite d'interroger et de le modifier localement est utile pour non seulement l' (->) r monade, qui est pourquoi il est placé dans l' MonadReader classe, à l'aide de beaucoup plus judicieux de noms que ce que j'ai utilisé ici:

http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-Reader-Class.html

Fondamentalement, il dispose de deux instances: (->) r que nous avons vu ici, et ReaderT r m, qui est juste un newtype wrapper autour de r -> m a, donc c'est la même chose que l' (->) r monade, j'ai décrit ici, sauf qu'il fournit des calculs dans certains autres, transformé monade.

27voto

Edward Kmett Points 18369

Pour définir une monade pour (->) r, nous avons besoin de deux opérations, return et (>>=), sous réserve de trois lois:

instance Monad ((->) r) where

Si l'on regarde le signature de rendement pour l' (->) r

    return :: a -> r -> a

nous pouvons voir son juste la fonction constante, qui ignore son deuxième argument.

    return a r = a

Ou alternativement,

    return = const

Pour construire (>>=), si nous nous spécialisons son type de signature avec la monade (->) r,

    (>>=) :: (r -> a) -> (a -> r -> b) -> r -> b

il n'y a vraiment qu'une seule définition possible.

    (>>=) x y z = y (x z) z

À l'aide de cette monade est comme le passage de l'un argument supplémentaire r pour chaque fonction. Vous pouvez l'utiliser pour la configuration, ou pour passer des options en profondeur dans les entrailles de votre programme.

On peut vérifier que c'est une monade, en vérifiant les trois monade lois:

1. return a >>= f = f a 

return a >>= f 
= (\b -> a) >>= f -- by definition of return
= (\x y z -> y (x z) z) (\b -> a) f -- by definition of (>>=)
= (\y z -> y ((\b -> a) z) z) f -- beta reduction
= (\z -> f ((\b -> a) z) z) -- beta reduction
= (\z -> f a z) -- beta reduction
= f a -- eta reduction

2. m >>= return = m

m >>= return
= (\x y z -> y (x z) z) m return -- definition of (>>=)
= (\y z -> y (m z) z) return -- beta reduction
= (\z -> return (m z) z) -- beta reduction
= (\z -> const (m z) z) -- definition of return
= (\z -> m z) -- definition of const
= m -- eta reduction

La finale de l'errance de la loi:

3. (m >>= f) >>= g  ≡  m >>= (\x -> f x >>= g)

suit par de semblables, facile général paramétré par le raisonnement.

On peut définir un certain nombre d'autres classes pour ((->) r) ainsi, comme Foncteur,

instance Functor ((->) r) where

et si l'on regarde le signature de

   -- fmap :: (a -> b) -> (r -> a) -> r -> b

nous pouvons voir que sa viens de la composition!

   fmap = (.)

De même, nous pouvons faire une instance d' Applicative

instance Applicative ((->) r) where
   -- pure :: a -> r -> a
   pure = const

   -- (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
   (<*>) g f r = g r (f r)

Ce qui est sympa sur le fait d'avoir ces cas, c'est qu'ils vous permettent d'employer tous les Monade et Applicative combinators lors de la manipulation de fonctions.

Il y a beaucoup d'instances de classes impliquant (->), par exemple, vous pourriez vous inscrire à la main l'instance de Monoïde (b -> a), compte tenu d'un Monoïde sur a comme:

enter code here
instance Monoid a => Monoid (b -> a) where
    -- mempty :: Monoid a => b -> a
    mempty _ = mempty
    -- mappend :: Monoid a => (b -> a) -> (b -> a) -> b -> a
    mappend f g b = f b `mappend` g b

mais compte tenu de la Monade/Applicative exemple, vous pouvez également définir cette instance avec

instance Monoid a => Monoid (r -> a) where
    mempty = pure mempty
    mappend = liftA2 mappend

à l'aide de l'Applicatif exemple pour (->) r ou avec

instance Monoid a => Monoid (r -> a) where
    mempty = return mempty
    mappend = liftM2 mappend

à l'aide de la Monade exemple pour (->) r.

Ici, les économies sont minimes, mais, par exemple, l' @pl outil de génération de point de code libre, qui est fourni par lambdabot sur le #haskell canal IRC abus de ces cas tout à fait un peu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X