Haskell超入門 Part.2
-
Upload
yuichi-watanabe -
Category
Technology
-
view
880 -
download
5
description
Transcript of Haskell超入門 Part.2
Nabe
Twitter / Facebook / Hatena
nabe256
Haskellにおけるクロージャ
Twitterの某発言から
› @rizumita: @nabetaro 関数型言語とかクロージャとかが聞きたいです。話せる人がどれだけいるか分かりませんが…
› @nabetaro: 関数型言語というと、話したい人がいるんじゃないかな〜(他力本願)
› @nabe256: Haskellで発表出来るかなぁ・・・
Twitterの某発言から
› @rizumita: @nabetaro 関数型言語とかクロージャとかが聞きたいです。話せる人がどれだけいるか分かりませんが…
› @nabetaro: 関数型言語というと、話したい人がいるんじゃないかな〜(他力本願)
› @nabe256: Haskellで発表出来るかなぁ・・・
そんな餌で俺様が釣られクマ――(AA略
でもクロージャは
ふいんき(←なぜか変換できない)
だけしか知らない。
なので、
関数型言語Haskellにおける
クロージャについて
それっぽい解説を。
Haskellは初心者レベルです。
クロージャは名前だけなら知ってるというレベルです。
色々調べてみましたが、間違いが含まれている可能性が大いにあります。
おかしな所があったら是非教えてください。
クロージャ(クロージャー、closure、閉包)はプログラミング言語における関数の一種。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。
(by Wikipedia)
なにゆーてんの?
典型的には、クロージャはある関数全体が他の関数(以下、エンクロージャ)の内部で宣言されたときに発生し、内部の関数はエンクロージャのローカル変数(レキシカル変数)を参照する。実行時に外部の関数が実行された際、クロージャが形成される。クロージャは内部の関数のコードとエンクロージャのスコープ内の必要なすべての変数への参照からなる。
(by Wikipedia)
なにそれ。おいしいの?
クロージャは
関数内で一時的な関数を作るための仕組み。
言葉で説明しても難しいので、
サンプルを作って考えてみる。
普通の書き方から。
割り算を計算する関数。 div :: Double -> Double -> Double
div x y = x / y
引数を二つ取り、値を返す関数。
使い方 ghci> div 4 3
1.3333333333333333
式変形をしてみる。
div’ x y = f
where
f = x / y
使い方 ghci> div’ 4 3
1.3333333333333333
div’ x y = f
where
f = x / y
fは外側のdiv’関数(エンクロージャ)の中で
定義された一時関数(クロージャ)になる。
クロージャはエンクロージャより外からは
参照出来ない。
fからは、エンクロージャの値(x,y)を参照することが出来る。
引数付きの関数も作成可能。
div’’ x y = f x y
where
f a b = a / b
使い方 ghci> div’’ 4 3
1.3333333333333333
二次方程式の解の公式
roots a b c =
((-b + sqrt(b*b – 4*a*c)) / (2*a),
(-b – sqrt(b*b – 4*a*c)) / (2*a))
roots a b c =
((-b + sqrt(b*b – 4*a*c)) / (2*a),
(-b – sqrt(b*b – 4*a*c)) / (2*a))
roots’ a b c =
((-b + det) / (2*a),
(-b – det) / (2*a))
where det = sqrt(b*b – 4*a*c)
roots a b c =
((-b + sqrt(b*b – 4*a*c)) / (2*a),
(-b – sqrt(b*b – 4*a*c)) / (2*a))
roots’ a b c =
((-b + det) / (2*a),
(-b – det) / (2*a))
where det = sqrt(b*b – 4*a*c)
共通部分をひとまとめにして、
見やすくする事が可能。
Haskellではwhereとほぼ同じ機能を
持つものとしてletというものがある。
whereの前と後を入れ替えたようなもの
なので、読みやすさや状況によって
使い分ける。
恐らくwhereの方が一般的に使われている。
同じ名前で関数定義すると、実際にどちらが使われているのか分かりづらい。
混ぜるな危険。
引数の一部だけ指定して定義。
div x y = x / y
div4 = div 4
ghci> div4 3
1.3333333333333333
値を固定した関数を作る事が出来る。
これもクロージャの一種。
定義が必ずしも必要でない書き方。
div’’’ = ¥x -> ¥y -> x / y
使い方 ghci> div’’’ 4 3
1.3333333333333333
ghci> (¥x -> ¥y -> x / y) 4 3
1.3333333333333333
同じような事が出来る。
使い方によってはこれもクロージャの一種。
言語によってクロージャの定義が
異なったりしています。
解説者によっても
ばらつきがあるように見えます。
Don’t think. Feel!
引数を二つ取り、値を返す関数について。
先程の割り算を計算する関数。 div :: Double -> Double -> Double
div x y = x / y
引数を二つ取り、値を返す関数について。
正確には、
引数を一つ取り、
[引数を一つ取り、値を返す関数]
を返す関数。
正しい意味を解説すると難しい話に
なるので、ここでは説明はしない。
引数や返り値について
もう少し詳しく知りたい人は
「Haskell超入門 Part.1」を見てみると
もしかしたらわかるかも。
確実に理解したい方は、
もっと詳しく丁寧に説明しているサイトが
沢山ありますのでとりあえずググれ。
先程のdiv関数に小細工。
div x y = x / y
div’’ x y = (/) x y
div’’’ x = (/) x
div’’’’ = (/)
式変形によって値を消すことが可能。
値が無い状態をポイントフリーと呼ぶ。
(ポイント=値、変数、引数)
いろんなテクニックがあるので奥が深い。
ポイントフリーと部分適用を使うと
関数合成が自由に行える。
ポイントフリーに限らず、式変形は面白い。
詳細はとりあえずググれ。
Q.こんな時、どんな書き方をすれば良いか
わからないの。
Q.こんな時、どんな書き方をすれば良いか
わからないの。
A.ググればいいと思うよ。
クロージャの説明が少なかったので
調べるのに苦労しました。
わかりやすいサンプルが作れなかったのが残念。
Haskellは難しいけど楽しいです。