无法理解monad的错误处理

时间:2015-01-12 19:32:46

标签: haskell monads

我正在尝试构建一个函数,该函数从列表中返回单个元素。该列表是Maybe (Int,[Int]) tupel的一部分。

如果列表中没有元素,我想返回错误。 如果列表中只包含1个元素,我想将该元素作为Monad返回。 如果列表包含多个元素,我想返回错误。

我有点迷失,看不出如何让这个相当简单的事情发挥作用。 以下是我到目前为止的情况:

import Control.Monad

test1 = Just (1,[2,3]) :: Maybe (Int,[Int])
test2 = Just (2,[1]) :: Maybe (Int,[Int])
test3 = Just (3,[]) :: Maybe (Int,[Int])

getValue :: Maybe Bool -> Bool
getValue (Just x) = x
getValue Nothing = False

singleElemOnly :: (MonadPlus m) => [a] -> m a
singleElemOnly x = let result = test2
                       value = fmap fst result
                       isEmpty = fmap null (fmap snd result)
                   in if (getValue isEmpty) then value else mzero

不幸的是,我在尝试编译时遇到的错误信息对初学者来说绝对没用..

Playground.hs:15:50:
    Could not deduce (a ~ Int)
    from the context (MonadPlus m)
      bound by the type signature for
                 singleElemOnly :: MonadPlus m => [a] -> m a
      at Playground.hs:11:19-45
      `a' is a rigid type variable bound by
          the type signature for singleElemOnly :: MonadPlus m => [a] -> m a
          at Playground.hs:11:19
    Expected type: m a
      Actual type: Maybe Int
    Relevant bindings include
      x :: [a]
        (bound at Playground.hs:12:16)
      singleElemOnly :: [a] -> m a
        (bound at Playground.hs:12:1)
    In the expression: value
    In the expression: if (getValue isEmpty) then value else mzero

Playground.hs:15:50:
    Could not deduce (m ~ Maybe)
    from the context (MonadPlus m)
      bound by the type signature for
                 singleElemOnly :: MonadPlus m => [a] -> m a
      at Playground.hs:11:19-45
      `m' is a rigid type variable bound by
          the type signature for singleElemOnly :: MonadPlus m => [a] -> m a
          at Playground.hs:11:19
    Expected type: m a
      Actual type: Maybe Int
    Relevant bindings include
      singleElemOnly :: [a] -> m a
        (bound at Playground.hs:12:1)
    In the expression: value
    In the expression: if (getValue isEmpty) then value else mzero

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

我将从您的规范中翻译出来:

  

如果列表中没有元素,我想返回错误。

f [] = mzero
  

如果   list只包含1个元素,我想将该元素作为一个返回   单子。

f [x] = return x
  

如果列表包含多个元素,我想返回一个   错误。

f (_:_:_) = mzero

所以,把所有东西放在一起:

singleElemOnly :: (MonadPlus m) => [a] -> m a
singleElemOnly []  = mzero
singleElemOnly [x] = return x
singleElemOnly _   = mzero
       -- a _ catches everything else, no need to write the exact pattern

或者甚至更简单,因为第三种情况包括第一种情况:

singleElemOnly :: (MonadPlus m) => [a] -> m a
singleElemOnly [x] = return x
singleElemOnly _   = mzero

答案 1 :(得分:1)

首先,hoogle是你的朋友。您可以查找签名,发现getFirst只是fstgetSecondsnd,您getValue的实现可以写为fromMaybe false }。

就错误消息而言,value的类型为(Integral i) => Maybe i(或接近,我现在没有编译器),这是{{1}的一个可能值返回。但签名singleElemOnly表示必须返回调用者想要的任何 (MonadPlus m) => [a] -> m a

同样,如果您在GHCi中运行此功能,则MonadPlus的类型默认为test2,但Maybe (Integer, [Integer])必须能够返回任何 { {1}}输入。