web-dev-qa-db-ja.com

purescriptの拡張可能な効果

Purescript 、IO=では、他の効果はEffモナドと、次のように宣言される拡張可能な効果で管理されます。

main :: Eff (trace :: Trace, random :: Random) {}

したがって、私がよく理解している場合、このmain宣言ではコンソールへのログ記録と乱数の生成のみが許可されます。 trace :: Trace, random :: Randomは、エフェクトの行、つまり、順序付けされていないラベル付きのエフェクトのコレクションです。

Traceが効果であり、traceがそのラベルであることがわかりました。しかし、なぜ両方が必要なのでしょうか。 { foo::String, bar::String }などのレコードには意味がありますが、異なるラベルで2つのRandom効果を管理する必要がある理由がわかりません。つまり、次のように記述します。

main :: Eff (Trace, Random) {} -- no redundant labels

エフェクトラベルはpurescriptで役立ちますか?はいの場合はどうですか?

5
Simon Bergot

簡単な答えは、PureScriptコンパイラの最初のリリースから、行の機構がタイプチェッカーにすでに存在していたため、Effモナドを定義するために再利用することは理にかなっています。唯一の変更は、ラベルでインデックス付けされたタイプの種類によって行をパラメーター化できるようにすることでした。

確かにラベルは不要のようで、効果が単なるシンボルである場合はそうなります。ただし、もう1つの答えは、ラベルを使用すると、型システムで最も一般的なunifiersを使用するという望ましい特性を維持できることです。

考案された例

タイプが2つ以上の不明なタイプ変数を持つエフェクトの行を含むハンドラーを定義したとします。

runFooBarEffects :: forall eff foo bar. Eff (foo :: foo, bar :: bar | eff) a -> Eff (combined :: Baz foo bar | eff) a

そして、対応する具体的な効果タイプのアクション:

myAction :: Eff (foo :: Foo, bar :: Bar, trace :: Trace) String

_runFooBarEffects myAction_を使用してこのアクションを実行しようとすると、型チェッカーは統合によって結果の型Eff (combined :: Baz Foo Bar, trace :: Trace) Stringを正しく推測します。

ただし、ラベルが存在しない場合を想像してみてください。行が順序付けされていないため、fooFooまたはBarのいずれかと統合できるため、統合アルゴリズムは続行できません。 2つの行の最も一般的なunifierはなくなりました。

この例は実際に考案されたものですが、行に表示される単純なアトミック型(記号)に限定されず、型の格子全体を持っているため、型システムを正常に保つためにラベルが必要であるという点を示しています。

6
Phil Freeman

私はPureScriptを使用したことがありませんが、簡単な答えは「はい」です。エフェクトラベルは、effectsを原理的にモデリングするのに役立ちます。

あなたの経歴がわからないので、質問にどのレベルで答えればよいかわかりません。副作用、それらの無制限の使用の欠点、関数型プログラミング、およびFPで副作用を回避しようとする理由をよく知っていますか?もしそうなら、それはエフェクトシステムに良い動機を提供し、それはそれらの無制限の使用を許可することなくエフェクトを使用することを可能にします。静的型付け言語では、型システムの影響を明示的に追跡することも可能です。人気のあるエフェクトシステムの1つはモナドトランスフォーマーです(もちろん、欠点がないわけではありません-しかし、一般的な言語ですでに実装されていますしたがって、実験を始めるのは簡単です)。

あなたがそれをすべて理解しているなら、おそらくあなたの質問は、なぜ同じ効果の複数の個別のインスタンスが必要/望まれるのかということでしょうか?疑似乱数ジェネレーターは乱数を生成せず、生成された数値間の関係はランダムではありません-したがって、2つ(またはそれ以上)の個別のランダム効果により、基本的に2つ(またはそれ以上)の無相関の疑似乱数を持つことができますストリーム。

免責事項:私はPureScriptを使用したことがありません-これは私の意見です!

なぜ同じ効果の複数の個別のインスタンスが必要/必要になるのでしょうか?疑似乱数ジェネレーターは乱数を生成せず、生成された数値間の関係はランダムではありません-したがって、2つ(またはそれ以上)の個別のランダム効果により、基本的に2つ(またはそれ以上)の無相関の疑似乱数を持つことができますストリーム。

名前を使用するもう1つの利点は、特定の効果のインスタンスが1つしかない場合でも、意味のあるラベルを使用して効果に意味的な意味を付けることができることです。つまり、すべてのStatesが同等に作成されるわけではありません。


同じ効果の複数のインスタンスを使用する別の例として、パーサーコンビネーターを確認してください。これらは、モナドトランスフォーマーなどのエフェクトシステムから簡単に構築できます。単純なバックトラッキング、エラー報告パーサーは、次のものから構築できます。

  • 状態-入力文字列を処理します
  • エラー-エラー報告
  • 多分-バックトラック

エフェクト(申し訳ありませんが、Haskellの用語です-これらがPureScriptのエフェクトにどのようにマッピングされるかはわかりません)。解析中に位置(行、列)も追跡したい場合は、2番目のStateエフェクトを追加できます。 3番目のStateエフェクトを使用して、グローバル変数の宣言を追跡することもできます(プログラミング言語を解析していると仮定します)。原則として、3つすべてのStateエフェクトを1つのエフェクトに組み合わせることができますが、これによりカップリングが導入され、拡張性が低下します。それらを分離することで、この結合を回避できます。

2
user39685