Haskell Reportは、リスト内包表記をどのように変換するかを教えてくれます:
[ e | True ] = [e]
[ e | q ] = [ e | q, True ]
[ e | b, Q ] = if b then [ e | Q ] else []
[ e | p <- l, Q ] = let ok p = [ e | Q ]
ok _ = []
in concatMap ok l
[ e | let decls, Q ] = let decls in [ e | Q ]
リスト内包表記は反駁できないパターン (つまり、決して失敗しないパターン) のみを使用するため、上記の 4 番目の節はいくらか単純化されています。
[ e | p <- l, Q ] = concatMap (\p -> [ e | Q ]) l
簡潔にするためにこのバージョンを使用しますが、真の導出ではレポートの定義を使用する必要があります。(宿題: 実際の翻訳を試してみて、最終的に「同じもの」が得られることを確認してください。) 試してみましょう。
[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]
= concatMap (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]] [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y]]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y], True]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z) | True]) [1..y]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z)]) [1..y]) [1..x]) [1..10]
そして、ついにリスト内包表記のないバージョンにたどり着きました。
concatMap
モナドに慣れている場合は、リストの(>>=)
関数の反転バージョンであることを観察することで、この式の動作についての洞察を得ることができます。また、[e]
リストの のようなものreturn e
です。したがって、モナド演算子で書き直すと、次のようになります。
= [1..10] >>= \x ->
[1..x] >>= \y ->
[1..y] >>= \z ->
return (x,y+z)