Polymorphism with list comprehension in Haskell

Asked

Viewed 81 times

3

I have these two functions:

sequenciaInt :: Int -> Int -> [Int]
sequenciaInt i j |j >= i = [i..j]
                 |otherwise = sequenciaInt j i

sequenciaChar :: Char -> Char -> [Char]
sequenciaChar i j |j >= i = [i..j]
                  |otherwise = sequenciaChar j i

A function returns a list of Int and the other a list of Char.

It is possible to have a generic function that returns a list of Int or Char depending on the parameter passed (i.e. Int or Char)?

Something like:

sequencia :: a -> a -> [a]
sequencia i j |j >= i = [i..j]
              |otherwise = sequencia j i

However, this above code returns error:

main.hs:2:16: error:
    • No instance for (Ord a) arising from a use of ‘>=’
      Possible fix:
        add (Ord a) to the context of
          the type signature for:
            sequencia :: forall a. a -> a -> [a]
    • In the expression: j >= i
      In a stmt of a pattern guard for
                     an equation for ‘sequencia’:
        j >= i
      In an equation for ‘sequencia’:
          sequencia i j
            | j >= i = [i .. j]
            | otherwise = sequencia j i
  |
2 | sequencia i j |j >= i = [i..j]
  |                ^^^^^^
main.hs:2:25: error:
    • No instance for (Enum a)
        arising from the arithmetic sequence ‘i .. j’
      Possible fix:
        add (Enum a) to the context of
          the type signature for:
            sequencia :: forall a. a -> a -> [a]
    • In the expression: [i .. j]
      In an equation for ‘sequencia’:
          sequencia i j
            | j >= i = [i .. j]
            | otherwise = sequencia j i
  |
2 | sequencia i j |j >= i = [i..j]
  |                         ^^^^^^

1 answer

1


Yes, it is possible and its function is almost correct.

Its implementation of sequencia uses the operator >= and the syntactic sugar [i..j]. In case you don’t know, syntactic sugar is a syntax of the language itself that allows you to write some expression in a more readable way. In this case, the expression [i..j] is replaced by, or unassuming for enumFromTo i j before the program is compiled. Therefore, sequencia requires the type a of entry belonging to the class Ord so that it can be used >=, and to the class Enum why enumFromTo be available.

As you stated sequencia :: a -> a -> [a] without requiring specific classes, the compiler complains that not all a is possible, saying that there is no guarantee that a be it Ord (first mistake) nor Enum (second mistake).

There are two solutions:

  1. Rewrite function type signature including class restrictions, i.e., sequencia :: (Ord a, Enum a) => a -> a -> [a], or

  2. Remove the signature completely and let the compiler infer the type correctly.

Test on Ghci and see that he will not complain anymore. The Wikibook by Haskell (in English) may help you understand class constraints.

  • Thank you so much, solved the error of my code. I am beginner in Haskell, your explanation and link are useful.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.