Haskell “写作帮助”;“共线主义者莫纳德”;(习语介绍论文中的练习)
我正在阅读Conor McBride和Ross Paterson的《功能性珍珠/习语:带效果的应用程序编程》(新版本,标题中有“习语”)。我在练习4中遇到了一点困难,如下所述。任何提示都将不胜感激(特别是:我是否应该开始编写Haskell “写作帮助”;“共线主义者莫纳德”;(习语介绍论文中的练习),haskell,monads,idioms,Haskell,Monads,Idioms,我正在阅读Conor McBride和Ross Paterson的《功能性珍珠/习语:带效果的应用程序编程》(新版本,标题中有“习语”)。我在练习4中遇到了一点困难,如下所述。任何提示都将不胜感激(特别是:我是否应该开始编写fmap和join或return和>=?) 问题陈述 您想创建一个实例Monad[]其中 return x = repeat x 和ap=zapp 标准库函数 如第页所示。在本文的第2部分,ap将一元函数值应用于一元值 ap :: Monad m => m (s -&
fmap
和join
或return
和>=
?)
问题陈述
您想创建一个实例Monad[]
其中
return x = repeat x
和ap=zapp
标准库函数
如第页所示。在本文的第2部分,ap
将一元函数值应用于一元值
ap :: Monad m => m (s -> t) -> m s -> m t
ap mf ms = do
f <- mf
s <- ms
return (f s)
列表特定函数zapp
(“zippy应用程序”)将一个列表中的函数应用于另一个列表中的对应值,即
zapp (f:fs) (s:ss) = f s : zapp fs ss
我的困难
请注意,在扩展的形式中,mf::m(a->b)
是本例中的函数列表[(a->b)]
。因此,在>>=
的第一个应用程序中,我们有
(f:fs) >>= mu
其中mu=(\f->(ms>=\s->return(fs))
。现在,我们可以调用fs>=mu
作为子例程,但这不知道如何删除ms
的第一个元素。(回想一下,我们希望得到的列表是[f1 s1,f2 s2,…)。我试图破解一些东西,但……正如预测的那样,它不起作用……任何帮助都将不胜感激
提前谢谢
编辑1
我想我成功了;首先我用fmap
重写了ap
,并按照用户“comonad”的建议加入join
我的信念的飞跃是假设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页的“解决方案”)……谢谢大家的帮助!Hm。我忍不住觉得这个练习有点不公平 练习4(肠绞痛患者单子) 虽然
repeat
和zapp
不是通常的Monad[]
实例的返回
和ap
,
它们仍然是替代单子的return
和ap
,更适合于
[]
的共导解释。什么是连接:[[x]]→ [x]
这个单子的名字
评论一下这个单子的ap
和我们的zapp
的相对效率
首先,我相当肯定所讨论的monad实例对[]
一般来说是无效的。当他们说“共导解释”时,我怀疑这指的是无限列表。在某些情况下,该实例实际上对有限列表有效,但通常对任意列表无效
这是第一个非常一般的提示——为什么monad实例只对某些列表有效,特别是无限列表
这里是您的第二个提示:fmap
和return
在本文前面给出的其他定义中是微不足道的。您已经有了return
;fmap
只是稍微不那么明显
此外,(>>=)
与任何Monad
一样,在其他功能方面都有一个简单的实现,这使得join
成为问题的关键。在大多数情况下,(>=)
对于编程来说更为自然,但是join
在概念上更为基础,在这种情况下,我认为更易于分析。因此我建议现在就开始进行这项工作,忘记(>=)
。一旦有了实现,就可以返回并重新构建(>>=)
并检查monad法则,确保其正常工作
最后,假设您有可用的
fmap
,但没有其他内容。给定类型为[a->b]
和[a]
的值,您可以将它们组合在一起,得到类型为[[b]]
。这里的连接类型是[[a]->[a]
。您如何编写join
,从而在这里获得与在原始值上使用zapp
相同的结果?请注意,关于相对效率的问题以及一个问题是关于实现的线索。单子的最小完整定义是fmap
+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
现在,可以根据join
和fmap
重写ap
的实现:
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
我只是想我应该澄清一下,标题中有练习和“习语”的版本是一篇较早的论文草稿,最终出现在JFP上。当时,我错误地认为共线性(我指的可能是无限的,可能是有限的列表)在某种程度上,我们是一个单子,与扎普相对应:有一个看似合理的候选人加入(在其他答案中提到),但杰里米·吉本斯(Jeremy Gibbons)好心地向我们指出,它不符合单子定律。反例包括“参差不齐”具有不同有限长度的列表列表。相应地,在JFP文章中,我们得到了更正。(我们对此相当满意,因为我们喜欢找到()不是单子的ap的应用程序函子。)
必要的无限列表(即流),通过排除不规则的情况,确实形成了一个单子,其ap行为类似于zapp。请注意,流x与Nat->x同构
我为这一混乱表示歉意。有时把旧的、未完成的草稿(充满错误)放在网上(哈哈)是很危险的。@camccann:有一点我不清楚。如果
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
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)
...
]