読者です 読者をやめる 読者になる 読者になる

第2回 関数型言語勉強会 大阪に参加した

fpstudy 勉強会

2012/11/24 に、第2回 関数型言語勉強会 大阪が開かれた。 なんかすごい人気で補欠だったんだけど、ぎりぎり参加できた。 勢いでLTしてきたので公開する。

JavaScript関数型言語

関数型言語は人気ないけど、JavaScript はみんな使ってるし関数型言語っぽく使えるし、JavaScript関数型言語はやらせたら良いと思って発表した。

関数型言語っぽい JavaScript の使い方はこんな感じ。

filter

filter はリストの中から条件を満たすものだけを集める処理のこと。

Haskellで書くと ...

-- 0より大きいものだけ集める
xs = [-2, -1, 0, 1, 2]
filter (\x -> x > 0) xs
-- => [1, 2]

関数型言語っぽい。

伝統的なJavaScriptの場合

var xs = [-2, -1, 0, 1, 2];
var result = [];
for (var i = 0; i < xs.length; i++) {
  if (xs[i] > 0) {
    result.push(xs[i]);
  }
}

// => result は [1, 2]

かっこわるい。いまどき for のループとか意味が分からない。

でも、最近のJavaScriptならちゃんと書ける。

var xs = [-2, -1, 0, 1, 2];
var odd = xs.filter(
  function(x) { return x > 0}
);

// => [1, 2]

おしゃれ!

これは ECMAScript 5の仕様に追加されている。 対応していないブラウザは無視してよい。 ばんばん使っていきましょう。

map

map はリストのすべての要素に関数を適応して新しいリストを作るやつ。

Haskellで書くと ...

-- 全部2乗する
xs = [1, 2, 3, 4]
map (\x -> x * x) xs
-- => [1, 4, 9, 16]

いいね、いいね。うらやましい。

JavaScriptでもできる。

var xs = [1, 2, 3, 4];
var square = xs.map(
  function(x) { return x * x }
);
// => [1, 4, 9, 16]

reduce (たたみこみ)

reduce はリストを順に処理して一つにまとめるやつ。

Haskellで書くと ...

-- 1から4まで足し算する
foldl (+) 1 [2, 3, 4]
-- 10

当然JavaScriptでもできる。

var xs = [1, 2, 3, 4];
var sum = xs.reduce(
  function(x, y) { return x + y }
);
// => 10

reduceRight を使うと右から結合できる。

部分適応

部分適応は、元の関数から引数の一部を固定した新しい関数を作ること。

Haskellで書くと ...

-- かけ算する関数があります
product x y = x * y

-- 片方を-1で固定
neg = product (-1)

neg 5
-- => -5 (-1 * 5 を計算している)

JavaScriptでもできます!

var product = function(x, y) { return x * y };

// product の第1引数が -1 に固定された関数を作る
var neg = product.bind(null, -1);

neg(5) // => -5

応用例

こういうやりかたを使うと、例えば平均と標準偏差を求める計算はこんな感じで書ける。

var calc = {
  "+" : function (x, y) { return x + y },
  "-" : function (x, y) { return x - y },
  "*" : function (x, y) { return x * y },
  "/" : function (x, y) { return x / y },
  "^" : function (exponent, base) { return Math.pow(base, exponent) }
};

// 符号を反転
calc["neg"] = calc["*"].bind(null, -1);
// 2乗
calc["^2"] = calc["^"].bind(null, 2);
// ルート
calc["^(1/2)"] = calc["^"].bind(null, 0.5);


// 平均を計算する
var getMean = function(array) {
  return calc["/"](array.reduce(calc["+"]), array.length);
};
getMean([1, 1, 3, 5])
// => 2.5

// 標準偏差を計算する
var getStddev = function(array) {
  var mean = getMean(array);

  return calc["^(1/2)"](
            calc["/"](
                array
                  .map(calc["+"].bind(null, calc.neg(mean)))
                  .map(calc["^2"])
                  .reduce(calc["+"])
                ,
                calc["-"](array.length, 1)
         )
  );
};

getStddev([1, 1, 3, 5]);
// 1.9148542155126762

感想

関数型言語なんて誰も使っていない空想の言語と思ってたけど、参加者がかなり多くて驚いた。 特に実際のサービスで使っている人の話が聞けて、とてもありがたかった。 なんかもう関数型言語ってそんなに特別なものではなくて、普通に選択肢に入るような感じ。

勉強会に参加して気合が高まって何でもできそうな感じなので、僕も何かサービス作ってみようと思う。 こうやってやる気が高まったので参加してよかった。