値を受け取り、値を返すだけ
関数型プログラミングは、プログラムを「値を受け取って値を返す関数」の組み合わせで書く方法です。Haskell(ハスケル)では、どの関数にも型がつき、型を読めば何を渡せるかが分かります。
店のレジで、価格から税込みの値段を出す計算を考えます。入れた価格が同じなら、いつ計算しても同じ値段が出ます。この性質を、そのまま言語の決まりにしたのが関数型です。
このレッスンのゴール
メモ
Haskell の短い関数と、その型の宣言を読むことができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| 純粋関数 | 同じ入力なら必ず同じ出力を返す関数 | |
| 型 | 値の種類 | Int、String、Bool |
| 型シグネチャ | 関数が受け取る型と返す型の宣言 | Int -> Int |
| 関数合成 | 2つの関数をつなぎ、1つの関数にすること | |
| 式 | 評価すると値になる、ひとまとまりの書き方 |
学生が入力するセルは、このプレビューでは空白です。
純粋な関数は入力だけで決まる
純粋関数は、受け取った値だけから結果を決めます。画面に書いたり、外の変数を書きかえたりしません。同じ入力には、いつでも同じ出力です。
そのため、関数を1つずつ取り出して試せます。外の状態を気にしなくてよいので、組み合わせてもこわれにくいのが利点です。
例: 3つの小さな関数
-- 例です。-- から後ろはコメントです。
square :: Int -> Int
square n = n * n
greet :: String -> String
greet name = "Hello, " ++ name ++ "!"
isEven :: Int -> Bool
isEven n = mod n 2 == 0ラボの端末で Haskell を動かす
次のコマンドは、ラボの端末に打ちこむ1行です。runghc はファイルを動かし、ghc -e は式を1つ評価して結果を出します。コンパイラが出す文字は、すべて英語です。
Basics.hs を書きかえていなければ、上の3つの関数と、それを呼ぶ main が入っています。
Basics.hs を動かす
docker exec haskell runghc Basics.hsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
その場で関数を作って呼ぶ
docker exec haskell ghc -e 'let double :: Int -> Int; double x = x * 2 in double 21'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
型シグネチャは関数の契約である
square :: Int -> Int は、「square は Int を1つ受け取り、Int を返す」と読みます。:: の右が型で、矢印の左が入力、最後が出力です。
型を先に読めば、本体を読まなくても使い方が分かります。まちがった型の値を渡すと、動かす前にエラーで止まります。
例: 型シグネチャの読み方
| 関数 | 型シグネチャ | 読み方 |
|---|---|---|
| square | Int -> Int | 整数を受け取り、整数を返す |
| greet | String -> String | 文字列を受け取り、文字列を返す |
| isEven | Int -> Bool | 整数を受け取り、真偽を返す |
| not | Bool -> Bool | 真偽を受け取り、真偽を返す |
学生が入力するセルは、このプレビューでは空白です。
not の型を調べる
docker exec haskell ghc -e ':t not'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
型のまちがいを起こす
docker exec haskell ghc -e 'not 5'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
よくある間違い
注意
「Haskell でも max(3, 7) のようにかっこで呼ぶ」と考える人が多くいます。Haskell は関数名のあとに、空白で区切って値を並べ、max 3 7 と書きます。かっこは、まとまりを作るときだけ使います。
関数合成で2つの関数をつなぐ
関数合成は、ピリオド1つで2つの関数をつなぐ書き方です。length . words は、まず words で文を単語に分け、次に length で数えます。
右の関数が先に働き、その結果が左の関数に渡ります。型が合っていれば、つなぎ目の型も合います。
単語の数を数える
docker exec haskell ghc -e '(length . words) "one two three"'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
合成した関数の型を調べる
docker exec haskell ghc -e ':t length . words'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Python で関数を値として渡す
# 関数も、数や文字列と同じように、別の関数に渡せます。
def double(n):
return n * 2
def add_tax(price):
return price * 110 // 100
def apply_twice(f, x):
return f(f(x))
print(apply_twice(double, 5))
print(apply_twice(add_tax, 1000))
# apply_twice の中の f(f(x)) を f(x) に変えて、もう一度実行してみましょう。