[英]Why is `Eq a` constraint required for the solution using `elem`?
I was solving the following exercise from the Haskell Book : 我正在从Haskell书中解决以下练习:
-- >>> flipMaybe [Just 1, Just 2, Just 3]
-- Just [1, 2, 3]
-- >>> flipMaybe [Just 1, Nothing, Just 3]
-- Nothing
flipMaybe :: [Maybe a] -> Maybe [a]
flipMaybe = undefined
First I tried using elem
, 首先我尝试使用elem
,
flipMaybeWithElem :: [Maybe a] -> Maybe [a]
flipMaybeWithElem ms
| Nothing `elem` ms = Nothing
| otherwise = Just (catMaybes ms)
but I got the error message: 但是我收到了错误消息:
misc.hs:86:5: error:
• No instance for (Eq a) arising from a use of ‘elem’
Possible fix:
add (Eq a) to the context of
the type signature for:
flipMaybe2 :: forall a. [Maybe a] -> Maybe [a]
• In the expression: Nothing `elem` ms
In a stmt of a pattern guard for
an equation for ‘flipMaybe2’:
Nothing `elem` ms
In an equation for ‘flipMaybe2’:
flipMaybe2 ms
| Nothing `elem` ms = Nothing
| otherwise = Just (catMaybes ms)
|
86 | | Nothing `elem` ms = Nothing
| ^^^^^^^^^^^^^^^^^
I understand that I should just add the Eq a =>
constraint to the function signature, but I was trying to stay true to the provided function stub. 我知道我应该只将Eq a =>
约束添加到函数签名中,但我试图保持对提供的函数存根的忠诚。 So I reused previous functions, and it did work: 所以我重用了以前的功能,它确实有效:
flipMaybe :: [Maybe a] -> Maybe [a]
flipMaybe ms =
case (filter isNothing ms) of
[] -> Just (catMaybes ms)
_ -> Nothing
The helper functions used: 使用的辅助函数:
isNothing :: Maybe a -> Bool
isNothing Nothing = True
isNothing _ = False
mayybee :: b -> (a -> b) -> Maybe a -> b
mayybee b _ Nothing = b
mayybee b f (Just a) = f a
fromMaybe :: a -> Maybe a -> a
fromMaybe a maybe = mayybee a id maybe
catMaybes :: [Maybe a] -> [a]
catMaybes xs = map (fromMaybe undefined) (filter isJust xs)
So why doesn't the first solution with elem
work without the type constraints? 那么为什么没有类型约束的elem
工作的第一个解决方案呢?
Is it simply because filter
and isNothing
have no constraints on the type variables and elem
has? 它只是因为filter
和isNothing
对类型变量没有约束而且elem
有吗? (Also with isNothing
the type variable never even comes into play because it is ignored.) (同样使用isNothing
类型变量甚至从未发挥作用,因为它被忽略。)
> :t filter
filter :: (a -> Bool) -> [a] -> [a]
> :t isNothing
isNothing :: Maybe a -> Bool
> :t elem
elem :: (Eq a, Foldable t) => a -> t a -> Bool
Maybe
has an Eq
instance, but I guess the compiler does not know anything about a
, right? Maybe
有一个Eq
实例,但我想编译器对a
一无所知,对吧?
Is it simply because
filter
andisNothing
have no constraints on the type variables andelem
has? 它只是因为filter
和isNothing
对类型变量没有约束而且elem
有吗? (Also withisNothing
the type variable never even comes into play because it is ignored.) (同样使用isNothing
类型变量甚至从未发挥作用,因为它被忽略。)
You've hit the nail on the head here. 你在这里击中了钉子。 elem
, in general , will only work if Eq a
is satisfied. 一般来说 , elem
只有在满足Eq a
时才有效。 You're trying to use it on [Maybe a]
, and Maybe a
has the following Eq
instance. 你试图在[Maybe a]
上使用它,而且Maybe a
有以下Eq
实例。
instance Eq a => Eq (Maybe a) where
...
So elem
looks at your Maybe a
and says "I need this to be Eq
". 所以elem
看着你的Maybe a
并说“我需要这个是Eq
”。 It sees the above instance and says "for Maybe a
to satisfy Eq
, a
must satisfy Eq
, and I don't know Eq a
". 它认为上述情况,并表示“为Maybe a
满足Eq
, a
必须满足的Eq
,我不知道Eq a
”。 Now, in your particular case, you only compare against Nothing
, so the Eq a
instance is never actually used. 现在,在您的特定情况下,您只与Nothing
进行比较,因此Eq a
实例永远不会被实际使用。 But the compiler doesn't have enough information to know this; 但编译器没有足够的信息来了解这一点; it just knows that elem
needs Eq a
, and you don't provide it with that constraint. 它只知道elem
需要Eq a
,并且你没有为它提供该约束。
In order to get this function to work without Eq
, you need to do it the way you already did it, either with explicit recursion or with filter
and isNothing
. 为了让这个函数在没有Eq
情况下工作,你需要按照你已经做过的方式去做,要么使用显式递归,要么使用filter
和isNothing
。 In short, I think you've already figured out the answer, and I'm just reiterating the things you've already said. 简而言之,我认为你已经找到了答案,我只是重申你已经说过的话。
Is it simply because
filter
andisNothing
have no constraints on the type variables andelem
has? 它只是因为filter
和isNothing
对类型变量没有约束而且elem
有吗? (Also withisNothing
the type variable never even comes into play because it is ignored.) (同样使用isNothing
类型变量甚至从未发挥作用,因为它被忽略。)
Correct, you nailed it here. 正确,你在这里钉了它。
Maybe
has anEq
instance, but I guess the compiler does not know anything abouta
, right?Maybe
有一个Eq
实例,但我想编译器对a
一无所知,对吧?
Nailed it again. 又把它钉了起来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.