我想在Haskell中建模field。字段是一组元素加上两个操作,可以看作乘法和加法。我进行如下:
data Field a = Field [a] (a -> a -> a) (a -> a -> a)
elements :: Field a -> [a]
elements (Field els _ _) = els
add :: Field a -> a -> a -> a
add (Field _ addop _) = addop
mul :: Field a -> a -> a -> a
mul (Field _ _ mulop) = mulop
但是,我现在想在字段上建模多项式,例如
data Poly = Poly f [(a, Int)]
其中f
应为字段,a
应为字段的类型。列表[(a, Int)]
表示多项式,例如
[(4, 2), (1, 1)] = 4 * x^2 + 1 * x^1
但我想不出如何在Haskell中实现这一目标。我想也许某种程度上我可以将Field
声明为一个类,然后以某种方式将Poly限制为仅使用Fields,但据我所知,我不能约束数据构造函数。
答案 0 :(得分:1)
另一种方法是定义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
实例,请参阅最后一个示例。
-- 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)]