   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
                 fab=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    xy=x/y
 div’’ x y = (/) x y
 div’’’ x = (/) x
 div’’’’   = (/)
 式変形によって値を消すことが可能。
 値が無い状態をポイントフリーと呼ぶ。
  (ポイント=値、変数、引数)
 いろんなテクニックがあるので奥が深い。
 ポイントフリーと部分適用を使うと
  関数合成が自由に行える。
 ポイントフリーに限らず、式変形は面白い。
 詳細はとりあえずググれ。
Q.こんな時、どんな書き方をすれば良いか
  わからないの。
Q.こんな時、どんな書き方をすれば良いか
  わからないの。
A.ググればいいと思うよ。
 クロージャの説明が少なかったので
  調べるのに苦労しました。
 わかりやすいサンプルが作れなかったのが
  残念。
 Haskellは難しいけど楽しいです。

Haskell超入門 Part.2

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