先日、Haskellのリストを処理する関数で、2つのリストの直積(direct product)を返す関数を探していて、僕は見つけられなかった。仕方ないのでリスト内包表記で書いた。
[(x, y) | x <- [0,1], y <- ['a','b']]
--[(0,'a'),(0,'b'),(1,'a'),(1,'b')]
先日、見知らぬ人のブログを見ていて、我が目を疑った。全く同じ結果を返す以下のようなコード例が記されていたのだ。
main = print f
f = do
x <- [0,1]
y <- ['a','b']
return ((x, y))
--[(0,'a'),(0,'b'),(1,'a'),(1,'b')]
この「do記法」で書かれた一連の処理を1行で書いたものが、「リスト内包表記」なんだろうか…?
これまでは、
[n * n | n <- ns]
のようなリスト内包表記の中で用いられる「<-」という記号と
line <- getLine
のような入出力で用いられる「<-」という記号は、同じ記号が異なる意味で用いられているのだろうと思っていた。そうではないってことなのか…。
驚くと同時に、腑に落ちる感覚もあった。「リスト内包表記」に妙に「命令型(手続き型)言語」の匂いを感じていた僕だが、「do記法」は「リスト内包表記」なんて比較にならないホド「命令型(手続き型)言語」の匂いを放っている(と言うか、そもそも「命令型(手続き型)言語」風のコードを記述可能にするための記法が「do記法」なんだろうけど)。
「リスト内包表記」も「do記法」もどちらも、Haskellというプログラミング言語にとってもっと本質的な機能(「モナド」とかその辺りの何か)のシンタックスシュガーに過ぎない、ということなのかな〜。
この辺りの話は、Haskell入門を最後まで読めば、中盤過ぎ辺りで述べられているのだろうけど、僕は前半で躓いてしまっているので…。Haskellというプログラミング言語の学習には、Haskellの仕組みそのものの理解を楽しむ、という面もある。先を急がず、お楽しみは後にとっておこう(笑)。