第11章. 怠惰な評価
この作品はAIを使って翻訳されている。ご意見、ご感想をお待ちしている:translation-feedback@oreilly.com
怠惰はしばしば人の性格的な欠点とみなされるが、プログラミング言語においては好ましい特徴と考えることができる。 コンピュータサイエンスの用語では、怠惰はコード評価の厳密さ( 熱心さ)と敵対するものである。
この章では、遅延がいかにパフォーマンスを向上させるかを紹介する。 厳密な評価と遅延評価の違い、そしてそれがコード設計に与える影響について学ぶ。
怠慢と厳格さ
言語の厳密性は、コードがどのように評価されるかのセマンティクスを記述する。
一方、非厳格評価は、式の結果が実際に必要になったときに行われる。こうすることで、1つ以上の部分式が評価に失敗しても、式は値を持つことができる。
関数型プログラミング言語Haskellはデフォルトで非厳密なセマンティクスを持ち、式を最も外側から内側に向かって評価する。 これにより、式の作成と 消費が分離されるため、制御構造や無限データシーケンスを作成することができる。
引数を2つ受け取り、ロジックには1つしか使わない単純なメソッドの厳密なJavaコードを見てみよう:
intadd(intx,inty){returnx+x;}
Haskellの厳密でない関数宣言は、変数代入のように見える:
addxy=x+x
この関数も第一引数のみを使用し、第二引数のy は全く評価しない。そのため、以下のハスケルのコードでも結果が得られる:
add5(1/0)=>10
この関数のJava等価性を同じ引数、値1 と式(1/0) で呼び出すと、Exceptionがスローされる:
varresult=add(5,(1/0));// => java.lang.ArithmeticException: Division by zero
add 呼び出しの2番目のパラメータは何も使われていないにもかかわらず、Javaは厳格な言語として、式を直ちに評価する。メソッドの引数は値によって渡される。つまり、メソッドに渡される前に評価される。この場合、ArithmeticException を投げる。
注
非プリミティブ型の場合、引数はオブジェクト・ハンドルとしてJVMからreferences と呼ばれる特殊型で渡される。これらは技術的にはまだバイ・バリューで渡され、一般的な用語とセマンティクスをかなり混乱させる。
逆に、遅延評価とは、式の結果が必要なときだけ評価することを定義している。 つまり、式の宣言が即座に評価を引き起こすことはなく、例11-1に見られるように、JavaのLambda式は遅延評価に最適なのである。
例11-1. サプライヤーを使ったJavaでの遅延評価
intadd(IntSupplierx,IntSuppliery){varactualX=x.getAsInt();returnactualX+actualX;}varresult=add(()->5,()->1/0);// => 10
IntSupplier インスタンス、またはインラインの等価性の宣言は厳密な文であり、即座に評価される。しかし実際のLambda本体は、getAsInt で明示的に呼び出されるまで評価されない。ArithmeticExceptionを防ぐことができる。
要するに、厳しさとは"やること "のことであり、 ...