2017-09-09 159 views
2

我正在编写一个类Separate,它在不同结构的“部分”上独立执行某些操作;例如一个复数的真实和复杂的部分(后来我还需要它的列表)。通过这种方式,我可以编写不关心他们正在执行的这些结构中的哪一个的函数,但会以这种独立的方式执行。复杂对偶实例

这些功能应该在没有零件的结构上正常工作,例如, Double。 (我知道有一个标准偏差定义为复数,它给出了一个实数,但“独立”一个在我的情况下更有意义)。

但我遇到了一些实例声明的问题。在操作中尤其应该是“乘用Double”,又名scale

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 

当然这并不编译,因为*是不是一个Double和一般Floating a之间定义。但我不能直接定义instance Separate (Complex Double) where...

我可以只写一个函数Double -> Complex Double -> Complex Double没有类,但标准偏差必须分别为不同的结构定义。

任何想法?

+2

只需使用FlexibleInstances。 –

回答

4

至于中午。指出,定义instance Separate (Complex Double)是完全正常的,如果您使用FlexibleInstances扩展名,这是一个流行和无害的扩展。

但也有其他的选择,太多,例如:

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

不错!我喜欢最后的选择。但为什么编译器不会抱怨呢?它不知道规模是否定义为一个给定的(例如Int)?如果你在稍后发生这种情况时使用它,它会不会complan?我应该仔细阅读构成实例.. – jorgen

+1

@jorgen注意'(Separate a)=>'子句,它保证'a''为'a'定义。这个例子说'Complex' *保留了*'Separate'的性质。 – luqui

+0

啊,有道理 – jorgen

2

这是一个类型的问题,而不是一个问题以及你如何处理实例。如您所说,(*)未在DoubleFloat之间定义。但是,我们可以轻松地在DoubleFloat之间进行转换,所以您很幸运!使用realToFrac,我们可以在各种分数类型之间进行转换。

如下我会改写实例:

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