这里提供一种与我之前发布的另一种解决方案不同的备选方案。
你似乎想为多项式创建一个ADT,而我会使用Map,但我们可以使用术语列表。首先导入一些内容:
import Data.Function (on)
import Data.List (sortBy, groupBy, foldl1')
在这种情况下,多项式是一个项的列表,按最高幂排序,而每个项都表示为 aX^n,用 X a n
表示。
newtype Poly a n = Poly {terms :: [Term a n]} deriving (Show)
data Term a n = X {coeff :: a, power :: n} deriving (Eq,Show)
让我们制作一些简单的多项式:
zero = Poly []
x = Poly [X 1 1]
constant :: (Num a,Eq a,Num n) => a -> Poly a n
constant 0 = zero
constant a = Poly [X a 0]
一旦我们定义了Num实例,就可以通过写3*x^4
来创建X 3 4
。
对于多项式的标准操作是使用特定的x值进行求值。
subst :: (Num a, Integral n) => a -> Term a n -> a
subst x (X a n) = a * x ^ n
evalAt :: (Num a, Integral n) => a -> Poly a n -> a
evalAt x = sum . map (subst x) . terms
我希望能够映射系数,但我不想将其作为Functor的实例,因为这是一个经典的学生错误,会逐项应用操作,例如平方、三角函数或对数函数,或者取平方根,而实际上只有极少数事物,如标量乘法、微分和积分才能像这样工作。提供fmap会鼓励您做错误的事情,例如而不是(+ (constant 1))
。
mapCoeffs :: (a -> b) -> Poly a n -> Poly b n
mapCoeffs f = Poly . map f' . terms
where f' (X a n) = X (f a) n
我们需要进行项的加法和乘法,并将同类项合并。当我们将同类项合并时,按幂的逆序排序并省略系数为零的项。
addTerm (X a n) (X b m) | n == m = X (a+b) n
| otherwise = error "addTerm: mismatched powers"
multTerm (X a n) (X b m) = X (a*b) (n+m)
collectLikeTerms :: (Num a, Ord n, Eq a) => Poly a n -> Poly a n
collectLikeTerms = Poly . filter ((/= 0).coeff)
. map (foldl1' addTerm)
. groupBy ((==) `on` power)
. sortBy (flip compare `on` power)
. terms
现在我们可以创建实例:
instance (Eq a,Num a,Ord n,Num n) => Eq (Poly a n) where
f == g = f - g == zero
instance (Eq a,Num a,Num n,Ord n) => Num (Poly a n) where
fromInteger = constant . fromInteger
signum (Poly []) = zero
signum (Poly (t:_)) = constant . signum . coeff $ t
abs = mapCoeffs abs
negate = mapCoeffs negate
(+) = (collectLikeTerms.) . (Poly.) . ((++) `on` terms)
(Poly ts) * (Poly ts') = collectLikeTerms $ Poly [multTerm t t' | t<-ts, t'<-ts']
实战应用:
ghci> 5*x^2 + 6*x^7 + 2
Poly {terms = [X {coeff = 6, power = 7},X {coeff = 5, power = 2},X {coeff = 2, power = 0}]}
data Poly = Const Int | Var Char | Add Poly Poly | Mult Poly Poly | Pow Poly Poly
。只需为每个所需操作添加一个新构造函数。 - bheklilrPoly
)和它的构造器(Const
,Add
,Int
)搞混了;Const 1
用来构造一个Poly
;而Poly 1
则不行。 - dafPow Int
吗? - Aserianx^2 + 2x^7 = [(1, 2), (2, 7)] :: [(系数,指数)]
。 - Noon Silk