简体   繁体   English

为什么使用`elem`解决方案需要`Eq a`约束?

[英]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? 它只是因为filterisNothing对类型变量没有约束而且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 and isNothing have no constraints on the type variables and elem has? 它只是因为filterisNothing对类型变量没有约束而且elem有吗? (Also with isNothing 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满足Eqa必须满足的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情况下工作,你需要按照你已经做过的方式去做,要么使用显式递归,要么使用filterisNothing 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 and isNothing have no constraints on the type variables and elem has? 它只是因为filterisNothing对类型变量没有约束而且elem有吗? (Also with isNothing the type variable never even comes into play because it is ignored.) (同样使用isNothing类型变量甚至从未发挥作用,因为它被忽略。)

Correct, you nailed it here. 正确,你在这里钉了它。

Maybe has an Eq instance, but I guess the compiler does not know anything about a , right? Maybe有一个Eq实例,但我想编译器对a一无所知,对吧?

Nailed it again. 又把它钉了起来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM