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)
_==
_は関数_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 …
_である場合は、同等性を比較できる必要があります。
つまり、Maybe
sにすでに存在する_==
_を定義する方法は次のとおりです。
_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
インスタンスが必要です。
_==
_のタイプは
_(==) :: (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
_をサポートするために必要なものだからです。
まず、Maybe
値に対して(==)
関数を設計することを目指しましょう。通常、sameデータコンストラクターがあり、parametersがすべて等しい場合、2つのことは同じであると見なされます。したがって、F
とG
が同じデータコンストラクタであり、F x1 x2 x3
、G y1 y2 y3
、およびx1 == y1
である場合、x2 == y2
とx3 == y3
は同じであると見なします。
したがって、これをMaybe
に実装すると、等しい2つのケースがあります。2つのNothing
sと2つのJust
sで、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)
と書くと、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