advent callendar 12/20日投稿用だったのですが、落とし所がよくわからずに期限過ぎてしまいました。ごめんなさい。
最近趣味でやってる言語にHaskellというものがあります。
いわゆる関数型言語と言うもので、数年前から、話題になり始めた感があります。
Haskellやる前はScalaに少し手を出してました。
Haskellの紹介しようと思ったけど、あまりまとまらなかったので、まずは関数型言語の説明をします。
この記事はHaskellの説明は一切ありません。また別の機会にします。
サンプルコードみたいなものはPHPで記述しています。
#関数型プログラムとは
まとめる時間が今はないので、命令形プログラムと、関数型プログラムで 1~10の足し算を書いてみる
<?php
//命令形的な 0~10の足し算
$x = 10
$sum = 0;
for ($i = 0 ; $i <=$x $i++) {
$sum = $sum + $i;
}
echo $sum;
//55
//関数型的な 0~10の足し算
function sum($x)
{
if ($x == 0) return 0;
return $x + sum($x-1);
}
echo sum(10);
//55
検索すると大体以下のようなキーワードとセットになってます。
- immutable
- 参照透過性
- 第一級関数・高階関数
- カリー化
immutable
値を定義した後に変更不可能であること、
PHPでいったら常にconstで定義してるようなものです。
この性質によって、「いつの間にか値が変わってた」みたいなバグを起こらないようにできます。
##参照透過性
簡単にいえば、同じ入力に対して、同じ結果を返す性質
例えば、以下のような関数は参照透過性ではありません
<?php
function getRandom($last)
{
return mt_rand(0, last)
}
getRandom(100);
同じ引数を与えてますが、返ってくる結果は常に同じとは限りません。
これだと、テストがしづらいです。
参照透過性のある関数を定義すると、同じ引数に対して、常に同じ結果が返ります。
第一級関数・高階関数
変数への格納や関数の引数・戻り値として定義できる関数のことです。
PHPの関数も、第一級関数・高階関数の性質をもっています。
PHPで記述すると以下のような感じになります。
変数に関数を格納する例
<?php
$hello = function($name) {return "hello ${name}!!"; };
$hello("John");
// hello John!!
関数を引数に取る例
<?php
//数値を2倍にする
$double = function($x) {return 2*$x; };
//とある範囲の数を、足し合わせる
$sum = function ($from,$to,$f){
$result = 0;
for($i = $from; $i <= $to; $i++) {
$result += $f($i);
}
return $result;
};
$sum(1, 10 ,$double);
// 110
##カリー化
いろいろ調べたり考えたりした結果、カリー化とは、どう活用するかは別として、
複数引数の関数を単引数の関数に変える。
ただこれだけと言う結論になりました。
<?php
//数値をN倍にする
$multiply = function($n,$x) {return $n*$x; };
//2引数なのでこれを1引数関数に変更する
$cmultiply = function ($n) {
$_mult = function ($x) use ($n) {return $n*$x;};
return $_mult;
};
//$cmultiplyは引数を1つ取り、関数$_multを返す関数
//第一級関数・高階関数でないと、関数を返り値にできない
//$cmultiplyを利用するとdoubleはこのように書ける
$double = $cmultiply(2);
$double(10)
// 20
//3倍する関数は以下の様に書ける
$triple = $cmultiply(3);
$triple(10)
// 30
#終わりに
今回は全然まとまらずに、関数型言語の特徴を書いただけになってしまいました。
haskellの説明も関数型言語のメリットもデメリットも全く書けていないので、次回の宿題にします。