Haskell类的误解

时间:2015-06-10 19:40:55

标签: haskell

您好我需要创建一个包含名为prize'的方法的类,该方法计算一些分数。我想要实例以防我得到Order,稍后我将再次实例以防我得到[Order],这是代码:

class Ped a where
    prize' :: Fractional b => a -> b

instance (Integral n, Fractional p) => Ped (Order n p) where
    prize' x = prizeOrder x

data (Integral c,Fractional p) => Product c p
    = Prod c String p
    deriving (Show, Read) 

data (Integral n, Fractional p) => Order n p
    = PdMult (Product n p) n
    | PdUnit (Product n p)
    deriving (Show, Eq)

prize :: (Fractional p, Integral c) =>(Product c p) -> p
prize (Prod _ _ x) = x

prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p
prizeOrder (PdMult p n) = (prize p) * (fromIntegral n)
prizeOrder (PdUnit p) = prize p

Prelude说:

Could not deduce (p ~ b)
from the context (Integral n, Fractional p)
bound by the instance declaration
at src\Funciones.hs:6:10-55
or from (Fractional b)
bound by the type signature for
     prize' :: Fractional b => Order n p -> b
at src\Funciones.hs:7:5-11
`p' is a rigid type variable bound by
  the instance declaration
  at src\Funciones.hs:6:10
`b' is a rigid type variable bound by
  the type signature for prize' :: Fractional b => Order n p -> b
  at src\Funciones.hs:7:5
Expected type: Order b
  Actual type: Order n p
Relevant bindings include
  x :: Order n p
    (bound at src\Funciones.hs:7:13)
  prize' :: Order n p -> b
    (bound at src\Funciones.hs:7:5)
In the first argument of `prizeOrder', namely `x'
In the expression: prizeOrder x

1 个答案:

答案 0 :(得分:1)

问题在于,class定义提供了额外的自由度,而您的instance无法提供。在你的班上你说:

class Ped a where
    prize' :: Fractional b => a -> b

这意味着程序员可以为他/她想要的Fraction b选择b

现在,如果我们查看您的实例:

instance (Integral n, Fractional p) => Ped (Order n p) where
    prize' x = prizeOrder x

在此您说prize'取决于prizeOrder。然而,prizeOrder函数具有签名:

prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p

这意味着您根本无法选择b。如果我将prize'与预期的返回类型Float一起使用,那么Ped会接受,Order Double Int会接受。

您可以使用多参数类“解决”这个问题,您可以使用b签名中的class

class Ped a b where
    prize' :: a -> b

接下来,您需要使用第二个类型参数定义实例,以确保输出为p

instance (Integral n, Fractional p) => Ped (Order n p) p where
    prize' x = prizeOrder x

您需要激活一些额外的 GHC 功能,完整代码如下:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DatatypeContexts #-}

class Ped a b where
    prize' :: a -> b

instance (Integral n, Fractional p) => Ped (Order n p) p where
    prize' x = prizeOrder x

data (Integral c,Fractional p) => Product c p
    = Prod c String p
    deriving (Show, Read) 

data (Integral n, Fractional p) => Order n p
    = PdMult (Product n p) n
    | PdUnit (Product n p)
    deriving (Show)

prize :: (Fractional p, Integral c) =>(Product c p) -> p
prize (Prod _ _ x) = x

prizeOrder :: (Fractional p, Integral c) => (Order c p) -> p
prizeOrder (PdMult p n) = (prize p) * (fromIntegral n)
prizeOrder (PdUnit p) = prize p

但正如@bheklilr所说,不要在数据类型上使用“类约束”。此外,有人最好问自己,使用class是否有用。