另一种方法是定义一个Field 类型类:
class Field a where
rplus :: a -> a -> a
rmult :: a -> a -> a
rnegate :: a -> a
rinverse :: a -> a
runit :: a
rzero :: a
对于每个字段,定义一个表示该字段基础集的类型,然后为该类型定义一个适当的实例。您有责任确保您的实现遵守各种场定律(乘法分布在加法之上,任何元素乘以它的倒数为 1,等等)。
请参阅最后一个示例,了解如何为字段上的多项式定义 Field 实例。
示例
整数模 7
-- Haskell doesn't have dependent types yet, so use the
-- next best thing: a smart constructor
newtype Z7 = Z7 Integer
makeZ7 :: Integer -> Z7
makeZ7 x = Z7 $ (x `mod` 7)
instance Field Z7 where
rplus (Z7 a) (Z7 b) = makeZ7 (a + b)
rmult (Z7 a) (Z7 b) = makeZ7 (a * b)
rzero = makeZ7 0
runit = makeZ7 1
rnegate (Z7 a) = makeZ7 (7 - a)
-- Necessarily partial, since 0 doesn't have an inverse
rinverse (Z7 a) | a == 1 = makeZ7 1
| a == 2 = makeZ7 4
| a == 3 = makeZ7 5
| a == 4 = makeZ7 2
| a == 5 = makeZ7 3
| a == 6 = makeZ7 6
理性
这个比较简单,因为Integral a => Ratio a 已经是Num 的一个实例,所以我们可以免费获得大部分实现。
import Data.Ratio
instance Integeral a => Field (Ratio a) where
rplus = (+)
rmult = (*)
rnegate = negate
rinverse q = denominator q % numerator q
rzero = 0
runit = 1
域上的多项式
多项式的系数可以是任何你想要的。
data Poly f = Poly [(f, Int)]
但是,多项式仅在系数本身来自某个域时才形成一个域,因此您可以在此处声明该约束。
-- A type Poly f is a field if f is a field.
-- Fields: Poly Z7, Integral a => Poly (Ratio a)
-- Not a field: Poly Integer
instance Field f => Field (Poly f) where
runit = Poly [(runit, 0)] -- Not Poly [(1,0)]
rzero = Poly [(rzero, 0)] -- Not Poly [(0,0)]
-- Not Poly [(-c, e) | (c,e) <- p]
rnegate (Poly p) = Poly [(rnegate c, e) | (c,e) <- p]
-- Left as an exercise for the reader
-- Remember to use runit instead of 1, rzero instead of 0
-- and rnegate instead of - where appropriate.
rinverse p = ...
rplus p q = ...
rmult p q = ...
一些非常简单的示例不需要我完成Poly 实例的实现。 (您可以为所有涉及的类型派生Show。)
> runit :: Z7
Z7 1
> runit :: Rational -- type Rational = Ratio Integer
1 % 1
> runit :: Poly Z7
Poly [(Z7 1,0)]
> runit :: Poly Rational
Poly [(1 % 1,0)]