简体   繁体   中英

Creating a list of Ints and functions Int -> Int -> Int

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM