Haskell - 提取可能在Monad

Jon*_*len 2 monads haskell

我正在研究Project Euler的第9个问题,我对在另一个monad中提取一个可能值的最佳方法有疑问.问题要求找到满足的'a','b','c':

  • a ^ 2 + b ^ 2 = c ^ 2
  • a + b + c = 1000

我编写了以下代码来解决问题:

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)
Run Code Online (Sandbox Code Playgroud)

'c'可以通过分析计算,但是,由于它可能不存在,我返回一个可能的值.

findC :: (Integral a) => a -> a -> Maybe a
findC a b = ... (implementation) ...
Run Code Online (Sandbox Code Playgroud)

要提取列表monad中的可能值,我创建了以下函数:

fromJustM :: (Monad m) => Maybe a -> m a
fromJustM (Just a) = return a
fromJustM Nothing = fail ""
Run Code Online (Sandbox Code Playgroud)

看起来这应该是一个常见的操作,所以有没有一个标准的库函数可以做到这一点,还是有更惯用的方法呢?

lef*_*out 6

fail实际上并不是一个单一的操作; 它只是在Monad类型类中因为历史意外/隐藏一些脏的错误处理.

对此更合适的一类是MonadPlus,或者更确切地说是它的Applicative通讯员Alternative.fail翻译成empty.有了这个,你的签名实际上应该是

fromJustM' :: Alternative m => Maybe a -> m a
Run Code Online (Sandbox Code Playgroud)

Hoogle报价

asum :: (Foldable t, Alternative f) => t (f a) -> f a
Run Code Online (Sandbox Code Playgroud)

这符合法案:Maybe是一个Foldable.

        c <- asum $ pure <$> findC a b
Run Code Online (Sandbox Code Playgroud)

可以说,这实际上并不可读.


通过写作,您可以更轻松地实现目标

        Just c <- pure $ findC a b
Run Code Online (Sandbox Code Playgroud)

这会再次使用该fail方法:do块中的模式匹配失败会隐式调用它.