我们可以做一些等式推理。首先让我们看一下bar'
。我会写成这个表格
asks bar >>= \z -> return (z i)
事实证明,它liftM
被定义为liftM f m = m >>= \a -> return (f a)
符合上述模式。所以让我们用
liftM ($ i) (asks bar)
然后我们foo
有
liftM show (liftM ($ i) (asks bar))
或者,特别写出来一点
liftM show . liftM ($ i) $ asks bar
如果我们知道那liftM
是fmap
我们可能会认识到Functor
这里的法律
fmap show . fmap ($ i) $ asks bar -- equals
fmap (show . ($ i)) $ asks bar
我个人不太喜欢($ i)
用作函数,所以让我们将其重写为显式 lambda
fmap (\f -> show (f i)) (asks bar)
现在,我们可以决定asks
通过bar
在调用站点使用(即bar
用作类型的函数)来消除bar :: FooEnv -> Int -> Int
fmap (\f -> show (bar f i)) ask
作为最后一个技巧,我们可以flip
在fmap
ped 函数中使用变得毫无意义,甚至返回使用asks
(感谢Ørjan Johansen)
fmap (show . flip bar i) ask -- or even
show . flip bar i <$> ask -- or even
asks (show . flip bar i)
我并不是说这是执行此任务的最易读或最美妙的方式,但您可以看到我们如何使用等式推理来减少碎片。