fmap 一个 2-arity 函数 Nothing should return Nothing?

fmap a 2-arity function on Nothing should return Nothing?

来自 ghcMaybe 的来源:

instance Functor Maybe where
    fmap _ Nothing  = Nothing
    fmap f (Just a) = Just (f a)

fmap应用于Nothing时,它应该return Nothing.

例如,运行 ghci (v8.2.2) 中的这个:

Prelude> fmap (+1) Nothing
Nothing

但是,当我应用元数为 2 的函数时:

Prelude> fmap (++) Nothing
<interactive>:11:1: error:
    • No instance for (Show ([a0] -> [a0]))
        arising from a use of ‘print’
        (maybe you haven't applied a function to enough arguments?)
    • In a stmt of an interactive GHCi command: print it

其实结果好像是Nothing:

Prelude> import Data.Maybe
Prelude Data.Maybe> isNothing $ fmap (++) Nothing
True

我的问题是,fmap (++) Nothing 真的 return Nothing 吗?

是的,fmap f Nothing = Nothing 不管 f 是什么或它有什么类型。 MaybeShow 实例看起来像

instance Show a => Show (Maybe a) where
  ...

因此您不能 showprint 类型 Maybe (A -> B) 的值,因为函数没有 Show 实例。

是的。让我们看看类型:

fmap :: Functor f => (a -> b) -> f a -> f b
(++) :: [a] -> [a] -> [a]

所以,

fmap (++) :: Functor f => f [a] -> f ([a] -> [a])

fmap 采用 1 元函数。但是,在 Haskell 中,2 元函数只是一个 1 元函数,returns 另一个 1 元函数:

([a] -> [a] -> [a]) ~ ([a] -> ([a] -> [a]))

所以你的fmap (++) :: Maybe [a] -> Maybe ([a] -> [a])

如果您将 Nothing 传递给它,它会 returns Nothing。如果您传递 Just "foo"(例如),它 returns Just 一个接受字符串并在其前面添加 "foo" 的函数:

Prelude> Just f = fmap (++) $ Just "foo"
Prelude> f "bar"
"foobar"

你得到错误的原因是因为 GHCi 试图打印输出,这意味着输出必须实现 Show 类型类。它试图 show 的是 Nothing :: Maybe ([a] -> [a])。类型系统不知道它只需要打印 Nothing,它只知道它不能 show[a] -> [a]。所以它打印错误。