ログイン
編集不可のページディスカッション情報添付ファイル

2013-06-24 19:18:41時点のリビジョン1

メッセージを消す
alstamber/HaskellSeminar2

MMA

ghciで遊ぼう

ghciという楽しいプログラムを使って遊びましょう。ghciというのはHaskellのインタプリタです。Ruby講習でirbというものに触れましたが、それによく似たものだと思ってください。
それではまずghciをたちあげてみましょう。

ghciが立ち上がったら色々なことを殺らせてみましょう。

まずは四則演算ですね。

1 + 2
4545 * 4545
11312 - 133333

当たり前ですが、1つの式の中に複数の演算子がある場合、数学で学んだ通りの優先順位に従って実行されます。
丸括弧を使って演算の順序を変えることもできます。

ghciで負の数を扱うときには少しだけ気をつける必要があります。

   1 1 * -2  動かない
   2 1 * (-2) 動く

次は論理演算をやってみましょう。Ruby講習に出た人ならおなじみだと思いますが、論理演算というのはTrueとFalseをつかった計算でした。
たとえば

   1 True && True
   2 False || False
   3 not False

のような演算ができます。

2つの値が等しいか等しくないかは、それぞれ==と/=という演算子で判定できます。

   1 5 == 5 True
   2 1 == 0 False
   3 5 /= 5 False
   4 5 /= 4 True
   5 "hoge" == "hoge" True

たとえば次のようなことをしてしまうとエラーになってしまいます。

   1 5 + "hoge"

"hoge"というのが数じゃないので、どうやって5と足せばいいのかわからない!というエラーが出るはずです。
+という計算をするときは、両辺に数の型が来ているかどうかをチェックして、そうでなければエラーが出るようになっているわけです。

関数を呼び出してみよう

これまでに簡単な計算をHaskellにやらせてきましたが、実はこのつまらない演習の中ですでにみなさんはHaskellの重要な概念に触れています。
それは関数です。関数はなにか値をとってそれに何か処理を施した結果を返すものだということを説明しました。
Haskellにおける関数は、Haskellのシステムの中核をなすシステムです。Haskellにおけるプログラミングは小さな関数から出発して、それを組み合わせて目的の処理をする大きな関数を作っていくという行為にほかなりません。

たとえば+というものは2つの数を引数にとって、それを足しあわせた結果を返す関数とみなせます。関数+を呼び出すためには足しあわせたい2つの数で+をはさみます。
このような関数は引数の間に置いて使うので、中置関数と言います。

しかしHaskellの関数の多くは中置関数ではありません。Haskellの関数の多くは前置関数、すなわち引数の前において使います。
Haskellで前置関数を呼び出すためには、関数名をはじめに書いて、スペースをあけて、スペースで区切られた引数を書きます。たとえば

succ 8

という感じです。succという関数は「後ろ」が定義されているものを何でもいいから引数としてとって、その「後ろ」を返す関数です。整数で「後ろ」といえば、次に大きな数です。

複数の引数を取る関数の例としてminという関数を挙げてみましょう。

   1 min 9 10

minは2つの引数をとって、どちらか小さい方を返す関数です。

関数の呼び出し(関数を適用するといいます)は、すべての計算の中で最も高い優先順位を持ちます。なので次の式はそれぞれ同じ意味を持ちます。

   1 succ 9 + 1
   2 (succ 9) + 1

また関数が2引数の時は、その関数をバッククオートで囲むことで中置関数に出来ます。たとえばmodという関数は2つの整数を引数にとって、割り算の余りを求める関数です。

   1 mod 9 2 1が答え

この呼び出し方ではどっちがどっちで割られるのかわからないかもしれません。そこで

   1 9 `mod` 2

と書くこともできます。

演習1

次の式の結果は何でしょう?

   1 succ 9 * 9

関数を作ってみよう

Haskellの基本は関数なので、関数を使うだけではなく作れるようにしたいものです。
Haskellでの関数の定義の仕方を覚えましょう。関数の定義は関数名の後ろにスペースで区切った引数が続きます。その後=という記号が続き、その後ろに関数の本体を表すコードを書きます。

とりあえず一つ関数を作ってみることにしましょう。

   1 doubleMe x = 2 * x

上のコードを皆さんの好きなエディタでかいてdouble.hsという名前で保存しましょう。それからdouble.hsを保存したディレクトリでghciを実行しましょう。
ghciが起動したら次のようにタイプします。

:l double

これで先ほど書いたdouble.hsがghciに読み込まれ、doubleMeという関数を使えるようになります。

じっさいにdoubleMeを使って遊んでみましょう。

doubleMeでひとしきり遊んだらdouble.hsに次のような関数を追加してみましょう。

   1 doubleUs x y = x * 2 + y * 2

追加できたらファイルを保存して、ghciで:l doubleとタイプして新しい関数をロードして遊んでみましょう。

関数の定義の中で自分が定義した関数を呼び出すこともできます。たとえばdoubleUsの定義の中にdoubleMeに共通する部分があることに気づけば、

   1 doubleUs x y = doubleMe x + doubleMe y

と定義することができるということに気づくでしょう。

この考え方は非常に大事です。先程も言った「小さな関数を組み合わせて目的の動作をする関数を作る」というHaskellの思想を表しているからです。

if式

次に数が100以下の時だけ数を2倍するような関数を書いてみましょう。

   1 doubleSmallNumber x = if x > 100 then x else 2 * x

ifはRubyをやっていた人なら馴染みがあるものだと思います。Haskellのifの特徴としてはelseが必須であることが挙げられます。
なぜelseが必須なのでしょうか。

Haskellではプログラムは関数の集まりなのでした。関数というのは何か値をとって必ず何か値を返すものです。もしelseを書かなくても良いのであれば、
条件が成り立たないときにはなにも値を返せないという関数を作ることができてしまうのです。これではHaskellの仕様を満たせないので、elseは必須になっています。

名前

今までは引数を持つ関数だけを扱って来ましたが、引数のない関数を考えることもできます。

   1 rasis = "RASIS is so cute"

このrasisという関数は呼び出されると必ず"RASIS is so cute"という文字列を返す関数になっています。これは言い換えれば"RASIS is so cute"という文字列にrasisという新しい名前をつけたのだということもできます。なのでHaskellでは引数のない関数を名前と呼ぶことがあります。

リスト

Haskellにはリストというデータ構造があります。リストはRubyで言うところの配列に似ていますが、それと違うところもあります。
Haskellのリストには同じ型の要素しか入れられません。なので整数のリストというものを作ることはできますが、整数と文字の両方からなるリストをつくることはできません。

またHaskellでは文字列が文字のリストとして表されています。Haskellのリストには強力な操作をできる関数がたくさん用意されているので、文字列が文字のリストとして表されていることによって、
それら強力な関数を文字列の操作に使うことができます。

リストをつくるには要素をカンマ区切りで並べて、角括弧で囲みます。

   1 let numbers = [1, 2, 3, 4]

letというのはghciの中で変数や関数を定義するための方法です。ghciの中でlet a = 1と入力するのは、なんとか.hsにa = 1と書いて、:lを使って読み込むのと同じ意味です。

リストの連結

リストに対して行う操作として最も一般的なのは連結という操作です。連結は++という演算子で行います。

   1 [1, 2] ++ [3, 4]
   2 "hello" ++ " " ++ "world"

++演算子を使うときには少し注意が必要です。++を使うとき、Haskellは++の左側のリストを最後までスキャンする操作をします(これは仕様です)。
なので++の左側が非常に大きなリストだと++という操作は非常に時間がかかります。

それに対してリストの先頭に何か一つ要素を追加するのは軽い操作になっています。この操作をするためには:演算子(consえんざんし)を使います。

   1 'a' : " small world"

:と++の違いに注目してください。:の第一引数は追加しようとしているリストの要素と同じ型の単一の要素になっています。それに対して++は必ず2つのリストを引数として受け取ります。
たとえば++を使ってリストの最後に1つだけ要素を追加したいときにも次のように書く必要があります。

   1 [1, 2, 3, 4] ++ [5]

[1, 2, 3, 4] ++ 5 は間違いです。なぜなら++は2つの引数が両方ともリストでなければいけないからです。5はリストではなくて数です。

実はHaskellでは[1, 2, 3]というのは1:2:3:[]のただのSyntax sugarです。[]は空のリストです。その先頭に3を追加すると[3]になります。そこにさらに2を先頭に追加すると[2, 3]になります。最後に1を追加すれば、[1, 2, 3]になります。

リストの要素を取り出す

リストの要素を取り出したいときには!!演算子を使います。Rubyなどと同じようにリストの中の位置は0から数えます。

   1 "hoge" !! 2
   2 [1, 2, 3, 4] !! 1

リストのリスト

Haskellのリストはリストの中にリストを要素として含むことができます。

演習の答え

演習1

先にsucc 9が実行されるので、90が答えになります。9*9の答えにsuccを適用したいなら

   1 succ (9 * 9)

と書く必要があります。丸括弧はダサいと思う人がいるかもしれません。そういう人にはもう少し後でかっこいい書き方を教えましょう。