Apart from creating functions that do simple things to lists, I'm pretty new to haskell. I would like to create a list which contains things of type Int
, and functions of type Int -> Int -> Int
.
Here is what I have tried:
data Token = Value Int | Operator (Int -> Int -> Int)
tokens :: [Token]
tokens = [12, (+)]
but I get the following error
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, (+)]
I'm not sure why this doesn't work, can anyone point me in the right direction?
You need to use your constructors to obtain values of type Token
. For example, 12
is not of type Token
, it is of type Int
(well, Num a => a
). Similarly, (+)
is not a token but a function Int -> Int -> Int
. Notice that Token /= Int -> Int -> Int
.
Fortunately you have defined a few constructors such as Value :: Int -> Token
and Operator :: (Int -> Int -> Int) -> Token
. So using those we get:
tokens :: [Token]
tokens = [Value 12, Operator (+)]
As said by Thomas, an Int
or Int->Int->Int
value can not have type Token
: every Haskell value has precisely one type 1 , there's no such thing as OO-style subtyping in Haskell.
However, Haskell types (and not just functions, but anything!) may be polymorphic. And indeed, number literals are polymorphic:
Prelude> :t 12
12 :: Num a => a
That means, if Token
is a Num
type, then 12
will actually be a correct value (it wouldn't have type Int
then, but Token
right away!). To achieve that, you can write
instance Num Token where
fromInteger = Token . fromInteger
Strictly speaking, you should then also implement addition, absolute-value etc. for Token
, which wouldn't come out very nice. Also, (+)
would still not be valid in a [Token]
. But you could write
tokens = [12, Operator(+)]
In fact, if this is supposed to be a very long list and you want to keep the code short, you could resort to a rather nasty trick that would allow you to write it exactly as you had originally:
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
and then
tokens = map mkToken [12, (+)] -- Note that `12` has type `Token->Token->Token` here!
But really, this would be quite a horrible hack.
1 A single type may have more than one name though: [Char]
and String
are actually the very same type , the latter is just defined as a synonym type String = [Char]
. OTOH, with data
or newtype
you're always defining a new (duh) and thus separate type.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.