2017-09-09 5 views
2

私はクラスSeparateを書いています。これは、異なる構造の「パーツ」に対して独立した演算を実行します。例えば複素数の実数部と複素数部(後でリストにも必要です)。このようにして、これらの構造のうちのどれが機能しているのかを気にせず、この独立した方法でそれを実行する関数を書くことができます。複合複式のインスタンス

機能は、部品のない構造で正常に機能するはずです。 Double

これは、標準偏差(私は実数を与えるが、「独立」1は、私の場合には、より理にかなって複素数のために定義された標準偏差が存在しているはず)を計算するために、他のものの間で使用されます。

しかし、私はいくつかのインスタンス宣言に問題があります。特に、業務の一つが「Doubleに掛ける」しなければならない、またの名scale*Doubleと一般Floating a間で定義されていないため

class Separate a where 
    scale :: Double -> a -> a 

instance Separate Double where 
    scale = (*) 

instance (Floating a) => Separate (Complex a) where 
    d `scale` z = (*d) <$> z 

もちろんこれはコンパイルされません。しかし、私は直接instance Separate (Complex Double) where...を定義することはできません。

クラスを持たない関数Double -> Complex Double -> Complex Doubleを書くことができますが、異なる構造に対して標準偏差を別々に定義する必要があります。

アイデア?

+2

ちょうどFlexibleInstancesを使用しています。 –

答えて

4

n.m。あなたが普及して無害な拡張子であるFlexibleInstances拡張子を使用すると、instance Separate (Complex Double)を定義することは完全に問題ありません。

しかし、他のオプションは、たとえば、あまりにも、あります

instance (Floating a) => Separate (Complex a) where 
    d `scale` z = (* realToFrac d) <$> z 

、組成インスタンスthe best kind of instance

instance (Separate a) => Separate (Complex a) where 
    d `scale` z = (d `scale`) <$> z 
+0

ニース!私は最後の選択肢が好きです。しかし、なぜコンパイラはこれについて不平を言っていません。スケールが与えられたa(例えば、Int)のように定義されていることを知ることはできませんか?後でこれが起こる可能性がある文脈でそれを使用すると、それは納得いかないでしょうか? – jorgen

+1

@ jorgen '(Separate a)=>'節に注意してください。これは 'a'に対して' scale'が定義されていることを保証します。このインスタンスは 'Complex' *は' Separate'nessを保持していると言います。 – luqui

+0

ああ、[私の作品]感覚 – jorgen

2

これはタイプ問題ではなく、問題ですあなたがインスタンスをどのように扱っているかであなたが言うように、(*)DoubleFloatの間に定義されていません。ただし、DoubleFloatの間で簡単に変換できるため、運が良かったです! realToFracを使用すると、さまざまな分数タイプ間で変換できます。

次のように私は、インスタンスを書き換えます:

instance (Floating a) -> Separate (Complex a) where 
    d `scale` z = (* (realToFrac d)) <$> z 
関連する問題