16

私は最近Scalaを学んでいます。よく知っているとは言えませんが、私は Haskell に少し精通しています。

Haskell に慣れていない人のための括弧書き

私が Haskell で気に入っている特徴の 1 つは、関数がファースト クラスの市民であるだけでなく、副作用 (アクションと呼びましょう) も含まれていることです。実行時に type の値を与えるアクションはa、特定の type に属しIO aます。これらのアクションは、他の値とほとんど同じように渡すことができ、興味深い方法で組み合わせることができます。

実際、副作用を実行することはできないため、Haskell で何かを行うには、副作用を組み合わせることが唯一の方法です。むしろ、実行されるプログラムmain、関数によって返される結合されたアクションです。これは、プログラムに実際に電力を消費する以外のことをさせながら、関数を純粋にすることができる巧妙なトリックです。

このアプローチの主な利点は、副作用を実行するコードの部分をコンパイラが認識しているため、それらのエラーを検出するのに役立つことです。

実際の質問

たとえば、特定の関数内で副作用を実行しないことが保証されるように、コンパイラに副作用をチェックさせる方法はありますか?

4

2 に答える 2

23

いいえ、これは原則として Scala では不可能です。言語は参照の透過性を強制しないためです。言語のセマンティクスは副作用を認識しません。コンパイラは、副作用を追跡および強制することはありません。

ただし、型システムを使用して、一部のアクションを型としてタグ付けすることができますIO。また、プログラマーの規律により、コンパイラーのサポートの一部を取得できますが、コンパイラーの証明はありません。

于 2012-07-23T21:00:57.673 に答える
18

参照透過性を強制する機能は、Java と相互運用可能なクラス/オブジェクト システムを持つという Scala の目標とほとんど相容れません。

Java コードは任意の方法で不純になる可能性があるため (Scala コンパイラーの実行時に分析に使用できない場合があります)、Scala コンパイラーはすべての外部コードが不純であると想定する必要があります (それらにIO型を割り当てます)。Java への呼び出しを含む純粋な Scala コードを実装するには、呼び出しを と同等のものでラップする必要がありますunsafePerformIO。これによりボイラープレートが追加され、相互運用性が大幅に低下しますが、さらに悪化します。

IOプログラマーが別の方法で約束しない限り、すべての Java コードが含まれていると想定しなければならないことは、Java クラスからの継承をほぼ無効にします。継承されたすべてのメソッドは、IO型にあると想定する必要があります。Scala コンパイラーは、Java ランドのどこかに不純な実装が存在することを想定しなければならないため、これはインターフェースにも当てはまります。IOしたがって、Java クラスまたはインターフェースから非メソッドを持つ Scala クラスを派生させることはできません。

さらに悪いことに、Scala で定義されたクラスであっても、理論的には、Java で定義された非純粋なメソッドを持つ追跡されないサブクラスが存在する可能性があり、そのインスタンスが親クラスのインスタンスとして Scala に戻される可能性があります。そのため、Scala コンパイラーは、特定のオブジェクトが Java コードによって定義されたクラスのインスタンスである可能性がないことを証明できない限り、そのオブジェクトに対するメソッド呼び出しは、Java コンパイラーによってコンパイルされたコードを呼び出す可能性があると想定する必要があります。結果を返さない関数IOは実行できません。これにより、ほとんどすべてが強制的にIO. しかし、すべてを入れることIOは、何も入れずにIO副作用を追跡しないこととまったく同じです!

最終的に、Scalaは純粋なコードを書くことを推奨しますが、そうするよう強制しようとはしません。コンパイラに関する限り、何かを呼び出すと副作用が発生する可能性があります。

于 2012-07-24T01:19:57.250 に答える