Haskell 具有多个类的函数的实例

Haskell 具有多个类的函数的实例,haskell,functional-programming,Haskell,Functional Programming,我想实现自定义数据类型的幂函数。我是指具有以下签名的电源(^): (^) :: (Num a, Integral b) => a -> b -> a 我的意思是,我的数据类型MyData应该是Num的实例,这样我就可以编写 x :: MyData ... y = x ^ b 其中b是一些积分。当我们需要一个类的函数,比如 (+), (-), (*) :: (Num a) => a -> a -> a 我们只是写信 instance Num MyData

我想实现自定义数据类型的幂函数。我是指具有以下签名的电源(^):

(^) :: (Num a, Integral b) => a -> b -> a
我的意思是,我的数据类型
MyData
应该是
Num
的实例,这样我就可以编写

x :: MyData
...
y = x ^ b
其中b是一些积分。当我们需要一个类的函数,比如

(+), (-), (*) :: (Num a) => a -> a -> a
我们只是写信

instance Num MyData where
  (*) x y = someFunc x y
但是考虑到还有积分b,我不知道如何定义它。这种语法应该是

instance (Integral b) => Num MyData b where
  (^) x y = someFunc x y

但我已经尝试过一百种这样的变化,但都没有效果。数小时的谷歌搜索也无济于事。

您不必做任何事情来定义数据类型的
(^)
;如果您的类型有一个
Num
实例,您将免费获得
x^b
,因为
(^)
是为具有
Num
实例的任何类型定义的。(它基本上只是调用了很多
*

请注意,
(^)
不是
Num
Integral
的成员;它只是一个独立函数,其类型受两个类的约束

(^):(数值a,整数b)=>a->b->a
x0^y0 | y0<0=错误,无跟踪“负指数”
|y0==0=1
|否则=f x0 y0
式中--f:x0^y0=x^y
f x y |偶y=f(x*x)(y`quot`2)
|y==1=x
|否则=g(x*x)(y`quot`2)x——见注释[y-1的一半]
--g:x0^y0=(x^y)*z
g x y z |偶y=g(x*x)(y`quot`2)z
|y==1=x*z
|否则=g(x*x)(y`quot`2)(x*z)——见注释[y-1的一半]

x0
是您的
MyData
值;
(^)
x0
所做的唯一一件事就是将其自身相乘(因为它被作为
x
参数传递给
f
g
),所以从技术上讲,
(^)
只要定义了
(*)
Num
实例中。

积分
约束与
Num
约束无关。如果为
MyData
定义一个
Num
实例,那么只要
b
是整数,就可以编写
x^b
(^)
将使用您的
Num
实例,而不是相反。您的类型实际上是数字类型,还是您只想将
(x^y)
作为编写“do
x
y
时间”的简短方式?如果是前者,您应该实现Num的所有功能,而不仅仅是一个功能,如果是后者,您应该使用除
(^)
之外的其他功能。例如,半群上诉,如果你想要一个像
stimes
这样的效果。如果你想使用
MyData
作为指数,那么你还需要为
MyData
定义一个
整数
实例。你不需要定义
(^)
;只要您有
MyData
Num
实例,您就可以免费获得它。此外,您的错误消息(类“Y”中没有成员“x”)似乎来自Hugs。你可能想考虑切换到GHC。拥抱真的很老了(自从上次官方发布以来已经十年多了),获得帮助是很困难的。非常感谢!它起作用了。不幸的是,这是绝对不明显的:(我认为正确的方法是一些bonecrushing实例语法变体
(^) :: (Num a, Integral b) => a -> b -> a
x0 ^ y0 | y0 < 0    = errorWithoutStackTrace "Negative exponent"
        | y0 == 0   = 1
        | otherwise = f x0 y0
    where -- f : x0 ^ y0 = x ^ y
          f x y | even y    = f (x * x) (y `quot` 2)
                | y == 1    = x
                | otherwise = g (x * x) (y `quot` 2) x         -- See Note [Half of y - 1]
          -- g : x0 ^ y0 = (x ^ y) * z
          g x y z | even y = g (x * x) (y `quot` 2) z
                  | y == 1 = x * z
                  | otherwise = g (x * x) (y `quot` 2) (x * z) -- See Note [Half of y - 1]