PatternSynonyms
参考
パターンに対してsynonymを定義できる
code:定義.hs
pattern Nil = [] -- []というパターンに対して、Nilと命名
pattern Cons x xs = x:xs -- (x:xs)というパターンに対してConsと命名
code:使用.hs
len (Cons _ xs) = 1 + len xs -- len (x:xs) = ...と書いてるのと同じ
len Nil = 0 -- len [] = ...と書いてるのと同じ
関数を定義するのと同じノリで定義できる
書き方
code:hs
pattern pat_lhs = pat
双方向
code:hs
pattern pat_lhs <- pat
単方向
docsの序盤に書いている例
こんな型とコードを考える
code:hs
data Type = App String Type collectArgs :: Type -> Type collectArgs (App "->" t1, t2) = t1 : collectArgs t2 collectArgs _ = []
isInt (App "Int" []) = True
isInt _ = False
このTypeという型はStringを引数に取る
Stringというと、任意の文字列を取れるわけだが、ここで想定しているものはもっと少ない
"->"とか"Int"のような数個の文字列しか許容しない
そこで、App "->" [t1, t2]とか、App "Int" []のような値に名前を付けて持ち回せるようにしたい
そこでPatternSynonymsが使える
code:hs
{-# LANGUAGE PatternSynonyms #-} pattern Arrow t1 t2 = App "->" t1, t2 pattern Int = App "Int" []
patternという予約語を導入して、値の取りうるpatternに対して、synonymを作れる
元のコードはSynonymを使って、こう書き直せる
code:hs
collectArgs :: Type -> Type collectArgs (Arrow t1 t2) = t1 : collectArgs t2
collectArgs _ = []
isInt :: Type -> Bool
isInt Int = True
isInt _ = False
「値コンストラクタを使った値」のsynonymを作るのね
この例、ただの設計ミスな気がするから例としてよくなさそうmrsekut.icon
PatternSynonymsの説明としてはわかりやすいから良いかmrsekut.icon
code:hs
{-# LANGUAGE PatternSynonyms #-} module NonZero
( NonZero()
, pattern NonZero
, unNonZero
, nonZero
) where
newtype NonZero a = UnsafeNonZero a
pattern NonZero a <- UnsafeNonZero a -- 疑似値コンストラクタを作って、これを公開
unNonZero :: NonZero a -> a
unNonZero (UnsafeNonZero a) = a
nonZero :: (Num a, Eq a) => a -> Maybe (NonZero a)
nonZero 0 = Nothing
nonZero i = Just (UnsafeNonZero i)
-- patternを定義していないと、この↓定義がerrorになる(これは外部module)
safeDivide :: Int -> NonZero Int -> Int
safeDivide i (NonZero j) = i div j
pattern NonZero a <- UnsafeNonZero aを定義して、これを公開することで
safeDivide i (NonZero j) = ..みたいに、外部でもパターンマッチはできる
↑このNonZeroはpatternで生成したもの
が、外部ではNonZero型を作ることはできない
なぜなら、UnsafeNonZeroが公開されていないから
つまり、
外部でもパターンマッチできるが
外部で型を作ることはできない
の2点を満たすために使われている
何が嬉しい?
いつ使う?
patternという識別子が新たに導入される?
値コンストラクタを使った値に別名を付ける感じ?
ただの変数束縛とは違うの?
イメージとしては同じっぽい
構造上ただの変数束縛がそもそもできない
recordでもサポート
パターンの別名