我正在研究Project Euler的问题9,我对在另一个monad中提取一个可能值的最佳方法有疑问。问题要求找到满足的“a”,“b”,“c”:
我编写了以下代码来解决问题:
problem9 :: (Integral a) => a -> [(a, a, a)]
problem9 n =
do
a <- [1..n]
b <- [1..a]
c <- fromJustM (findC a b)
guard (a + b + c == n)
return (a, b, c)
'c'可以通过分析计算,但由于它可能不存在,我会返回一个可能的值。
findC :: (Integral a) => a -> a -> Maybe a
findC a b = ... (implementation) ...
要提取列表monad中的可能值,我创建了以下函数:
fromJustM :: (Monad m) => Maybe a -> m a
fromJustM (Just a) = return a
fromJustM Nothing = fail ""
看起来这应该是一个常见的操作,所以有没有一个标准的库函数可以做到这一点,还是有更惯用的方法呢?
答案 0 :(得分:6)
fail
实际上不是一个monadic操作;它只是在Monad
类型类中,因为历史意外/隐藏了一些脏的错误处理。
更合适的类是MonadPlus
,或者更确切地说是Applicative
通讯员Alternative
。 fail
转换为empty
。有了这个,你的签名实际上应该是
fromJustM' :: Alternative m => Maybe a -> m a
asum :: (Foldable t, Alternative f) => t (f a) -> f a
符合条件的是:Maybe
是Foldable
。
c <- asum $ pure <$> findC a b
可以说,这实际上并不可读。
通过编写
,您可以更轻松地实现目标 Just c <- pure $ findC a b
这再次使用fail
方法:do
块中的模式匹配失败会隐式调用它。