除了创建对列表执行简单操作的函数之外,我对haskell很新。我想创建一个列表,其中包含Int
类型的内容和Int -> Int -> Int
类型的函数。
以下是我的尝试:
data Token = Value Int | Operator (Int -> Int -> Int)
tokens :: [Token]
tokens = [12, (+)]
但是我收到以下错误
Couldn't match expected type `Token'
with actual type `Integer -> Integer -> Integer'
In the expression: (+)
In the expression: [12, (+)]
In an equation for `tokens': tokens = [12, (+)]
我不确定为什么这不起作用,有人能指出我正确的方向吗?
答案 0 :(得分:14)
您需要使用构造函数来获取类型Token
的值。例如,12
不属于Token
类型,类型为Int
(嗯,Num a => a
)。同样,(+)
不是令牌,而是函数Int -> Int -> Int
。请注意Token /= Int -> Int -> Int
。
幸运的是,您已经定义了一些构造函数,例如Value :: Int -> Token
和Operator :: (Int -> Int -> Int) -> Token
。所以使用我们得到的那些:
tokens :: [Token]
tokens = [Value 12, Operator (+)]
答案 1 :(得分:4)
正如托马斯所说,Int
或Int->Int->Int
值不能有类型Token
:每个Haskell值只有一个类型 1 ,没有这样的在Haskell中作为OO风格的子类型的东西。
然而,Haskell类型(而不仅仅是函数,但任何东西!)可能是多态的。实际上,数字文字是多态的:
前奏> :t 12
12 :: Num a =>一个
这意味着,如果Token
是Num
类型,那么12
实际上将是一个正确的值(它不会有Int
类型,但Token
1}}马上!)为此,您可以编写
instance Num Token where
fromInteger = Token . fromInteger
严格地说,你应该为Token
实现加法,绝对值等,这不会很好。此外,(+)
在[Token]
中仍然无效。但你可以写
tokens = [12, Operator(+)]
事实上,如果这应该是一个非常长的列表并且你想保持代码简短,那么你可以采用一种相当讨厌的技巧,它可以让你完全按照原来的方式编写它:
mkToken :: TokenRep -> Token
mkToken f = f undefined undefined
type TokenRep = Token->Token->Token
instance Num Token where
_ + _ = Operator (+)
_ - _ = Operator (-)
_ * _ = Operator (*)
instance Num TokenRep where -- You need `-XFlexibleInstances` here
fromInteger n _ _ = Value $ fromInteger n
然后
tokens = map mkToken [12, (+)] -- Note that `12` has type `Token->Token->Token` here!
但实际上,这将是一个非常糟糕的黑客。
1 但是,单个类型可能有多个名称:[Char]
和String
实际上属于同一类型,后者是刚刚定义为同义词type String = [Char]
。 OTOH,data
或newtype
您总是定义 new (duh),因此会分开类型。