3

So i'm having problems with some variable types.

getOrdenado :: (String,Int,String,Int,Int) -> Int
getOrdenado (_,_,_,a,_) = a 

listaOrdenado :: [(String,Int,String,Int,Int)] -> [Int]
listaOrdenado xs = map getOrdenado xs

getOrdenado takes a certain Int value from a tuple contained in a list of tuples and listaOrdenado makes a list of all of thoose specific Int's.

This function is supposed to work on the following list:

firma = [("Ana", 30, "RH", 1500, 3), ("Rui", 40, "Vendas", 1000, 2),
        ("Luis", 45, "RH", 3333, 5), ("Maria", 55, "Admin", 2000, 4)]

But whenever i try running listaOrdenado with this list i get the following error

Couldn't match type `Integer' with `Int'
Expected type: [(String, Int, String, Int, Int)]
  Actual type: [([Char], Integer, [Char], Integer, Integer)]
In the first argument of `listaOrdenado', namely `firma'
In the expression: listaOrdenado firma
In an equation for `it': it = listaOrdenado firma

I am not allowed to use Integer in the class signature, only Int so i have no clue on how to solve this, nor do i have any clue why it says that those values in firma are Integer's

eXistanCe
  • 735
  • 1
  • 9
  • 25
  • You can force `Int` as the type by putting inline types like `30 :: Int`, or give `firma` a type signature so that it uses `Int` instead of `Integer` (`Integer` is the default) – cronburg Oct 29 '15 at 18:35
  • 1
    Try putting `firma :: [(String, Int, String, Int, Int)]` before the declaration for `firma`. If you're defining this in GHCi, then put it in a file instead. – bheklilr Oct 29 '15 at 18:35
  • I'm not allowed to give any signature to **firma** , more specifically i'm not allowed to alter anything about **firma** – eXistanCe Oct 29 '15 at 18:37
  • Then wherever you *use* `firma` in your code, reference it like this: `(firma :: [(String, Int, String, Int, Int)])` – cronburg Oct 29 '15 at 18:38
  • So i should add this line to my code: – eXistanCe Oct 29 '15 at 18:40
  • You have to put the type signature somewhere, but if you can't change `firma` you can just call `listaOrdenado` in `ghci` like this: `λ> listaOrdenado (firma :: [(String, Int, String, Int, Int)])` – cronburg Oct 29 '15 at 18:43
  • Firma is not defined in my .hs file since its and hypothetical list to test the functions, if I simply add that firma signature to my .hs file won't ghci complain? – eXistanCe Oct 29 '15 at 18:50

2 Answers2

5

Since the problem is not solved yet, I edited my answer to be more precise:

If you have top level definitions in your Haskell module, Haskell will infer a monomorphic type and not a polymorphic. The reason is very simple. Haskell assumes that a top level definition is used quite often and if an expression has a monomorphic type, it has to be evaluated just ones. In your case, Haskell tries to find the best fitting monomorphic type for the numbers in your tuple. By specification/implementation Haskell tries first the type Integer and then the type Float. This is the reason why you have the type error in your code.

Now you have several options to solve this problem:

1.Add the type of firma in your module (preferred solution):

module Test where

getOrdenado :: (String,Int,String,Int,Int) -> Int
getOrdenado (_,_,_,a,_) = a 

listaOrdenado :: [(String,Int,String,Int,Int)] -> [Int]
listaOrdenado xs = map getOrdenado xs

firma :: Num a => [(String,a,String,a,a)]
firma = [("Ana", 30, "RH", 1500, 3), ("Rui", 40, "Vendas", 1000, 2),
        ("Luis", 45, "RH", 3333, 5), ("Maria", 55, "Admin", 2000, 4)]

If you call listaOrdenado firma, it works just fine for me.

2.The second possibility is to turn off monomorphic type inference by overwriting the used defaults. How this is done is explained in this wiki entry: https://wiki.haskell.org/Monomorphism_restriction

3.The last, but quite expensive, solution in my mind is to manually cast the elements of your list to the preferred type.

Christoph W.
  • 958
  • 2
  • 10
  • 24
  • Annotating at the use site will only move the type error. – dfeuer Oct 29 '15 at 19:30
  • After adding this line to my code: firma :: Num a, Num b, Num c => [(String, a, String, b, c)] i get the following error when trying to load my .hs file onto ghci: .hs:1:15: parse error on input `,' caracter 15 being the first , after **a** – eXistanCe Oct 29 '15 at 19:51
  • sorry this was a copy paste error, I updated my answer. – Christoph W. Oct 29 '15 at 19:55
  • The parse error is gone but now it gives another error regarding the lack of an accompanying binding: The type signature for `firma' lacks an accompanying binding – eXistanCe Oct 29 '15 at 22:43
  • Can you explain how you use firma? Did you try to manually cast it and then you get this error? – Christoph W. Oct 30 '15 at 10:02
3

If you can change the signature of firma, just add the appropriate type signature to it:

firma :: [(String, Int, String, Int, Int)]
firma = [("Ana", 30, "RH", 1500, 3), ("Rui", 40, "Vendas", 1000, 2),
        ("Luis", 45, "RH", 3333, 5), ("Maria", 55, "Admin", 2000, 4)]

If not allowed to change firma, you can call listaOrdenado by giving firma a specific type signature on the ghci prompt:

$ ghci firma.hs
λ> listaOrdenado (firma :: [(String, Int, String, Int, Int)])

If firma actually has a type signature with Integer used, then you need to cast from Integer to Int using fromIntegral in some manner like this:

fI = fromIntegral
integerToInt [] = []
integerToInt ((a,b,c,d,e):xs) = (a, fI b, c, fI d, fI e) : (integerToInt xs)

and then invoke listaOrdenado like this in ghci:

$ ghci firma.hs
λ> listaOrdenado (integerToInt firma)
cronburg
  • 892
  • 1
  • 8
  • 24
  • The thing is firma is a list that's going to be used to test my code, firma may have more tuples than the ones I was provided with, the only firm thing are the types of the variables inside the tuples. So I can't like put a version of firma in my . Hs file nor can I add the specification when calling it for the ghci since I will not be the one calling her when avaluating the functions. and I do belive firma doesn't have a signature or at least I am not provided with it – eXistanCe Oct 29 '15 at 19:19
  • If you're not the one calling `listaOrdenado` and you're not allowed to use `Integer` or `Num` in the type signature, then you can just assume whoever uses your code will pass in the right type because the onus is on the caller to provide the correct types because Haskell is strongly typed. – cronburg Oct 30 '15 at 15:28