web-dev-qa-db-ja.com

HaskellのisNothingと(== Nothing)の違いは?

Nothingを含む以下の2つの関数が異なる理由について私は混乱しています。

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

予想通り。しかし、2番目のものは:

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

(==Nothing)を使用するとEq a制約が導入されるのはなぜですか?

(GHC 8.2.2)

12
tinlyx

_==_は関数_Eq a => a -> a -> Bool_です。オペランドの1つをNothingにしているので、aはあるタイプのbの_Maybe b_ですが、その_Eq a_制限は引き続き適用されます– _Maybe b_にはEqインスタンスが必要です。 _Maybe b_には、そのようなインスタンスの定義が含まれています– Eq (Maybe b) –すべての_Eq b_。

つまり、_==_は単なる関数であり、引数としてNothingを指定していることを事前に認識していません。 some _Maybe a_であることがわかっているだけであり、それが_Just …_である場合は、同等性を比較できる必要があります。

つまり、Maybesにすでに存在する_==_を定義する方法は次のとおりです。

_equals a b = case a of
    Nothing -> isNothing b
    Just x -> case b of
        Nothing -> False
        Just y -> x == y
_

_x == y_がどのように表示されるかに注意してください。つまり、Eqおよびxのタイプにはyインスタンスが必要です。

14
Ry-

_==_のタイプは

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

2番目の定義(_coalesce'_)は_==_を使用するため、引数のEq制約を_==_から継承します。


厳密に言えば、_coalesce'_はタイプ_==_の値に_Maybe a_を使用しますが、インスタンスがあります

_instance (Eq a) => Eq (Maybe a) where ...
_

したがって、Eq (Maybe a)制約は_Eq a_になります。これは、_==_で_Maybe a_をサポートするために必要なものだからです。

6
melpomene

まず、Maybe値に対して(==)関数を設計することを目指しましょう。通常、sameデータコンストラクターがあり、parametersがすべて等しい場合、2つのことは同じであると見なされます。したがって、FGが同じデータコンストラクタであり、F x1 x2 x3G y1 y2 y3、およびx1 == y1である場合、x2 == y2x3 == y3は同じであると見なします。

したがって、これをMaybeに実装すると、等しい2つのケースがあります。2つのNothingsと2つのJustsで、Justsがカプセル化する値は同じです。

instance Eq a => Eq (Maybe a) where
    (==) Nothing Nothing = True
    (==) (Just x) (Just y) = x == y
    (==) _ _ = False

Maybe aEqインスタンスを実装する最も論理的な方法です。実装では、x == yを使用するため、Eq a型制約を追加しました。

現在、Haskellは関数を概念的にブラックボックスと見なしています。したがって、Maybeの場合、(==)(==) :: Eq a => Maybe a -> Maybe a -> Boolと見なされます。したがって、この(==)関数を使用する場合、特定の使用法でEq aチェックを実行するためにこの型制約が必要かどうかに関係なく、常に型制約x == yが必要になります。 (== Nothing)と書くと、2番目の句((==) (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
4