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

标签 haskell

我正在解决 Haskell Book 中的以下练习:

-- >>> 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

首先我尝试使用 elem ,
flipMaybeWithElem :: [Maybe a] -> Maybe [a]
flipMaybeWithElem ms
  | Nothing `elem` ms = Nothing
  | otherwise         = Just (catMaybes ms)

但我收到错误消息:
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
   |     ^^^^^^^^^^^^^^^^^

我知道我应该只添加 Eq a =>对函数签名的约束,但我试图忠实于提供的函数 stub 。所以我重用了以前的功能,它确实有效:
flipMaybe :: [Maybe a] -> Maybe [a]
flipMaybe ms =
  case (filter isNothing ms) of
    [] -> Just (catMaybes ms)
    _  -> Nothing

使用的辅助函数:
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)

所以为什么第一个解决方案没有 elem在没有类型约束的情况下工作?

难道仅仅是因为filterisNothing对类型变量和 elem 没有限制有? (同样对于 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有一个 Eq例如,但我猜编译器对 a 一无所知, 正确的?

最佳答案

Is it simply because filter and isNothing have no constraints on the type variables and elem has? (Also with isNothing the type variable never even comes into play because it is ignored.)



你在这里一针见血。 elem ,一般来说,只有在 Eq a 时才有效很满意。您正在尝试在 [Maybe a] 上使用它, 和 Maybe a有以下 Eq实例。
instance Eq a => Eq (Maybe a) where
    ...

所以elem看着你的Maybe a并说“我需要这个是Eq”。它看到上面的实例并说“对于 Maybe a 要满足 Eqa 必须满足 Eq ,我不知道 Eq a ”。现在,在您的特定情况下,您只比较 Nothing ,所以 Eq a instance 从未实际使用过。但是编译器没有足够的信息来知道这一点;它只知道elem需要Eq a ,并且您没有为它提供该约束。

为了让这个功能在没有 Eq 的情况下工作,你需要按照你已经做过的方式来做,要么使用显式递归,要么使用filterisNothing .总之,我想你已经找到答案了,我只是重申一下你已经说过的话。

关于haskell - 为什么使用 `Eq a` 的解决方案需要 `elem` 约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49519683/

相关文章:

haskell - 我需要一个对子节点进行操作的函数

haskell - 是否有用于编译时检查的示例值以及它们应该在代码中的什么位置?

scala - 值、类型、种类……作为无限序列?

haskell - 为n个不同版本构建haskell包

haskell - 使用堆栈实现撤消和重做功能。如何编辑堆栈而无需在 Haskell 中重新创建它

haskell - 在 Haskell 中,为什么在如下函数之前使用 Eq a => [a] 很重要?

Haskell 推断/显式的 Where 绑定(bind)类型

haskell - 使用 `a0' 引起的模糊类型变量 `it'

Haskell 在基本包中缺少文件

haskell - Haskell 特里树中的太空泄漏