2012-03-03 22 views
17

私が意味するのは、関数のローカルスコープ(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変数の「値」が含まれている可能性があります。これは、クロージャ変数に依存することができますが、引数を含まないため引数から抽出できません。

+2

いいえローカルインスタンスを持つことはできません。モジュラー算術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 –

+1

を参照してください。 Olegペーパーのパッケージ版。 – ehird

+0

ハスケルの現在の状態について:いいえ。インスタンスは、どこにでも、どこにでも手を届けることができます。将来のハスケルへの調整について:おそらく。 typeclassesではなく独自のメカニズムの使用について:はい。 –

答えて

11

提案された拡張機能は、私のthis previous answerで示された同じ問題を持っています。ローカルインスタンスを使用して同じキータイプで異なるOrdインスタンスを持つ2つのMapを作成すると、すべての不変条件がクラッシュする可能性があります。

しかし、reflectionパッケージには、あなたがそのようなModNタイプを定義することができます:あなたはReifies制約を持つ単一のインスタンスを定義して、reifyで特定のNのインスタンスを起動します。 (私はimplicit parametersもこれを可能にすると信じていますが、その拡張はめったに使われません)