已定义函数

时间:2016-08-22 13:07:52

标签: haskell

我正在尝试实现一个乘以多项式的函数(用列表表示 - 3x ^ 2 + 5x + 2 = P [2,5,3]):

newtype Poly a = P [a]

plus :: Num a => Poly a -> Poly a -> Poly a
plus (P a) (P b) = P (map (\(y,z) -> z + y) (zipWithPadding 0 a b))
    where
        zipWithPadding :: (Num a) => a -> [a] -> [a] -> [(a, a)]
        zipWithPadding e (aa: as) (bb: bs) = ((aa, bb): zipWithPadding e as bs)
        zipWithPadding e [] bs = zip (repeat e) bs
        zipWithPadding e as [] = zip as (repeat e)

times :: Num a => Poly a -> Poly a -> Poly a
times (P a) (P b) = sum $ multList 0 [] a b
    where
        multList :: Num a => Int -> [Poly a] -> [a] -> [a] -> [Poly a]
        multList _ s [] _ = s
        multList e s (aa:as) bs = multList (e + 1) (s ++ (multElement e aa bs)) as bs

        multElement :: Num a => Int -> a -> [a] -> [Poly a]
        multElement e aa bs = [P $ replicate e 0 ++ (map (*aa) bs)]


instance Num a => Num (Poly a) where
    (+) = plus
    (*) = times
    negate      = undefined
    fromInteger = undefined
    -- No meaningful definitions exist
    abs    = undefined
    signum = undefined

但是当我尝试运行时,我收到undefined错误:

*HW04> times (P [1,2,2]) (P [1,2])
*** Exception: Prelude.undefined

我很困惑。

3 个答案:

答案 0 :(得分:4)

显然,您正在调用Num实例中的undefined方法之一。

您可以使用以下定义确定调用哪一个:

negate      = error "Poly negate undefined"
fromInteger = error "Poly fromInteger undefined"
abs    = error "Poly abs undefined"
signum = error "Poly signum undefined"

运行测试表达式得到:

Poly *** Exception: Poly fromInteger undefined

问题在于您使用sum,其实质上定义为:

sum xs = foldl (+) 0 xs

因此正在呼叫fromInteger 0。您可以通过以下方式解决此问题:

fromInteger x = P [ fromInteger x ]

<强>更新

fromInteger Poly a需要以这种方式定义的原因是 因为我们需要构建Num a值列表,fromInteger x 是从整数值Num a创建x的方法。

答案 1 :(得分:2)

虽然存在环单态Num a => a -> Poly a,但多项式实际上不是Num。

弃掉Num实例并使用foldl plus代替sum

答案 2 :(得分:0)

我将采取的立场是,您不应该仅仅为了劫持类的功能而定义类的实例。 Num实例的最小定义需要定义某些函数;明确地将undefined分配给这些名称不符合定义。考虑Haskell为列表连接提供特定的运算符(++),而不是简单地使用像

这样的实例重载(+)
instance Num [a] where
    a + [] = a
    [] + b = b
    (a:as) + b = a:(as + b)
    (*) = undefined
    negate = undefined
    -- etc

相反,定义一个 提供所需操作的类。在这种情况下,您需要Ring,这是一种类型,以及遵循某些定律的两个操作,加法和乘法。 (简单地说,操作就像你想象的那样整数作为一个例子,除了乘法不需要是可交换的。)

在Haskell中,我们将类定义为

class Ring a where
    rplus :: a -> a -> a -- addition
    rmult :: a -> a -> a -- multiplication
    rnegate :: a -> a    -- negation
    runit :: a           -- multiplicative identity
    rzero :: a           -- additive identity, multiplicative zero

具有有效Num实例的任何值都会形成一个响铃,但您需要单独定义实例。

instance Ring Integer where
    rplus = (+)
    rmult = (*)
    rnegate = negate
    rzero = 0
    runit = 1

instance Ring Float
    rplus = (+)
    rmult = (*)
    rnegate = negate
    rzero = 0
    runit = 1

-- etc

您可以为多项式定义Ring的实例,只要系数也形成一个环。

newtype Poly a = P [a]

instance Ring a => Ring (Poly a) where
    -- Take care to handle polynomials with different degree
    -- Note the use of rplus and rzero instead of (+) and 0
    -- when dealing with coefficients
    rplus (P a) (P b) = case (compare (length a) (length b)) of
                          LT -> rplus (P (rzero:a)) (P b)
                          EQ -> P $ zipWith rplus a b
                          GT -> rplus (P a) (P (rzero:b))



    -- I leave a correct implementation of rmult as an exercise
    -- for the reader.
    rmult = ...
    rnegate (P coeffs) = P $ map rnegate coeffs
    rzero = P [0]
    runit = P [1]