我正在从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
Run Code Online (Sandbox Code Playgroud)
首先我尝试使用elem,
flipMaybeWithElem :: [Maybe a] -> Maybe [a]
flipMaybeWithElem ms
| Nothing `elem` ms = Nothing
| otherwise = Just (catMaybes ms)
Run Code Online (Sandbox Code Playgroud)
但是我收到了错误消息:
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
| ^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
我知道我应该只将Eq a =>约束添加到函数签名中,但我试图保持对提供的函数存根的忠诚.所以我重用了以前的功能,它确实有效:
flipMaybe :: [Maybe a] -> Maybe [a]
flipMaybe ms =
case (filter isNothing ms) of
[] -> Just (catMaybes ms)
_ -> Nothing
Run Code Online (Sandbox Code Playgroud)
使用的辅助函数:
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)
Run Code Online (Sandbox Code Playgroud)
那么为什么没有elem类型约束的第一个解决方案没有工作呢?
它只是因为filter并且isNothing对类型变量没有约束而且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
Run Code Online (Sandbox Code Playgroud)
Maybe有一个Eq实例,但我想编译器对此一无所知a,对吧?
它只是因为
filter并且isNothing对类型变量没有约束而且elem有吗?(同样,isNothing类型变量甚至从未发挥作用,因为它被忽略了.)
你在这里击中了钉子.elem,一般来说,只会工作,如果Eq a是满意的.您正尝试使用它[Maybe a],并Maybe a具有以下Eq实例.
instance Eq a => Eq (Maybe a) where
...
Run Code Online (Sandbox Code Playgroud)
所以elem看着你Maybe a说"我需要这个Eq".它看到上面的例子并说"为了Maybe a满足Eq,a必须满足Eq,我不知道Eq a".现在,在您的特定情况下,您只需进行比较Nothing,因此Eq a实例永远不会被实际使用.但编译器没有足够的信息来了解这一点; 它只知道elem需求Eq a,而你没有提供这种约束.
为了让这个函数无需工作Eq,你需要按照你已经做过的方式去做,无论是使用显式递归还是使用filter和isNothing.简而言之,我认为你已经找到了答案,我只是重申你已经说过的话.
它只是因为
filter并且isNothing对类型变量没有约束而且elem有吗?(同样,isNothing类型变量甚至从未发挥作用,因为它被忽略了.)
正确,你在这里钉了它.
Maybe有一个Eq实例,但我想编译器对此一无所知a,对吧?
又把它钉了起来.