Reputation: 889
I've got three functions
boombangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs odd x]
length' xs = sum [1 | _ <- xs]
removeNonUppercase st = [x | x <- st, x `elem` ['A'..'Z']]
Here's what I get for the type(type signature?) of each function
*Main> :t boombangs
boombangs :: Integral a => [a] -> [[Char]]
*Main> :t length'
length' :: Num a => [t] -> a
*Main> :t removeNonUppercase
removeNonUppercase :: [Char] -> [Char]
Haskell should give me an error when I pass an array of ints to removeNonUppercase or a string to boombangs. It does too, but how does it know it's wrong when I haven't specified the type anywhere.
Also why are the types of boombangs and removeNonUppercase different even though they work on the same input.
I apologize if the question seems vague or downright ignorant. I've just started on Learn You a Haskell and I'm slowly wrapping my head around this paradigm coming from programming mainly in C and python.
Any resources for learning more about haskell and the type system would also be appreciated.
Upvotes: 0
Views: 286
Reputation: 15121
how does it know it's wrong when I haven't specified the type anywhere.
Haskell compiler, GHC in your case, can do type inference, which means it can figure out (almost always) what the type of an expression by context information. For example, for
mbangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs, odd x]
you could infer its type manually like this:
You define mbangs
by list comprehension, so xs
must be a list, and
you apply odd
on the element of xs
, therefore the type of xs
must be (Integral a) => [a]
, because the type of odd
is (Integral a) => a -> Bool
.
Also, for each element of xs
, you generate a String
by your output function if x < 10 then "BOOM" else "BANG"
,
therefore the type of mbangs
must be Integral a => [a] -> [[Char]]
, as ghci
just told you.
why are the types of boombangs and removeNonUppercase different even though they work on the same input.
Because you are using different output function in their list comprehension definitions.
Upvotes: 2
Reputation: 54058
GHC uses type inference to try to guess what type your function can be.
In boombangs
, it can tell that you're passing in a list because of the x <- xs
in the list comprehension, and it can tell that the list elements must have type Integral a => a
because you're applying odd
to each element. It knows you're returning a list of String
s because of the literal "BOOM"
and "BANG"
inside the list comprehension.
In length'
, your type is only constrained by sum
, which requires Num a => [a]
. Your input type is a list of any type because you don't actually perform any operations on the elements themselves, but you do indicate that the parameter is a list by the _ <- xs
.
In removeNonUpperCase
, it sees that you're passing in a list for the same reasons as the first two functions, and since you're checking if each element is in the list ['A'..'Z']
, so each element must be a Char
, so you're taking a list of Char
s and returning a list of Char
s, since no other transformation is performed on the elements. Since String
is just an alias for [Char]
, it knows the type fully.
Upvotes: 5
Reputation: 49803
For boombangs
, it can see by the operators you apply to x that it can't be a string. For removeNonUpperCase
, it can see that the elements have to be in ['A'..'Z']
, and so can't be ints. Which also explains why they DON'T work on the same input.
Upvotes: 0