Haskell 中 isNothing 和 (== Nothing) 的区别?
difference between isNothing and (== Nothing) in Haskell?
我很困惑为什么下面涉及 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)
因为==
的类型是
(==) :: (Eq a) => a -> a -> Bool
您的第二个定义 (coalesce'
) 使用 ==
,因此它从 ==
.
继承了对其参数的 Eq
约束
严格来说 coalesce'
对类型 Maybe a
的值使用 ==
,但有一个实例
instance (Eq a) => Eq (Maybe a) where ...
所以 Eq (Maybe a)
约束变为 Eq a
,因为这是在 Maybe a
上支持 ==
所需要的。
==
是函数 Eq a => a -> a -> Bool
。您正在创建其操作数之一 Nothing
,因此 a
是某种类型 b
的 Maybe b
,但 Eq a
限制仍然适用 – Maybe b
必须有一个 Eq
实例。 Maybe b
包括对此类实例的定义 – Eq (Maybe b)
– 对于所有 Eq b
.
换句话说,==
只是一个函数,它不会提前知道您提供 Nothing
作为参数。它只知道是someMaybe a
,如果碰巧是Just …
.
就需要能够比较相等
换句话说,您可以通过以下方式定义 Maybe
已经存在的 ==
:
equals a b = case a of
Nothing -> isNothing b
Just x -> case b of
Nothing -> False
Just y -> x == y
注意 x == y
的出现方式,这意味着 x
和 y
.
类型必须有一个 Eq
实例
让我们首先针对 Maybe
值设计一个 (==)
函数。通常我们认为两个事物相同,如果它们具有相同数据构造函数,并且参数都相等。所以我们认为 F x1 x2 x3
和 G y1 y2 y3
相同,如果 F
和 G
是相同的数据构造函数,并且 x1 == y1
、x2 == y2
和 x3 == y3
.
所以如果我们为 Maybe
实现这个,有两种情况是相等的:两个 Nothing
和两个 Just
,其中值 Just
s封装相同,所以:
instance Eq a => Eq (Maybe a) where
(==) Nothing Nothing = True
(==) (Just x) (Just y) = x == y
(==) _ _ = False
是为 Maybe a
实现 Eq
实例的最合乎逻辑的方式。在实现中,我们使用 x == y
,因此我们添加了 Eq a
类型约束。
现在 Haskell 在概念上将函数视为黑盒。对于 Maybe
,它因此将 (==)
视为 (==) :: Eq a => Maybe a -> Maybe a -> Bool
。如果您因此使用此 (==)
函数,它将始终需要类型约束 Eq a
,无论特定用法是否需要此类型约束来执行 x == y
检查。如果你写 (== Nothing)
,那么我们会看到,第二个子句 ((==) (Just x) (Just y)
) 将永远不会被使用,但是由于 Haskell 将函数视为黑盒,它不知道在什么情况下类型约束是相关的。
isNothing :: Maybe a -> Bool
只检查值是否为 Nothing
,如果是 Just
,则始终为 False
,无论值是什么 Just
构造函数包装,因此实现如下:
isNothing :: Maybe a -> Bool
isNothing Nothing = True
isNothing _ = False
所以我们在这里不需要 Eq a
类型约束:我们不检查元素 Just
构造函数换行的相等性。因此,如果我们再次使用它,Haskell 只会检查类型签名,注意到没有涉及 Eq a
类型约束,因此不会将其添加到使用此函数的函数中。
请注意,您在这里实现的实际上已经在 Control.Applicative
模块中实现:(<|>) :: Alternative f => f a -> f a -> f a
,例如:
Prelude> import Control.Applicative
Prelude Control.Applicative> (<|>) Nothing Nothing
Nothing
Prelude Control.Applicative> (<|>) Nothing (Just 3)
Just 3
Prelude Control.Applicative> (<|>) (Just 3) Nothing
Just 3
Prelude Control.Applicative> (<|>) (Just 3) (Just 2)
Just 3
我很困惑为什么下面涉及 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)
因为==
的类型是
(==) :: (Eq a) => a -> a -> Bool
您的第二个定义 (coalesce'
) 使用 ==
,因此它从 ==
.
Eq
约束
严格来说 coalesce'
对类型 Maybe a
的值使用 ==
,但有一个实例
instance (Eq a) => Eq (Maybe a) where ...
所以 Eq (Maybe a)
约束变为 Eq a
,因为这是在 Maybe a
上支持 ==
所需要的。
==
是函数 Eq a => a -> a -> Bool
。您正在创建其操作数之一 Nothing
,因此 a
是某种类型 b
的 Maybe b
,但 Eq a
限制仍然适用 – Maybe b
必须有一个 Eq
实例。 Maybe b
包括对此类实例的定义 – Eq (Maybe b)
– 对于所有 Eq b
.
换句话说,==
只是一个函数,它不会提前知道您提供 Nothing
作为参数。它只知道是someMaybe a
,如果碰巧是Just …
.
换句话说,您可以通过以下方式定义 Maybe
已经存在的 ==
:
equals a b = case a of
Nothing -> isNothing b
Just x -> case b of
Nothing -> False
Just y -> x == y
注意 x == y
的出现方式,这意味着 x
和 y
.
Eq
实例
让我们首先针对 Maybe
值设计一个 (==)
函数。通常我们认为两个事物相同,如果它们具有相同数据构造函数,并且参数都相等。所以我们认为 F x1 x2 x3
和 G y1 y2 y3
相同,如果 F
和 G
是相同的数据构造函数,并且 x1 == y1
、x2 == y2
和 x3 == y3
.
所以如果我们为 Maybe
实现这个,有两种情况是相等的:两个 Nothing
和两个 Just
,其中值 Just
s封装相同,所以:
instance Eq a => Eq (Maybe a) where
(==) Nothing Nothing = True
(==) (Just x) (Just y) = x == y
(==) _ _ = False
是为 Maybe a
实现 Eq
实例的最合乎逻辑的方式。在实现中,我们使用 x == y
,因此我们添加了 Eq a
类型约束。
现在 Haskell 在概念上将函数视为黑盒。对于 Maybe
,它因此将 (==)
视为 (==) :: Eq a => Maybe a -> Maybe a -> Bool
。如果您因此使用此 (==)
函数,它将始终需要类型约束 Eq a
,无论特定用法是否需要此类型约束来执行 x == y
检查。如果你写 (== Nothing)
,那么我们会看到,第二个子句 ((==) (Just x) (Just y)
) 将永远不会被使用,但是由于 Haskell 将函数视为黑盒,它不知道在什么情况下类型约束是相关的。
isNothing :: Maybe a -> Bool
只检查值是否为 Nothing
,如果是 Just
,则始终为 False
,无论值是什么 Just
构造函数包装,因此实现如下:
isNothing :: Maybe a -> Bool
isNothing Nothing = True
isNothing _ = False
所以我们在这里不需要 Eq a
类型约束:我们不检查元素 Just
构造函数换行的相等性。因此,如果我们再次使用它,Haskell 只会检查类型签名,注意到没有涉及 Eq a
类型约束,因此不会将其添加到使用此函数的函数中。
请注意,您在这里实现的实际上已经在 Control.Applicative
模块中实现:(<|>) :: Alternative f => f a -> f a -> f a
,例如:
Prelude> import Control.Applicative
Prelude Control.Applicative> (<|>) Nothing Nothing
Nothing
Prelude Control.Applicative> (<|>) Nothing (Just 3)
Just 3
Prelude Control.Applicative> (<|>) (Just 3) Nothing
Just 3
Prelude Control.Applicative> (<|>) (Just 3) (Just 2)
Just 3