如何使用( - >)Monad实例和关于( - >)的混淆

mak*_*elc 36 monads haskell functional-programming pointfree

在不同的问题上,我发现了关于使用(->)Monads实例的评论中的提示,例如用于实现无点样式.

至于我,这有点过于抽象.好吧,我已经看到了Arrow实例,在(->)我看来,它(->)可以在实例表示法中使用,但不能在类型声明中使用(这可能只是另一个问题的东西).

有没有任何例子使用(->)Monad的例子?还是一个很好的链接?

很抱歉,如果这个问题可能已经在这里讨论过,但是搜索" (->)Monad实例"会给你很多次点击,因为你可以想象......因为几乎所有关于Haskell的问题都涉及到(->)"Monad".

Cac*_*tus 31

对于给定类型r,类型的函数r -> a可以被认为是a使用所键入的环境来递送的计算r.鉴于两个函数r -> aa -> (r -> b),很容易想象,给定的环境中时(同样,类型的一个可以撰写这些r).

可是等等!这正是monads的意思!

因此,对于我们可以创建单子的实例(->) r实现f >>= g通过传递r到两个fg.这就是Monad实例(->) r所做的.

要实际访问环境,您可以使用id :: r -> r,您现在可以将其视为在环境中运行的计算r并提供r.要创建本地子环境,可以使用以下命令:

inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a)
inLocalEnvironment xform f = \env -> f (xform env)
Run Code Online (Sandbox Code Playgroud)

这种将环境传递给计算然后可以查询并在本地修改它的模式不仅对(->) rmonad 有用,这就是为什么它被抽象到MonadReader类中,使用比我在这里使用的更明智的名称:

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

基本上,它有两个实例:(->) r我们在这里看到的ReaderT r m,它只是一个newtype包装器r -> m a,所以它与(->) r我在这里描述的monad 相同,除了它在其他一些转换后的monad中提供计算.

  • 很好的答案,希望看到一个使用一些monad组合器与这个实例以及它如何展开的例子.例如.`liftM2`. (2认同)

Edw*_*ETT 27

要定义monad (->) r,我们需要两个操作,return(>>=)遵守三个法则:

instance Monad ((->) r) where
Run Code Online (Sandbox Code Playgroud)

如果我们看一下返回的签名 (->) r

    return :: a -> r -> a
Run Code Online (Sandbox Code Playgroud)

我们可以看到它只是常量函数,它忽略了它的第二个参数.

    return a r = a
Run Code Online (Sandbox Code Playgroud)

或者,或者,

    return = const
Run Code Online (Sandbox Code Playgroud)

要构建(>>=),如果我们专门使用monad的类型签名(->) r,

    (>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
Run Code Online (Sandbox Code Playgroud)

实际上只有一个可能的定义.

    (>>=) x y z = y (x z) z
Run Code Online (Sandbox Code Playgroud)

使用这个monad就像r向每个函数传递一个额外的参数.您可以使用它进行配置,或者将选项深入到程序的内容中.

通过验证三个monad定律,我们可以检查它是monad:

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
Run Code Online (Sandbox Code Playgroud)

最终的monad法则:

3. (m >>= f) >>= g  ?  m >>= (\x -> f x >>= g)
Run Code Online (Sandbox Code Playgroud)

通过类似的,简单的等式推理.

我们也可以为(( - >)r)定义许多其他类,例如Functor,

instance Functor ((->) r) where
Run Code Online (Sandbox Code Playgroud)

如果我们看一下签名

   -- fmap :: (a -> b) -> (r -> a) -> r -> b
Run Code Online (Sandbox Code Playgroud)

我们可以看到它的组成!

   fmap = (.)
Run Code Online (Sandbox Code Playgroud)

同样,我们可以做一个实例 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)
Run Code Online (Sandbox Code Playgroud)

有这些实例的好处是它们允许你在操作函数时使用所有MonadApplicative组合器.

有很多类涉及( - >)的实例,例如,你可以手工编写Monoid实例(b - > a),给定一个Monoid on a:

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
Run Code Online (Sandbox Code Playgroud)

但是给定Monad/Applicative实例,您也可以使用

instance Monoid a => Monoid (r -> a) where
    mempty = pure mempty
    mappend = liftA2 mappend
Run Code Online (Sandbox Code Playgroud)

使用Applicative实例(->) r或使用

instance Monoid a => Monoid (r -> a) where
    mempty = return mempty
    mappend = liftM2 mappend
Run Code Online (Sandbox Code Playgroud)

使用Monad实例(->) r.

这里节省的费用很少,但是,例如用于生成无点代码的@pl工具,由#haskell IRC频道上的lambdabot提供,滥用这些实例相当多.