Creating a list of Ints and functions Int & # 8594; Int & # 8594; Int

Besides creating functions that do simple things on lists, I'm pretty new to haskell. I would like to create a list containing elements of type Int and functions of type Int -> Int -> Int .

Here is what I 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 is not working, can someone point me in the right direction?

+6
source share
2 answers

You need to use your constructors to get values ​​of type Token . For example, 12 not of type Token , it is of type Int (well, Num a => a ). Similarly, (+) not a token, but a function Int -> Int -> Int . Note that Token /= Int -> Int -> Int .

Fortunately, you have defined several constructors, such as Value :: Int -> Token and Operator :: (Int -> Int -> Int) -> Token . So, using the ones we get:

 tokens :: [Token] tokens = [Value 12, Operator (+)] 
+14
source

As Thomas said, the value of Int or Int->Int->Int cannot be of the Token type: each Haskell value has exactly one type 1 there is no such thing as subtyping the OO style in Haskell.

However, Haskell types (not just functions, but all!) Can be polymorphic. Indeed, numeric literals are polymorphic:

Prelude>: t 12
12 :: Num a => a

This means that if Token is a type of Num , then 12 will be actually the correct value (it will not be of type Int , and then Token right away!). For this you can write

 instance Num Token where fromInteger = Token . fromInteger 

Strictly speaking, then you should also implement add, absolute value, etc. for Token , which doesn’t work out very nicely. In addition, (+) is still not valid in [Token] . But you could write

 tokens = [12, Operator(+)] 

In fact, if this should be a very long list, and you want the code to be short, you could resort to a rather nasty trick that would allow you to write it exactly as you originally did:

 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 actually it would be a terrible hack.


1 One type can have more than one name: [Char] and String are actually the same type, the latter is simply defined as a synonym for type String = [Char] . OTOH, with data or newtype you always define a new (duh) and therefore a separate type.

+4
source

Source: https://habr.com/ru/post/973470/


All Articles