在source code of GHC.Base中,Applicative Maybe
定义为:
instance Applicative Maybe where
pure = Just
...
我想知道为什么纯正的定义忽略了Nothing
?
根据这个定义,我希望
pure Nothing
应该减少到Just Nothing
,因为pure = Just
和
Prelude> Just Nothing
Just Nothing
而不是实际上:
Prelude> pure Nothing
Nothing
为什么这是魔术?我怎么了谢谢!
答案 0 :(得分:5)
它不会不忽略Nothing
,但是如果运行<Applicative
函数,则需要为指定哪个 pure
我们使用-XTypeApplications
运行它,我们可以指定Applicative
的类型,然后获得:
$ ghci -XTypeApplications
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> pure @Maybe Nothing
Just Nothing
如果未指定类型,则解释器将“默认”为某个Applicative
(在这种情况下为IO
)变体,因此这意味着它将返回该值,并且解释器的标准行为是在IO
shell中打印值“ wrapped”。
Applicative
占用pure = Just
的原因是,它必须与Functor
实例一致。此仿函数实例定义为:
instance Functor Maybe where fmap f (Just x) = Just (f x) fmap _ Nothing = Nothing
现在需要满足的法律之一是:
fmap f x = pure f <*> x
因此,如果我们定义pure _ = Nothing
,则意味着fmap f x = Nothing <*> x
,这意味着我们“丢失了有关f
的信息”。结果,唯一合理的解决方案可能是fmap
总是返回Nothing
,但这作为函子没有多大意义。此外,它还会违反函子级的另一个约束,即fmap id x
应该始终返回x
。
答案 1 :(得分:4)
pure
已超载。单独输入pure Nothing
时,您无需指定要调用的pure
版本。它本身具有类型
pure Nothing :: Applicative f => f (Maybe a)
如果您明确地说想要Maybe (Maybe a)
,您将得到期望的结果:
ghci> pure Nothing :: Maybe (Maybe a)
Just Nothing
但是,当您在GHCi中键入pure Nothing
时,它实际上选择制作一个IO (Maybe a)
。这是因为GHCi尝试运行它可以执行的任何IO
操作。当它执行动作pure Nothing :: IO (Maybe a)
时,您将返回Nothing
。您还可以提供类型签名:
ghci> pure Nothing :: IO (Maybe a)
Nothing
也就是说,您从未调用过pure = Just
的{{1}}版本。您调用了另一个函数,也称为pure
。这就是为什么您会有一些有趣的行为的原因。