正格評価と遅延評価のイメージ
関数の評価の違いを授業で聞いて、分かりやすかったから忘れないようにまとめておきます。
正格評価を C++
、遅延評価を Haskell
のコードで説明していきます。
正格評価
簡単に言うと、値を使うか使わないか考えず渡されたら評価する事です。
a.cpp
#include <iostream>
using namespace std;
int foo(int a, int b) {
return a;
}
int bar(int a) {
return bar(a - 1);
}
int main(int argc, const char* argv[]) {
cout << foo( 2, bar(1) ) << '\n';
}
上のプログラムは main
関数で foo
関数を呼んでいます。foo
関数は第一引数の a
を返すだけなので b
は必要無いです。しかし、正格評価 をする言語では b
の値も先に計算しようとします。bar
関数 は終了条件が無い再帰関数なので b
の値を計算できないです。従って、このプログラムはセグメントエラーかプログラムが終了しないです。
実行結果
$ g++ a.cpp
$ ./a.out
Segmentation fault
$ g++ -O2 a.cpp
$ ./a.out
最適化オプションをつけないでコンパイルすると、プログラムに割り当てられたスタック領域をドンドン使うので、セグメントエラーが起きます。オプションをつけるとスタック領域を増やさないようにするので、セグメントエラーは起きないです。
遅延評価
簡単に言うと、変数が使われた時に初めて値を計算しようとする評価の事です。
a.hs
foo a b = a
bar a = bar (a - 1)
main = do
print ( foo 2 (bar 1) )
関数は先ほどの C++
のコードと同じです。
しかしHaskell
では、遅延評価 をするのでちゃんとプログラムは終わります。
実行結果
$ ghc a.hs
$ ./a
2