Haskell Language
リストの理解
サーチ…
基本的なリストの理解
Haskellにはリストの解説があります 。これは、PythonやJavaScriptなどの命令型言語での数学や同様の実装での解説のようなものです。彼らの最も基本的なリスト内包は、次のような形をとっています。
[ x | x <- someList ]
例えば
[ x | x <- [1..4] ] -- [1,2,3,4]
関数をxに直接適用することもできます:
[ f x | x <- someList ]
これは次のようになります。
map f someList
例:
[ x+1 | x <- [1..4]] -- [2,3,4,5]
ジェネレータ式のパターン
しかし、ジェネレータ式のx
は変数だけでなく、任意のパターンであることができます。パターンの不一致の場合、生成された要素はスキップされ、リストの処理は次の要素に進み、フィルタのように動作します。
[x | Just x <- [Just 1, Nothing, Just 3]] -- [1, 3]
パターン内に変数x
持つジェネレータは、その右側のすべての式を含む新しいスコープを作成します。ここで、 x
は生成された要素です。
これは、ガードが次のようにコーディングできることを意味します。
[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]
警備員
リスト内包表記のもう1つの特徴はガードであり、フィルターとしても機能します。ガードはブール式であり、リストの理解のバーの右側に表示されます。
彼らの最も基本的な使用は
[x | p x] === if p x then [x] else []
ガードで使用される変数は、その理解の左側に表示されなければなりません。そう、
[ f x | x <- list, pred1 x y, pred2 x] -- `y` must be defined in outer scope
これは
map f (filter pred2 (filter (\x -> pred1 x y) list)) -- or,
-- ($ list) (filter (`pred1` y) >>> filter pred2 >>> map f)
-- list >>= (\x-> [x | pred1 x y]) >>= (\x-> [x | pred2 x]) >>= (\x -> [f x])
( >>=
演算子はinfixl 1
。つまり、左に括弧でinfixl 1
ます)。例:
[ x | x <- [1..4], even x] -- [2,4]
[ x^2 + 1 | x <- [1..100], even x ] -- map (\x -> x^2 + 1) (filter even [1..100])
ネストされたジェネレータ
リスト内包表記は、複数のリストから要素を引き出すこともできます。その場合、結果は、2つのリストがネストされた方法で処理されたかのように、2つの要素のすべての可能な組み合わせのリストになります。例えば、
[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]
-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
パラレル・コンピューティング
Parallel List Comprehensionsの言語拡張により、
[(x,y) | x <- xs | y <- ys]
は
zip xs ys
例:
[(x,y) | x <- [1,2,3] | y <- [10,20]]
-- [(1,10),(2,20)]
ローカルバインディング
リスト内包表記では、変数にローカルバインディングを導入して、いくつかの中間値を保持できます。
[(x,y) | x <- [1..4], let y=x*x+1, even y] -- [(1,2),(3,10)]
トリックで同じ効果を達成することができますが、
[(x,y) | x <- [1..4], y <- [x*x+1], even y] -- [(1,2),(3,10)]
let
インリスト内包は、いつものように再帰的です。しかし、ジェネレータのバインディングはシャドーイングを可能にするものではありません。
[x | x <- [1..4], x <- [x*x+1], even x] -- [2,10]
表記を行う
任意のリスト内包は、それに対応して符号化することができるのは、リストモナド do
記法を 。
[f x | x <- xs] f <$> xs do { x <- xs ; return (f x) }
[f x | f <- fs, x <- xs] fs <*> xs do { f <- fs ; x <- xs ; return (f x) }
[y | x <- xs, y <- f x] f =<< xs do { x <- xs ; y <- f x ; return y }
ガードは、 Control.Monad.guard
を使用して処理できます。
[x | x <- xs, even x] do { x <- xs ; guard (even x) ; return x }