任务是翻译这个
f = do
c <- [1 .. 200]
b <- [1 .. 200]
guard (c >= b)
a <- [1 .. 200]
guard (a >= b && (c^2 - a^2 == b^2))
return (a,b, c)
进入非糖的角落。
我认为我已经弄清楚了大部分内容,但是在我可以继续之前,我需要解决一个问题。到目前为止,我有:
f = [1 .. 200] >>= \c ->
[1 .. 200] >>= \b ->
if (c >= b)
then [1 .. 200] >>= \a -> if (a >= b && (c^2 - a^2 == b^2))
then return(a,b,c)
else return ()
else return ()
不编译。当我输入(a,b,c)返回时,它会编译,但显然它不再给出预期的结果。如何在else分支中返回“nothing”?
如果我输入((),(),())作为返回值,编译器会得到一个“没有实例(Num [a])来自文字'1'”
答案 0 :(得分:8)
而不是return ()
,而[()]
,您必须生成一个空列表,因此else []
或通用guard
实现else mzero
。< / p>
成功分支生成三元组列表[(Int,Int,Int)]
(或Integer
或其他Num
类型),因此失败分支必须生成相同的内容。由于失败意味着没有找到三元组,它们将产生一个空列表。
请注意,在[]
monad中,return x
只是[x]
而mzero
(来自MonadPlus
)与fail whatever
相同,即[]
。
答案 1 :(得分:5)
guard
实际上并不是语法糖。它是Control.Monad
的函数。
guard :: MonadPlus m => Bool -> m ()
guard True = return ()
guard False = mzero
如果列表mzero
为[]
。在此处阅读更多内容:http://en.wikibooks.org/wiki/Haskell/MonadPlus