Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 应为类型,但具有种类‘;*-&燃气轮机;约束’;_Haskell - Fatal编程技术网

Haskell 应为类型,但具有种类‘;*-&燃气轮机;约束’;

Haskell 应为类型,但具有种类‘;*-&燃气轮机;约束’;,haskell,Haskell,我正在写一个加减数字的计算器。这里我有两个抽象,一个是Expr,它被建模为一个树,另一个是typeclass操作数,它包含树的左右节点。操作数有一个函数组合,用于将函数应用于左右节点: module Data.Calculator where class Operand a where combine :: a -> a data Operator = Plus | Minus data Expr = Node Operator Operand Operand | Value

我正在写一个加减数字的计算器。这里我有两个抽象,一个是
Expr
,它被建模为一个树,另一个是typeclass
操作数
,它包含树的左右节点。操作数有一个函数
组合
,用于将函数应用于左右节点:

module Data.Calculator where

class Operand a where
    combine :: a -> a

data Operator = Plus | Minus
data Expr = Node Operator Operand Operand | Value Integer

instance Operand Expr where
    combine (Node op left right) =
        case op of 
            Plus -> (combine left) + (combine right)
            Minus -> (combine left) - (combine right)
    combine (Value a) = (Value a)

instance Num Expr where
    (+) (Value left) (Value right) = Value (left + right)
    (*) (Value left) (Value right) = Value (left * right)
    abs (Value a) = Value (abs a)
    fromInteger i = Value i
    negate (Value a) = Value (negate a)
当我试图编译它时,我得到了错误

calculator/src/Data/Calculator.hs:7:35: error:

    • Expecting one more argument to ‘Operand’
      Expected a type, but ‘Operand’ has kind ‘* -> Constraint’
    • In the type ‘Operand’
      In the definition of data constructor ‘Node’
      In the data declaration for ‘Expr’
  |
  | data Expr = Node Operator Operand Operand | Value Integer

这是什么意思?我知道这个问题可以在不将操作数定义为typeclass的情况下解决,但我想使用
操作数
typeclass,因为这是我现在正在学习的主题。我做错了什么?

在代码中,操作数不是类型,而是类型的类。不能有
操作数
类型的值,因为它不是数据类型。因此,不能将其用作
Expr
定义的一部分

隐式符号
*->约束
意味着标识符
操作数
,如果应用于类型(表示为
*
),将给您一个
约束
。编译器说它在该上下文中需要一个类型(例如
Int
String
可能是Float
,等等),但您给了它
操作数
,它具有种类
*->约束

从您的代码中,我猜您实际上想做的是构造
Expr
,使其可以包含任何类型的值,只要这些类型具有
操作数的实例。这是正确的假设吗

如果是这样,那么方法是将这些值包装为存在类型:

data SomeOperand = forall a. Operand a => SomeOperand a
或GADT符号中的相同内容:

data SomeOperand where
    SomeOperand :: forall a. Operand a => a -> SomeOperand
这些符号字面上表示类型
SomeOperand
只包含一个值
a
,该值必须具有
操作数的实例

现在,您可以在
Expr
的定义中使用
SomeOperand

data Expr = Node Operator SomeOperand SomeOperand | Value Integer
现在,当在
Expr
上进行匹配时,您将获得一个具有
操作数实例的值,因此您将能够对其应用
合并

f :: Expr -> Expr
f (Node op (SomeOperand a) (SomeOperand b)) = Expr op (combine a) (combine b)
f (Value i) = Value i
请注意,除了将这些操作数转换为同一类型的其他值之外,您实际上无法使用这些操作数执行任何操作,这同样让您无所事事。为了使其在任何方面都有用,类
操作数
必须有一些方法来转换为类型本身以外的内容,例如:

class Operand a where
    combine :: a -> a
    showOperand :: a -> String
现在我可以使用
showOperator
来达到一个有用的目的:

showExpr :: Expr -> Expr
showExpr (Node op (SomeOperand a) (SomeOperand b)) = showOperand a ++ show op ++ showOperand b
showExpr (Value i) = show i

需要为“Operand”增加一个参数,而“Operand”需要一个类型,但“Operand”具有种类“*->”约束“
请参阅EditsWakly realted:您定义了一个typeclass
Operand
。对于两种不同类型的
T1、T2
,您是否希望至少有两个实例
实例操作数T1
实例操作数T2
?如果您认为您将只使用
操作数Expr
,这表明您不应该使用类型类,而只需定义
combine::Expr->Expr
。你想实现什么?我怀疑你在考虑面向对象编程,将
combine
作为基类
Operand
Expr
继承自
Operand
的成员函数。类型类与OO类不同——特别是,它们不是类型。