Haskell中isNothing和(== Nothing)之间的区别?

时间:2018-04-22 06:50:37

标签: haskell maybe

我对以下涉及Nothing的两个函数不同的原因感到困惑:

coalesce  m1 m2 = if  isNothing m1 then m2 else m1

coalesce' m1 m2 = if  (m1 == Nothing) then m2 else m1

第一个有类型:

λ> :t coalesce
coalesce :: Maybe a -> Maybe a -> Maybe a

正如所料。但第二个有:

λ> :t coalesce'
coalesce' :: Eq a => Maybe a -> Maybe a -> Maybe a

为什么使用(==Nothing)引入Eq a约束?

(GHC 8.2.2)

3 个答案:

答案 0 :(得分:14)

==是一个函数Eq a => a -> a -> Bool。您正在制作其中一个操作数Nothing,因此某些类型a Maybe bb,但Eq a限制仍然适用 - {{ 1}}必须有Maybe b个实例。 Eq包含此类实例的定义 - Maybe b - 适用于所有Eq (Maybe b)

换句话说,Eq b只是一个函数,它不会提前知道您提供==作为参数。它只知道它是某些 Nothing,如果碰巧是Maybe a,它需要能够比较相等。

换句话说,您可以在此处定义Just …已存在的==

Maybe

注意equals a b = case a of Nothing -> isNothing b Just x -> case b of Nothing -> False Just y -> x == y 的显示方式,这意味着x == yEq的类型必须有x个实例。

答案 1 :(得分:6)

因为==的类型是

(==) :: (Eq a) => a -> a -> Bool

您的第二个定义(coalesce')使用==,因此它会从Eq继承对其参数的==约束。

严格来说,coalesce'==类型的值使用Maybe a,但是有一个实例

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

因此Eq (Maybe a)约束变为Eq a,因为==上支持Maybe a需要什么。

答案 2 :(得分:4)

让我们首先设计(==)函数而不是Maybe值。如果它们具有相同的数据构造函数,并且参数都相等,通常我们会认为两件事情是相同的。因此,如果F x1 x2 x3G y1 y2 y3是相同的数据构造函数,FG和{{{{1} 1}}。

因此,如果我们为x1 == y1实现此功能,则有两种情况相同:两个x2 == y2 s和两个x3 == y3 s,其中值为Maybe s封装是相同的,所以:

Nothing

是为Just实施Just实例的最合理方式。在实现中,我们使用instance Eq a => Eq (Maybe a) where (==) Nothing Nothing = True (==) (Just x) (Just y) = x == y (==) _ _ = False ,因此我们添加了Eq类型约束。

现在Haskell在概念上将功能视为黑盒子。对于Maybe a,它会将x == y视为Eq a。如果您因此使用此Maybe函数,则始终需要类型约束(==),无论特定用法是否需要此类型约束来执行(==) :: Eq a => Maybe a -> Maybe a -> Bool检查。如果您编写(==),那么我们会看到,第二个子句(Eq a)将永远不会被使用,但由于Haskell将函数视为黑盒,因此不知道类型约束在何种情况下是相关的。

isNothing :: Maybe a -> Bool仅检查值是x == y,如果是(== Nothing),则它始终为(==) (Just x) (Just y),无论值是{{1}构造函数换行,它实现如下:

Nothing

所以我们这里不需要Just类型约束:我们不检查元素False构造函数换行的相等性。因此,如果我们使用它,Haskell只会检查类型签名,注意到没有涉及Just类型约束,因此不会将它添加到使用此函数的函数中。

请注意,您在此实施的内容实际上已在isNothing :: Maybe a -> Bool isNothing Nothing = True isNothing _ = False 模块中实现:(<|>) :: Alternative f => f a -> f a -> f a,例如:

Eq a