I started learning Haskell following the recommandations in this answer. So I am just implementing easy list functions, and I stumble onto a difference in the compiler behavior I cannot explain to myself :
-- Impl 1
elementAt :: (Integral b) => [a] -> b -> a
elementAt xs id = xs !! (fromIntegral(id-1))
-- Impl 2
elementAt' :: (Num b) => [a] -> b -> a
elementAt' xs id = xs !! (id-1)
With following signatures :
fromIntegral :: (Integral a, Num b) => a -> b
(!!) :: [a] -> Int -> a
I get an error only for the second implementation, elementAt'
.
Could not deduce (b ~ Int)
from the context (Num b)
If I understand correctly, it means that the operator (!!) is expecting an Int instance as its second argument (as seen from the signature), but we only guarantee that the provided parameter is conforming to the Num typeclass (inferred from elemenAt'
signature), which is wider than Int.
With that in mind, I do not understand why the first implementation actually works, knowing that fromIntegral
also returns an value that is only conforming to the Num typeclass.
id
is not a great variable name, being already a standard identifier for the identity function. There's nothing wrong with justi
. – leftaroundaboutNum a
value, what it's really saying is that "WhateverNum a
type you need from me, I can provide it." When a function takes aNum a
value as an argument, really it's saying, "You can give me anyNum a
value and in the most difficult of situations I will know what to do to work it all out." That means that when you take aNum a
argument, it is your responsibility to work it out. When you call a function that returns aNum a
value, it is its responsibility to work it out. – kqrNum a
that could actually return something different depending on the calling context), is what confused me, probably because of my C and C++ background. It has something "templates with return type deduction" to it ! – Ad N