如何使用( – >)Monad的实例和( – >)混淆
在不同的问题中,我发现了有关使用Monads (->)
实例的注释,例如实现无点风格。
至于我,这太抽象了。 好的,我在(->)
上看到了Arrow实例,在我看来, (->)
可以用于实例符号中,但不能用于types声明中(这只会是另一个问题)。
有没有人使用(->)
作为Monad的实例? 或者一个很好的链接?
对不起,如果这个问题可能已经在这里讨论过,但是search“ (->)
Monad实例”会给你很多点击,因为你可以想象…因为几乎所有关于Haskell的问题都涉及(->)
或者“Monad” 。
对于给定的typesr
,typesr -> a
的函数可以被认为a
使用环境typesr
来传递一个a
的计算。 给定两个函数r -> a
和a -> (r -> b)
,很容易想象当给定一个环境(也是r
types)时可以构成这些r
。
可是等等! 这正是单子的意义!
所以我们可以通过将r
传递给f
和g
来为(->) r
创build一个Monad实例来实现f >>= g
g
。 这是(->) r
的Monad实例。
要实际访问环境,可以使用id :: r -> r
,现在您可以将其视为在环境r
运行并计算r
的计算。 要创build本地子环境,可以使用以下方法:
inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a) inLocalEnvironment xform f = \env -> f (xform env)
这种将环境传递给可以在本地查询并进行修改的环境的模式对于不仅仅是(->) r
monad是有用的,这就是为什么它被抽象到MonadReader
类中,使用比我更多的合理的名字这里用过:
http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-Reader-Class.html
基本上,它有两个例子:我们在这里看到的(->) r
和ReaderT rm
,它只是r -> ma
一个新types包装器,所以它和(->) r
monad I'已经在这里描述了,除了它提供了一些其他转换monad中的计算。
要为(->) r
定义一个monad,我们需要两个操作, return
和(>>=)
,遵循三个定律:
instance Monad ((->) r) where
如果我们看看(->) r
的回报签名
return :: a -> r -> a
我们可以看到它的不变函数,忽略了它的第二个参数。
return ar = a
或者,
return = const
要构build(>>=)
,如果我们用monad (->) r
专门化它的types签名,
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
实际上只有一个可能的定义。
(>>=) xyz = y (xz) z
使用这个monad就好像给每个函数传递一个额外的参数r
。 您可以使用这个configuration,或者将选项传递给程序的深处。
通过validation三个monad法则,我们可以检查它是否是monad:
1. return a >>= f = fa return a >>= f = (\b -> a) >>= f -- by definition of return = (\xyz -> y (xz) z) (\b -> a) f -- by definition of (>>=) = (\yz -> y ((\b -> a) z) z) f -- beta reduction = (\z -> f ((\b -> a) z) z) -- beta reduction = (\z -> faz) -- beta reduction = fa -- eta reduction 2. m >>= return = m m >>= return = (\xyz -> y (xz) z) m return -- definition of (>>=) = (\yz -> y (mz) z) return -- beta reduction = (\z -> return (mz) z) -- beta reduction = (\z -> const (mz) z) -- definition of return = (\z -> mz) -- definition of const = m -- eta reduction
最后的单子法:
3. (m >>= f) >>= g ≡ m >>= (\x -> fx >>= g)
遵循类似的,容易的等式推理。
我们也可以为(( – >)r)定义一些其他的类,例如Functor,
instance Functor ((->) r) where
如果我们看看签名
-- fmap :: (a -> b) -> (r -> a) -> r -> b
我们可以看到它的组成!
fmap = (.)
同样,我们可以制作一个Applicative
实例
instance Applicative ((->) r) where -- pure :: a -> r -> a pure = const -- (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b (<*>) gfr = gr (fr)
有这些实例的好处是他们让你在操作函数时使用所有的Monad和Applicative组合器。
有很多涉及( – >)类的实例,例如,你可以手写一个Monoid实例给(b – > 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 fgb = fb `mappend` gb
但是考虑到Monad / Applicative实例,你也可以用这个实例来定义这个实例
instance Monoid a => Monoid (r -> a) where mempty = pure mempty mappend = liftA2 mappend
使用(->) r
或with的Applicative实例
instance Monoid a => Monoid (r -> a) where mempty = return mempty mappend = liftM2 mappend
(->) r
使用Monad实例。
这里的节省是最小的,但是,例如,生成无点代码的@pl工具,它是由#haskell IRC通道上的lambdabot提供的,这些工具相当多地滥用了这些实例。