私が意味するのは、関数のローカルスコープ(let
またはwhere
)に適用されるタイプクラスのインスタンスを定義することです。さらに重要なのは、このインスタンスの関数をクロージャーにしたい、つまりインスタンスが定義されているレキシカルスコープ内の変数をクローズできるようにしたいということです(インスタンスが呼び出された次回の関数)。"ローカル"タイプクラスインスタンスを持つことは可能ですか?
私はあなたにこれを簡略化したユースケースを与えることができます。型クラスに基づいた型で動作する関数があるとします。この例では、私はsquierを使用しています。これはインスタンスNum
のインスタンスで動作します(正方形は非常に単純で簡単に再実装できますが、複雑になる可能性があります)。私は既存の機能をそのまま使用する必要があります(変更や再実装なし)。
square :: Num a => a -> a
square x = x * x
ここで、この演算をモジュラ演算、つまり加算、乗算などmodで使用したいとします。これは固定のモジュロベースでは簡単に実装できますが、モジュロベースごとに再利用できる汎用のものを用意したいと思います。私はこのような何かを定義することができるようにしたい:
newtype ModN = ModN Integer deriving (Eq, Show)
-- computes (x * x) mod n
squareModN ::
squareModN x n =
let instance Num ModN where
ModN x * ModN y = ModN ((x * y) `mod` n) -- modular multiplication
_ + _ = undefined -- the rest are unimplemented for simplicity
negate _ = undefined
abs _ = undefined
signum _ = undefined
fromInteger _ = undefined
in let ModN y = square (ModN x)
in y
これのポイントは、私が(square
)上から機能を使用する必要があるということですが、特定のインスタンスである型であるために、その引数を必要としますタイプクラス。私は新しいタイプを定義し、それをNum
のインスタンスにします。ただし、モジュロ演算を正しく実行するには、モジュロベースn
に依存します。これは、この関数の汎用設計により、コールからコールに変更される可能性があります。私はsquare
関数が今度は(そして今回のみ)操作をどのようにカスタマイズするかを一回限りの「コールバック」(もしあれば)のようなものとしてインスタンス関数を定義したいと思います。
「閉包変数」をデータ型自体に直接組み込むことができます(つまり、番号とそれが属する基数を表現するためにModN (x, n)
)。操作では引数からこの情報を抽出できます。しかし、これにはいくつかの問題があります。1)複数引数関数(例えば(*)
)の場合、実行時にこれらの情報が一致しているかどうかを確認する必要があります。 2)インスタンスには、0変数の「値」が含まれている可能性があります。これは、クロージャ変数に依存することができますが、引数を含まないため引数から抽出できません。
いいえローカルインスタンスを持つことはできません。モジュラー算術Oleg KiselyovとCC Shanは、彼らの論文 "Implicit Configurations"(http://www.cs.rutgers.edu/~ccshan/prepose/prepose.pdf)の問題を解決しました。個人的に私はこれを避け、単にモジュールベースの新しいタイプ、つまりZ7、Z12を作成する傾向があります。 Conal Elliottは、別のタイプのクラスを選択するための別のパターンを持っています.CxMonoidの論文「Applicative Data-Driven Computation」 - http://conal.net/papers/data-driven/paper.pdf –
を参照してください。 Olegペーパーのパッケージ版。 – ehird
ハスケルの現在の状態について:いいえ。インスタンスは、どこにでも、どこにでも手を届けることができます。将来のハスケルへの調整について:おそらく。 typeclassesではなく独自のメカニズムの使用について:はい。 –