我正在阅读Conor McBride和Ross Paterson的“功能性珍珠/成语:带效果的应用编程:”( new 版本,标题中带有“成语”)。我对练习4有点困难,这将在下面解释。任何提示都会非常感激(特别是:我应该开始撰写fmap
和join
或return
和>>=
吗?)。
您想要创建一个instance Monad []
return x = repeat x
和ap = zapp
。
如同p。在论文的第2篇中,ap
将monadic函数值应用于monadic值。
ap :: Monad m => m (s -> t) -> m s -> m t
ap mf ms = do
f <- mf
s <- ms
return (f s)
我将规范符号扩展为
ap mf ms = mf >>= (\f -> (ms >>= \s -> return (f s)))
特定于列表的函数zapp
(“zippy application”)将一个列表中的函数应用于另一个列表中的对应值,即
zapp (f:fs) (s:ss) = f s : zapp fs ss
请注意,在展开的表单中,mf :: m (a -> b)
是我们案例中的函数列表[(a -> b)]
。因此,在>>=
的第一个应用中,我们有
(f:fs) >>= mu
其中mu = (\f -> (ms >>= \s -> return (f s)))
。现在,我们可以将fs >>= mu
作为子例程调用,但是这不知道要删除ms
的第一个元素。 (回想一下,我们希望得到的结果列表是[f1 s1,f2 s2,...]。我试图破解一些东西但是...正如预测的那样,它没有用......任何帮助都会非常感激。< / p>
提前致谢!
我想我得到了它的工作;首先,我使用ap
和fmap
重写join
作为用户“comonad”建议。
我的信仰的飞跃是假设fmap = map
。如果有人能解释如何到达那里,我会非常感激。在此之后,显然join
适用于用户“comonad”建议的列表列表,并且应该是对角线\x -> zipWith ((!!) . unL) x [0..]
。我的完整代码是:
newtype L a = L [a] deriving (Eq, Show, Ord)
unL (L lst) = lst
liftL :: ([a] -> [b]) -> L a -> L b
liftL f = L . f . unL
joinL :: L (L a) -> L a
joinL = liftL $ \x -> zipWith ((!!) . unL) x [0..]
instance Functor L where
fmap f = liftL (map f)
instance Monad L where
return x = L $ repeat x
m >>= g = joinL (fmap g m)
希望这是正确的(似乎是本文第18页的“解决方案”)...感谢大家的帮助!
答案 0 :(得分:11)
嗯。我不禁想到这次演习有点不公平。
练习4(colist Monad)
虽然
repeat
和zapp
不是通常return
实例的ap
和Monad []
, 它们是替代monad的return
和ap
,更适合 对[]
的共同解释。这个monad的join :: [[x]] → [x]
是什么?评论此monad的
ap
和zapp
的相对效率。
首先,我非常确定有问题的monad实例对[]
一般无效。当他们说“coinductive explain”时,我怀疑这是指无限列表。在某些情况下,实例实际上对有限列表有效,但一般不适用于任意列表。
这是你的第一个,非常一般的提示 - 为什么monad实例只对某些列表有效,特别是无限的?
这是您的第二个提示:fmap
和return
在本文前面的其他定义中是微不足道的。你已经有return
; fmap
只是略显不明显。
此外,(>>=)
在其他功能方面也很容易实现,就像任何Monad
一样,join
是问题的关键。在大多数情况下(>>=)
对于编程来说更自然,但join
在概念上更具基础性,在这种情况下,我认为,分析更直接。所以我建议你继续努力,暂时忘掉(>>=)
。实施后,您可以返回并重新构建(>>=)
并检查monad法则以确保一切正常。
最后,假设您有fmap
可用,但没有别的。给定类型为[a -> b]
和[a]
的值,您可以将它们组合起来以获得[[b]]
类型的值。此处join
的类型为[[a]] -> [a]
。您如何撰写join
,以便在此处获得与使用zapp
原始值相同的结果?请注意,关于相对效率的问题以及问题是关于实施的线索。
答案 1 :(得分:7)
我只是想我应该澄清一下,标题中带有练习和“成语”的版本是该论文的早期早期草案,最终出现在JFP中。当时,我错误地认为colists(我的意思是可能是无限的,可能是有限的列表)是一个monad,其方式与zapp相对应:有一个似乎合理的候选者(在其他答案中提到)但是Jeremy Gibbons很友好地向我们指出它不符合monad法则。反例涉及具有不同有限长度的列表的“参差不齐”列表。相应地,在JFP文章中,我们得到了纠正。 (我们对它感到非常高兴,因为我们喜欢找到那些(&lt; *&gt;)不是Monad的ap的应用函子。)
必然无限的列表(即 streams ),通过排除粗糙的案例,确实形成了一个其行为像zapp的monad。有关线索,请注意Stream x与Nat同构 - > X
我为这种困惑道歉。在网络上留下旧的,未完成的草稿(充满错误)有时很危险。
答案 2 :(得分:3)
Monad的最小完整定义是fmap
+ return
+ join
或return
+ (>>=)
。你可以用另一个来实现:
(>>=) :: Monad m => m a -> (a->m b) -> m b
(>>=) ma amb = join $ fmap amb ma
fmap :: Monad m => (a->b) -> m a -> m b
fmap f ma = ma >>= (return . f)
join :: Monad m => m (m a) -> m a
join mma = mma >>= id
现在,ap
的实施可以用join
和fmap
重写:
ap :: Monad m => m (a->b) -> m a -> m b
ap mf ma = do
f <- mf
a <- ma
return (f a)
ap mf ma = do
f <- mf
fmap f ma
ap mf ma = join $ fmap (flip fmap ma) mf
在练习中,给出了fmap
和return
以及ap
的语义。
一旦你看了一个例子,剩下的就很明显了:
ap [f1,f2,f3...] [1,2,3...] = join $ fmap (flip fmap [1,2,3...]) [f1,f2,f3...]
= join $ [ [(f1 1), f1 2 , f1 3 ...]
, [ f2 1 ,(f2 2), f2 3 ...]
, [ f3 1 , f3 2 ,(f3 3)...]
...
]
= [(f1 1)
, (f2 2)
, (f3 3)
...
]