はじめての
函数型プログラミング
                  うさみけんた
            Zonu.EXE

   2011年12月10日
   関数型都市勉強会
あんた誰よ
ò  うさみけんた

ò  技術趣味者
  ò  プログラミング言語
  ò  ガジェット… etc.
ò  Rubyistです(∑ÿØ
  ò  お仕事では、いろいろ。
はじめに
ò  函数ってなあに? からはじめます

ò  基本的には函数型プログラミングを知らない、
    よくわからないひと向けな感じで

ò  函数型プログラミング言語じゃなくても
    利点を巧く取り入れてプログラミングできるよ!

ò  発表者は初心者です!!1 ←重要
函数とは何か


f (x) = 3x + 2
   こんなの
わたしたちは算数で習った
ò  f (x) = 3x + 2              x      -2     -1   0   1   2
       y = 3x + 2               y      -4     -1   2   5   8
ò  この例は一次方程式の函数
   ò  ある数 x に対して、対応する値 y を計算して返す
   ò  y = 3! ("2) + 2
                         y = 3! (1) + 2 = 5
        = "6 + 2 = "4
ò  ほかにも三角函数とか対数函数とか高校(数学IIとか)
    でやった気がしますね
函数とは何か
ò  英語では function (ファンクション)

ò  函数(かんすう) = 関数
  ò  漢字表記についてはいろんな経緯があるけど省略
  ò  どうして上海をシャンハイと読むのか?
  ò  (少くとも日本人には)どっちでもいい


ò  このセッションに限っては「函数」で統一します
プログラムでは…
ò  f (x) = 3x + 2

ò  C言語なら、だいたいこんな感じに書けますね…

 int f(int x){
                 printf(“%d, ”, f(0));
     return 3 * x + 2;
         printf(“%d, ”, f(1));
 }                              printf(“%d ”, f(2));

                                2, 5, 8


 for(int n = -2; n <= 3; n++){
              n=-2 f(n)=-4
     printf(“n=%2d f(n)=%2dn”, n, f(n));
   n=-1 f(n)=-1
 }
                                          n= 0 f(n)= 2
                                             ………
ちょっと考えてみる
#include <stdio.h>
int main(void){
    for(int n = -2; n <= 3; n++){
        printf(“n=%2d f(n)=%2dn”, n, f(n));
    }
    return 0;
}


ò  このプログラムの問題点
   ò  ぶっちゃけ、継続条件を考えるのめんどくないです?
   ò  うっかり n < 3 とか n >= 3 とか書いちゃったら…?
Pythonならどうするよ
for n in range(-2, 3):
    print “n=%2d f(n)=%2d” % (n, f(n))

ò  range(-2, 3) = [-2, -1, 0, 1, 2] というリスト
   ò  range(a, b) は「a 以上 b 未満」 と読める
ò  n の値は -2, -1, 0, 1 2 と変化する

ò  コードのメリット
   ò  継続条件が「ない」
   ò  リストの各要素に対して処理を実行
設計指向の違い
ò  キミの言語は何指向?
  ò  C言語は手続き型プログラミング言語
  ò  Pythonは手続き型+オブジェクト指向+函数型
  ò  F#/Scalaは函数型+オブジェクト指向+手続き型
  ò  Haskellは純粋函数型プログラミング言語
ò  補足
  ò  どの言語でその記述ができるか、という話ではない
  ò  例: C言語でもオブジェクト指向プログラミングは可能
設計指向の違い
 ò  手続き型
 ò  オブジェクト指向
 ò  函数型
ò  処理の抽象化の違い=人間がどのように考えるか

ò  「大雑把に言って」コンパイラが最適化できるので
    これらの間で実行の速度差は出にくくなっている
 ò  むしろ、メモリの型付けシステムによって差がつく
 ò  CやC++、F#などは静的型付けの仲間 = 速い
改めて、函数型言語
ò  一般的には、ラムダ計算の概念を論理的基盤にした
    プログラミング言語のことを指す

ò  函数型言語では函数をお手軽に扱える
 ò  プログラム中で簡単に函数を定義したり、
     変数に代入できたり、使い捨ての函数を作ったり!
ò  抽象度の高いループ
 ò  リストに対する処理
 ò  再帰処理
函数型言語の系統
ò  LISP (LISt Processing)
   ò  Scheme
   ò  Common Lisp
   ò  Emacs Lisp
ò  ML (Meta-Language)
   ò  Standard ML (SML)
   ò  OCaml, F#
   ò  (Haskell)             (Scala)
R.I.P.
手続き型の中の函数型
ò  函数型言語で培われた要素は、部分的に
    手続き型言語にも持ち込まれている

ò  例えば: Ruby、Python、JavaScriptなどは
  ò  簡単に配列(リスト)を使って反復処理ができる
  ò  プログラム中で簡単に函数(相当)を定義して使える
JavaScriptだと…
// function文で定義する場合
function f1(x){
    return 3 * x + 2;
}
// function式に代入する場合
var f2 = function(x){ return 3 * x + 2 }
// 作成した函数をそのままで使用する場合
console.log( function(x){ return 3 * x + 2 }(5) )
// 配列をその場で作って、それぞれにf1を適用
[-2,-1,0,1,2].map(f1)
//=> [-4, -1, 2, 5, 8]
// その場で作った配列にその場で作った函数をry
[-2,-1,0,1,2].map(function(x){return 3 * x + 2 })
Rubyだと
# lambdaメソッドで
f1 = lambda{|x|
    return 3 * x + 2;
}
f1[5] 
#=> 17
# lambdaを配列のそれぞれに適用
[-2,-1,0,1,2].map{|x| return f1[x] }
#=> [-4, -1, 2, 5, 8]
# lambdaを配列のそれぞれに適用
[-2,-1,0,1,2].map{|x|
    return 3 * x + 2;
}
#=> [-4, -1, 2, 5, 8]
Pythonなら…再び
# 順番に実行されるだけなのでMapではない
def f1(x):
    return 3 * x + 2

for n in range(-2, 3):
    print f(n)
# リスト内包 = map と同じ
[f1(n) for n in range(-2, 3)]
#=> [-4, -1, 2, 5, 8]
# リスト内包: for 内で関数を作れる
[ (lambda x: 3*x+2)(n) for n in range(-2, 3)]
#=> [-4, -1, 2, 5, 8]
ラムダ計算とは何か
ò  ラムダ計算(lambda calculus)は、理論計算機科学や
    数理論理学における、関数の定義と実行を抽象化した
    計算体系である。ラムダ算法とも言う。

ò  例えば、ある数に 2 を加える関数 f を考える。これは
    通常の書き方では f(x) = x + 2 と書くことができるだ
    ろう。この関数 f は、ラムダ計算の式(ラムダ式とい
    う)では λx. x + 2 と書かれる。……この関数に 3 を
    適用した結果の数 f(3) は (λx. x + 2) 3 と書かれる。
  ò  以上、Wikipediaより引用 (ja.Wp: ラムダ計算)
Pythonならラムダ計算も
ò  RubyでもJavaScriptでもできるんですけどね

ò  Pythonでラムダ計算 - DT戦記(zonu_exeの日記)
  ò  この内容を実演しました
  ò  別にPythonはラムダが得意なわけではないです
発表ここまで
ò  以下のスライドは後からの補足。
質疑応答
ò  好きな函数型言語は?
 ò  F#です(∑ÿØ
 ò  最近は「ふつうのHaskellプログラミング」を読んでる
   ò  でもまづはF#ですよね
質疑応答
ò  Pythonのmapを避けたのはなぜか?
  ò  Pythonの作者がLisp的なmapとかlambdaを入れるのが
      嫌だったらしいので避けました
  ò  Pythonでは函数内にローカル変数を作れるので、
      ちょっと面倒でもdefで名前付きの函数を作るのが正統
  ò  その観点では「Pythonでラムダ計算」は邪道!
質疑応答
ò  Pythonでは再帰でスタックを食い潰さないか
 ò  すみません、調べてませんでした
   ò  末尾最適化はしてくれないらしいです
 ò  多くの函数型言語では末尾最適化してくれて、
     機械語レベルではループに置換されます
あとから気付いた
ò  手続き型って何よ、ってことをしっかり説明できて
    ないよね

ò  説明なしに「(値)に函数を適用」って喋ってたよね

ò  C++11にはlambdaあるよね、も盛り込んでおけば
    おいしかったかもしれない

ò  C++のラムダとデリゲートの話も(ry

関数型都市忘年会『はじめての函数型プログラミング』