仙石浩明の日記

2006年4月28日

Haskell

遅ればせながら Haskell で遊んでいます。 KLab の技術者の中にも、手続き型言語の世界に どっぷりつかっていて他の世界を知らない人は いるので、 tech ML (技術者向の KLab 社内メーリングリスト) で Haskell の紹介をしてみました。

~~ tech ML に投げたメールここから ~~
Subject: [tech:8480] Haskell

仙石です。

唐突ですが、Haskell って知ってますか?

私は面接した人に教えてもらった ;) のですが、最近流行りの関数型言語です。
ブログを見てると、あちこちで話題になっていますね。
入門用のページ:

  やさしい Haskell 入門 (バージョン98)
  http://www.sampou.org/haskell/tutorial-j/index.html

「やさしい」と書いてますが、関数型言語を初めて学ぼうとする人には敷居が
高いかも知れません。まずは簡単な Haskell プログラムを見てみましょう。

------------------------------------------------------------------------
guusuu x
  | x `mod` 2 == 0  =  True
  | otherwise       =  False
------------------------------------------------------------------------

これは guusuu(x) という関数の定義です。

  x を 2 で割った余りが 0 ならば、guusuu(x) = True
  それ以外ならば、                guusuu(x) = False

と読みます。簡単ですね? ;)
早速実行してみましょう。
上記プログラムを test.hs というファイル名で保存しておいて、
Haskell 処理系である ghci コマンドを実行します。

------------------------------------------------------------------------
senri:/home/sengoku/tmp % ghci
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.4.2, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base-1.0 ... linking ... done.
Prelude> :load test.hs
Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> guusuu 2
True
*Main> guusuu 7
False
*Main>
------------------------------------------------------------------------

「:load test.hs」というのが「test.hs」を読み込むためのコマンドです。
「guusuu 2」を実行すると、guusuu(2) の値である True が出力されていますね。
これだけだと、あまり能がないので、偶数列を表示させてみましょうか。

------------------------------------------------------------------------
*Main> take 10 [1,2..]
[1,2,3,4,5,6,7,8,9,10]
*Main> take 10 [x|x <- [1,2..], guusuu x]
[2,4,6,8,10,12,14,16,18,20]
------------------------------------------------------------------------

「take 10」というのはその後ろのリストの先頭 10 個の要素を取り出す関数で
す。「[1,2..]」というのは自然数列のリストですね。take を使わずに [1,2..]
を表示させようとすると、無限に自然数列を表示します。

------------------------------------------------------------------------
*Main> [1,2..]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22, ...無限に続く...
------------------------------------------------------------------------

途中で止めるには control-C を押します。
さて、

  [x|x <- [1,2..], guusuu x]

という書き方は、グラフ理論の輪講に参加している人や、述語論理を学んだこと
のある人にはおなじみの書き方じゃないでしょうか。自然数列の中で、
述語 guusuu(x) が True であるような x のみ取り出したリスト、という意味です。

じゃ、このプログラムはどうでしょう?

------------------------------------------------------------------------
hurui [] = []
hurui (top:rest) = top:(hurui [x|x <- rest, x `mod` top /= 0])
------------------------------------------------------------------------

関数 hurui は引数としてリストをとります。「[]」は空リストです。つまり要
素が何もないリストですね。引数が空リストならば hurui [] の値も [] です。

引数が [] でない場合は、引数のリストを、先頭 top と残り rest に分解します。
例えば hurui [3,5,9,11,13] の場合、top が 3 で rest が [5,9,11,13] です。

# このあたり、lisp を知っている人にはおなじみの概念ですね

次に top と (hurui [x|x <- rest, x `mod` top /= 0]) をつなげたリストを、
hurui の値として返します。「:」がリストを作るための演算子です。

# lisp で言うところの cons と言えば lisp を知っている人には簡単ですね

では (hurui [x|x <- rest, x `mod` top /= 0]) とは何でしょう?

「/=」というのは等しくない、という演算子です。C で言うところの「!=」です
ね。つまり、rest の中で「x `mod` top /= 0」が True になるものを取り出し
たリストを求め、これを引数として hurui を再帰呼出しして求めたリスト、と
いうことになります。

top が 3 で rest が [5,9,11,13] でしたから、3 で割って余りが 0 でない
(つまり 3 で割り切れない) もののリスト、ということになります。9 以外は 3
で割り切れないので [5,11,13] ですね。これを引数として hurui に与えます。
つまり、3 (top の値) と hurui [5,11,13] の値をつなげたリストが答になりま
す。

同様に hurui [5,11,13] の値は、5 と hurui [11,13] (11 も 13 も 5 では割
り切れないから) の値をつなげたリストですね。というのをどんどん再帰的に繰
り返すと、hurui [3,5,9,11,13] の値は [3,5,11,13] になります。実際に試し
てみましょう:

------------------------------------------------------------------------
*Main> hurui [3,5,9,11,13]
[3,5,11,13]
------------------------------------------------------------------------

スルドイ人はすでに分かっていると思いますが、
この関数は「エラトステネスの篩」です。したがって、

------------------------------------------------------------------------
*Main> take 20 (2:hurui [3,5..])
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71]
------------------------------------------------------------------------

などと実行することにより、20個の素数を列挙することができました。

どうです? 面白いでしょう?

関数型言語を知っている人は、たぶん Haskell もすぐ使いこなすことができる
と思いますし、関数型言語を知らない人は、ぜひこの機会に知ることをオススメ
します。なぜなら関数型言語を知らないプログラマってプログラミング言語の世
界の半分しか知らないわけで、Haskell を学ぶことにより世界が大きく広がると
思うからです。

関数型言語を初めて学ぶ人は、まずは

  入門Haskell―はじめて学ぶ関数型言語
  向井 淳 (著)

あたりを読むのがいいかも知れません。私の机の上に置いておくので、興味ある
かたはどーぞ (先着一名様限定)。

この本は、副題にもあるように関数型言語を初めて学ぶ人向けに書かれているの
で、イマイチ本質を外しているんですよねぇ... だから本音ではオススメな本で
はない ;-) のですが、関数型言語へのとっかかりとしてはよいのかも知れません。

#13425                                                          仙石 浩明
https://www.gcd.org/sengoku/             Hiroaki Sengoku <sengoku@gcd.org>
~~ tech ML に投げたメールここまで ~~

このメールに一番早く反応したのは、KLab の開発に参加いただいている 協力会社 H 社の CTO の T さんでした。 T さんとはご無沙汰していたのですが、 彼も私と同様に Haskell で遊んでいたことが分かって、 さすがと思った次第。

# 協力会社さんに負けずに頑張ってね > KLab 社員

~~ T さんのメール(一部抜粋)ここから ~~
ご無沙汰しております。
H 社の T です。

Hiroaki Sengoku wrote:
> 唐突ですが、Haskell って知ってますか?

なぜか私も、今月の頭ぐらいにとあるブログで知って(YAPC::Asia 2006のPugs関連
のエントリだったような…)

>   入門Haskell―はじめて学ぶ関数型言語
>   向井 淳 (著)

を購入して、ひそやかに楽しんでおりました。
そして、いやあ、これは、自分だけ楽しんでいるには余りにももったいないので、
(H社内の)勉強会のネタにしようと宣言していた矢先に、投稿を拝見しまして、
つい反応してしまいました。
~~ T さんのメール(一部抜粋)ここまで ~~

KLab でも Haskell 勉強会やりましょう!

Filed under: プログラミングと開発環境 — hiroaki_sengoku @ 06:32

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment