Boolの代わりにEither () ()を使って,論理演算をポイントフリースタイルで定義
Bool | Either () () |
---|---|
true | Left |
false | Right |
この記事では,上記の対応付けを使って,ポイントフリースタイルで論理演算を定義します。
否定 not の定義
a | not a |
---|---|
true | false |
false | true |
notを定義するには,ArrowChoiceの(|||)を使います。
not :: Either () () -> Either () () not = false ||| true
true = Left, false = Rightであることに注意してください。
論理和 or を定義する準備
a | b | or a b |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
orの型は,以下のようになります。
or :: (Either () (), Either () ()) -> Either () ()
この記事では,複数個の引数は,タプルの形で与えます。カリー化はしません。
orを定義するために,補助関数distrを定義しておきます。distrは,orの第1引数を場合分けするために使います。
distr :: (Either a b, c) -> Either (a, c) (b, c) distr = uncurry (curry Left ||| curry Right)
型の表記を変更する
型を読みやすくするために,型の表記を変更します。
distr :: (Either a b, c) -> Either (a, c) (b, c)
↓
distr :: (a + b) * c -> a * c + b * c
or :: (Either () (), Either () ()) -> Either () ()
↓
or :: )(() + ())( * )(() + ())( -> () + ()
orの型が「()」だらけで,まだ読みにくいので,さらに表記を変更します。
Tはtrueに対応する型です。true = Leftなので,左側がTとなります。or :: )(() + ())( * )(() + ())( -> () + ()
↓
or :: (T + F) * (T + F) -> T + F
orの定義
distrを使えば,orは以下のように定義できます。*1
or :: (T + F) * (T + F) -> T + F or = distr >>> ((fst >>> true) ||| snd)
このときのdistrの役割は,こんな感じです。
おまけ:直積と直和の分配法則
distrには逆関数が存在します。
undistr :: a * c + b * c -> (a + b) * c undistr = ((fst >>> Left) ||| (fst >>> Right)) &&& (snd ||| snd)
distrとundistrによって,直積と直和には分配法則が成り立つことがわかります。
(a + b) * c = a * c + b * c
*1:このorは短絡評価できます