Haskell 无法理解monad的错误处理

Haskell 无法理解monad的错误处理,haskell,monads,monadplus,Haskell,Monads,Monadplus,我试图构建一个函数,从列表中返回单个元素。该列表是Maybe(Int,[Int])tupel的一部分 如果列表不包含任何元素,我想返回一个错误。 如果列表正好包含1个元素,我想将该元素作为Monad返回。 如果列表包含多个元素,我想返回一个错误 我有点迷路了,看不出如何让这件相当简单的事情起作用。 以下是我到目前为止的情况: import Control.Monad test1 = Just (1,[2,3]) :: Maybe (Int,[Int]) test2 = Just (2,[1])

我试图构建一个函数,从列表中返回单个元素。该列表是
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
非常感谢任何帮助

首先,是你的朋友。您可以查找签名,发现
getFirst
只是
fst
getSecond
snd
,并且
getValue
的实现可以写成
fromFalse

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


类似地,如果您在GHCi中运行此操作,则
test2
的类型默认为
Maybe(Integer,[Integer])
,但是
singleElemOnly
必须能够返回任何
积分
类型。

我将从您的规范转换为:

如果列表不包含任何元素,我想返回一个错误

如果 列表正好包含1个元素,我想将该元素作为 蒙纳德

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

所以,把一切放在一起:

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

错误消息是什么?总是发布你看到的编译器错误。抱歉,错误太长了。我添加了它们并修复了这个示例。将类型签名添加到
test1,
:您可能希望它们的类型为
Maybe(Int,[Int])
或类似的类型。GHC为您选择了
Integer
而不是
Int
。一旦该类型被修复,您现在可以看到您的函数
singleelemony
只返回
Int/Integer
类型,而它的签名保证它可以在任何类型
a
下工作(而不仅仅是
Int
)。这是GHC报告的类型错误。此外,我不清楚上一个函数应该做什么。你能编辑你的问题来解释你想要达到的目标吗?我现在的猜测是
f[]=mzero;f(x:uz)=返回x
但很难说。@chi抱歉,我用最新的代码和错误更新了问题,并对我想要实现的目标进行了更好的解释。这几乎是完美的!但现在我需要以某种方式将
test1
作为一个参数引入其中,而这一部分我仍然无法理解
singleElemOnly(fmap snd test2)
不起作用,它抱怨它“无法将类型
可能
[]
匹配”?
singleElemOnly
获取一个列表<代码>fmap snd测试
具有类型
可能[Int]
。您可以执行
fmap(singleElement.snd)测试
,但这会得到
可能(可能[Int])
。您可能希望
fmap snd test>=singleElement
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