generated at
PatternSynonyms





参考





パターンに対してsynonymを定義できる
定義.hs
pattern Nil = [] -- []というパターンに対して、Nilと命名 pattern Cons x xs = x:xs -- (x:xs)というパターンに対してConsと命名
使用.hs
len :: [a] -> Int len (Cons _ xs) = 1 + len xs -- len (x:xs) = ...と書いてるのと同じ len Nil = 0 -- len [] = ...と書いてるのと同じ
関数を定義するのと同じノリで定義できる




書き方
hs
pattern pat_lhs = pat
双方向
hs
pattern pat_lhs <- pat [where ...]
単方向
whereありは、explicitly bidirectional synonymsともいうっぽい?




COMPLETEプラグマで網羅性チェックできる


docsの序盤に書いている例
こんな型とコードを考える
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が使える
hs
{-# LANGUAGE PatternSynonyms #-} pattern Arrow t1 t2 = App "->" [t1, t2] pattern Int = App "Int" []
pattern という予約語を導入して、値の取りうるpatternに対して、synonymを作れる
元のコードはSynonymを使って、こう書き直せる
hs
collectArgs :: Type -> [Type] collectArgs (Arrow t1 t2) = t1 : collectArgs t2 collectArgs _ = [] isInt :: Type -> Bool isInt Int = True isInt _ = False
「値コンストラクタを使った値」のsynonymを作るのね
この例、ただの設計ミスな気がするから例としてよくなさそうmrsekut
PatternSynonymsの説明としてはわかりやすいから良いかmrsekut


この辺でみた
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点を満たすために使われている
smart constructorを定義するためのデザパタと言える





何が嬉しい?
いつ使う?
pattern という識別子が新たに導入される?

値コンストラクタを使った値に別名を付ける感じ?
ただの変数束縛とは違うの?
イメージとしては同じっぽい
構造上ただの変数束縛がそもそもできない

recordでもサポート
パターンの別名
パターンってなに #??