Why does "take" change datatype in haskell? - haskell

I'm writing a function which takes elements from a list and returns them.
Pretty simple I thought. But when using "take" in for example: take 2 [1.2,3,4]
it returns: [1.2,3.0] when I actually want [1.2, 3]
I thought for creating a function that goes through the list and cuts unnecessary decimals but I can't get my head around it seeing haskell doesn't accept my comparison with x & round(x) in
function :: [a] -> [a]
function(x:xs)
if x == round(x) = round(x):function xs
else x:function xs
So A: Are there any simpler solutions?
B: Why can't haskell compare x with round(x)?

You say, "I actually want [1.2, 3] [and not [1.2, 3.0]]". I interpret this to mean that you want a list that contains Floats or the like for fractional numbers and Ints or the like for numbers without a fraction part.
You can't have this.
All lists in Haskell are homogeneous: every element has the same type.
There are some things you can do; for example, you can have tagged unions, the canonical example being Either. So
[Left 1.2, Right 3] :: [Either Double Integer]
would be fine; but you need to explicitly tag each element.
This is also more or less the answer to why x == round x doesn't work: the (==) operator takes two arguments of the same type; whereas typically round cannot return a value of the same type as its argument. You might like properFraction instead:
> properFraction 3
(3,0.0)
> properFraction 1.2
(1,0.19999999999999996)
You can check the second part of this to determine whether your number is a whole number or not (and when it is, the first part will be the result of round).

take does not change the type of list elements. Start up GHCi and follow along. My prompt is >>>.
>>> :t [1.2,3,4]
[1.2,3,4] :: Fractional t => [t]
This says the list elements have some Fractional type.
>>> :t [1.2,3.0,4.0]
[1.2,3.0,4.0] :: Fractional t => [t]
GHCi says the same thing here as well. What is going on?
>>> :t 2
2 :: Num t => t
>>> :t 2.0
2.0 :: Fractional t => t
A number literal without a decimal is inferred to have some Num type. A number literal with a decimal is inferred to have some Fractional type. For two elements to be in the same list, they must have the same type. What is the common type for 2 and 2.0?
>>> :t 2 `asTypeOf` 2.0
2 `asTypeOf` 2.0 :: Fractional a => a
All Fractional types are Num types, and so the common type for 2 and 2.0 is some Fractional type.
>>> [1.2,3,4]
[1.2,3.0,4.0]
We can see from the printing of the list that all the elements have been inferred as a Fractional type. This defaults to Double.
To remove unnecessary decimals from a list you will have to be more specific about what type you want this list to have. A list of Int has no decimals and a list of Double always has decimals. A single list cannot have both Int and Double typed elements.

Related

How does equality work for numeric types?

I see that Haskell allows different numeric types to be compared:
*Main> :t 3
3 :: Num t => t
*Main> :t 3.0
3.0 :: Fractional t => t
*Main> 3 == 3.0
True
Where is the source code for the Eq instance for numeric types? If I create a new type, such as ComplexNumber, can I extend == to work for it? (I might want complex numbers with no imaginary parts to be potentially equal to real numbers.)
“Haskell allows different numeric types to be compared” no it doesn't. What Haskell actually allows is different types to be defined by the same literals. In particular, you can do
Prelude> let a = 3.7 :: Double
Prelude> let b = 1 :: Double
Prelude> a + b
4.7
OTOH, if I declared these explicitly with conflicting types, the addition would fail:
Prelude> let a = 3.7 :: Double
Prelude> let b = 1 :: Int
Prelude> a + b
<interactive>:31:5:
Couldn't match expected type ‘Double’ with actual type ‘Int’
In the second argument of ‘(+)’, namely ‘b’
In the expression: a + b
Now, Double is not the most general possible type for either a or b. In fact all number literals are polymorphic, but before any operation (like equality comparison) happens, such a polymorphic type needs to be pinned down to a concrete monomorphic one. Like,
Prelude> (3.0 :: Double) == (3 :: Double)
True
Because ==, contrary to your premise, actually requires both sides to have the same type, you can omit the signature on either side without changing anything:
Prelude> 3.0 == (3 :: Double)
True
In fact, even without any type annotation, GHCi will still treat both sides as Double. This is because of type defaulting – in this particular case, Fractional is the strongest constraint on the shared number type, and for Fractional, the default type is Double. OTOH, if both sides had been integral literals, then GHCi would have chosen Integer. This can sometimes make a difference, for instance
Prelude> 10000000000000000 == 10000000000000001
False
but
Prelude> 10000000000000000 ==(10000000000000001 :: Double)
True
because in the latter case, the final 1 is lost in the floating-point error.
There is nothing magical going on here. 3 can be of either a real number or an integer, but its type gets unified with a real number when compared to 3.0.
Note the type class:
class Eq a where
eq :: a -> a -> Bool
So eq really does only compare things of same type. And your example 3 == 3.0 gets its types unified and becomes 3.0 == 3.0 internally.
I'm unsure of any type tricks to make it unify with a user defined complex number type. My gut tells me it can not be done.

converting list of type Integer to list of type Int

i'm trying to convert this list [1..20] from [Integer] to [Int]
map fromInteger [1..20]
however this still gives me a list of Integers
This on its own converts 2 which is Integer type to Int
fromInteger 2 :: Int
What's wrong
In Haskell, values can – just like functions – be polymorphic.
This idea is familiar to most programmers for the numerical operators: nobody finds it strange that 5 + 6 works, yielding and integer, just as fine as 3.14159 + 2.71828 works yielding a float. But in languages like C this is done pretty much ad-hoc, just because this special case is so handy. This brings a lot of problems with it, in particular when you write things like 1/12, which will carry out the / as integer-division, resulting in 0. Clearly not the intended thing when ou use it in something like
for (double hourWay = 0; hourWay<1; hourWay += 1/12)
double theta = hourWay * 2 * pi;
...
So programmers have to resort to ugly hacks like writing out the fraction in decimal, or explicitly making one of the numbers float (1.0 / 12.0, urgh!).
Haskell does this automatically for us: when it sees the result will be a double (that's explicitly written out in hourWays declaration) it makes no sense to start that calculation with integers, so it interprets 1 and 12 as floating-point right away. No problem with that since the integers certainly form a subset of the reals1. You can directly access this functionality by giving explicit type signatures:
Prelude> 4 :: Int
4
Prelude> 4 :: Double
4.0
Note that :: Double does not convert the number. 4 by itself does not have any particular type at all, it's polymorphic: whatever number type you want, 4 is a valid description; this is expressed in the type system by the signature
Prelude> :t 4
4 :: Num a => a
And in particular, this means
Prelude> :t [1..20]
[1..20] :: (Num t, Enum t) => [t]
is also polymorphic, which allows you to write
Prelude> [1..20] :: [Int]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
Prelude> [1..20] :: [Double]
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0]
Only when you don't give any signature, ghci will default to the "safest bet", which is Integer.
So in the case of [1..20] you don't need fromInteger at all. You would need it though if some elements weren't given directly as literals, but external constants / arguments of fixed type Integer.
Prelude> let x = 13 :: Integer
Prelude> :t [1..12]++[x]++[14..20]
[1..12]++[x]++[14..20] :: [Integer]
Prelude> map fromInteger ([1..12]++[x]++[14..20]) :: [Int]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
This works again with any numerical result type you request, because although x prevents [1..12]++[x]++[14..20] from being polymorphic, fromInteger re-introduces that.
Prelude> :t map fromInteger ([1..12]++[x]++[14..20]) :: [Int]
map fromInteger ([1..12]++[x]++[14..20]) :: Num b => [b]
1Which doesn't actually mean Double forms a subtype of Integer or even Int... it doesn't; but this becomes a problem only for big numbers.

Haskell Type Coercion

I trying to wrap my head around Haskell type coercion. Meaning, when does can one pass a value into a function without casting and how that works. Here is a specific example, but I am looking for a more general explanation I can use going forward to try and understand what is going on:
Prelude> 3 * 20 / 4
15.0
Prelude> let c = 20
Prelude> :t c
c :: Integer
Prelude> 3 * c / 4
<interactive>:94:7:
No instance for (Fractional Integer)
arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Integer)
In the expression: 3 * c / 4
In an equation for `it': it = 3 * c / 4
The type of (/) is Fractional a => a -> a -> a. So, I'm guessing that when I do "3 * 20" using literals, Haskell somehow assumes that the result of that expression is a Fractional. However, when a variable is used, it's type is predefined to be Integer based on the assignment.
My first question is how to fix this. Do I need to cast the expression or convert it somehow?
My second question is that this seems really weird to me that you can't do basic math without having to worry so much about int/float types. I mean there's an obvious way to convert automatically between these, why am I forced to think about this and deal with it? Am I doing something wrong to begin with?
I am basically looking for a way to easily write simple arithmetic expressions without having to worry about the neaty greaty details and keeping the code nice and clean. In most top-level languages the compiler works for me -- not the other way around.
If you just want the solution, look at the end.
You nearly answered your own question already. Literals in Haskell are overloaded:
Prelude> :t 3
3 :: Num a => a
Since (*) also has a Num constraint
Prelude> :t (*)
(*) :: Num a => a -> a -> a
this extends to the product:
Prelude> :t 3 * 20
3 * 20 :: Num a => a
So, depending on context, this can be specialized to be of type Int, Integer, Float, Double, Rational and more, as needed. In particular, as Fractional is a subclass of Num, it can be used without problems in a division, but then the constraint will become
stronger and be for class Fractional:
Prelude> :t 3 * 20 / 4
3 * 20 / 4 :: Fractional a => a
The big difference is the identifier c is an Integer. The reason why a simple let-binding in GHCi prompt isn't assigned an overloaded type is the dreaded monomorphism restriction. In short: if you define a value that doesn't have any explicit arguments,
then it cannot have overloaded type unless you provide an explicit type signature.
Numeric types are then defaulted to Integer.
Once c is an Integer, the result of the multiplication is Integer, too:
Prelude> :t 3 * c
3 * c :: Integer
And Integer is not in the Fractional class.
There are two solutions to this problem.
Make sure your identifiers have overloaded type, too. In this case, it would
be as simple as saying
Prelude> let c :: Num a => a; c = 20
Prelude> :t c
c :: Num a => a
Use fromIntegral to cast an integral value to an arbitrary numeric value:
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
Prelude> let c = 20
Prelude> :t c
c :: Integer
Prelude> :t fromIntegral c
fromIntegral c :: Num b => b
Prelude> 3 * fromIntegral c / 4
15.0
Haskell will never automatically convert one type into another when you pass it to a function. Either it's compatible with the expected type already, in which case no coercion is necessary, or the program fails to compile.
If you write a whole program and compile it, things generally "just work" without you having to think too much about int/float types; so long as you're consistent (i.e. you don't try to treat something as an Int in one place and a Float in another) the constraints just flow through the program and figure out the types for you.
For example, if I put this in a source file and compile it:
main = do
let c = 20
let it = 3 * c / 4
print it
Then everything's fine, and running the program prints 15.0. You can see from the .0 that GHC successfully figured out that c must be some kind of fractional number, and made everything work, without me having to give any explicit type signatures.
c can't be an integer because the / operator is for mathematical division, which isn't defined on integers. The operation of integer division is represented by the div function (usable in operator fashion as x `div` y). I think this might be what is tripping you up in your whole program? This is unfortunately just one of those things you have to learn by getting tripped up by it, if you're used to the situation in many other languages where / is sometimes mathematical division and sometimes integer division.
It's when you're playing around in the interpreter that things get messy, because there you tend to bind values with no context whatsoever. In interpreter GHCi has to execute let c = 20 on its own, because you haven't entered 3 * c / 4 yet. It has no way of knowing whether you intend that 20 to be an Int, Integer, Float, Double, Rational, etc
Haskell will pick a default type for numeric values; otherwise if you never use any functions that only work on one particular type of number you'd always get an error about ambiguous type variables. This normally works fine, because these default rules are applied while reading the whole module and so take into account all the other constraints on the type (like whether you've ever used it with /). But here there are no other constraints it can see, so the type defaulting picks the first cab off the rank and makes c an Integer.
Then, when you ask GHCi to evaluate 3 * c / 4, it's too late. c is an Integer, so must 3 * c be, and Integers don't support /.
So in the interpreter, yes, sometimes if you don't give an explicit type to a let binding GHC will pick an incorrect type, especially with numeric types. After that, you're stuck with whatever operations are supported by the concrete type GHCi picked, but when you get this kind of error you can always rebind the variable; e.g. let c = 20.0.
However I suspect in your real program the problem is simply that the operation you wanted was actually div rather than /.
Haskell is a bit unusual in this way. Yes you can't divide to integers together but it's rarely a problem.
The reason is that if you look at the Num typeclass, there's a function fromIntegral this allows you to convert literals into the appropriate type. This with type inference alleviates 99% of the cases where it'd be a problem. Quick example:
newtype Foo = Foo Integer
deriving (Show, Eq)
instance Num Foo where
fromInteger _ = Foo 0
negate = undefined
abs = undefined
(+) = undefined
(-) = undefined
(*) = undefined
signum = undefined
Now if we load this into GHCi
*> 0 :: Foo
Foo 0
*> 1 :: Foo
Foo 0
So you see we are able to do some pretty cool things with how GHCi parses a raw integer. This has a lot of practical uses in DSL's that we won't talk about here.
Next question was how to get from a Double to an Integer or vice versa. There's a function for that.
In the case of going from an Integer to a Double, we'd use fromInteger as well. Why?
Well the type signature for it is
(Num a) => Integer -> a
and since we can use (+) with Doubles we know they're a Num instance. And from there it's easy.
*> 0 :: Double
0.0
Last piece of the puzzle is Double -> Integer. Well a brief search on Hoogle shows
truncate
floor
round
-- etc ...
I'll leave that to you to search.
Type coercion in Haskell isn't automatic (or rather, it doesn't actually exist). When you write the literal 20 it's inferred to be of type Num a => a (conceptually anyway. I don't think it works quite like that) and will, depending on the context in which it is used (i.e. what functions you pass it to) be instantiated with an appropitiate type (I believe if no further constraints are applied, this will default to Integer when you need a concrete type at some point). If you need a different kind of Num, you need to convert the numbers e.g. (3* fromIntegral c / 4) in your example.
The type of (/) is Fractional a => a -> a -> a.
To divide Integers, use div instead of (/). Note that the type of div is
div :: Integral a => a -> a -> a
In most top-level languages the compiler works for me -- not the other way around.
I argue that the Haskell compiler works for you just as much, if not more so, than those of other languages you have used. Haskell is a very different language than the traditional imperative languages (such as C, C++, Java, etc.) you are probably used to. This means that the compiler works differently as well.
As others have stated, Haskell will never automatically coerce from one type to another. If you have an Integer which needs to be used as a Float, you need to do the conversion explicitly with fromInteger.

Haskell types frustrating a simple 'average' function

I'm playing around with beginner Haskell, and I wanted to write an average function. It seemed like the simplest thing in the world, right?
Wrong.
It seems like Haskell's type system forbids average from working on a generic numeric type - I can get it to work on a list of Integrals, or an list of Fractionals, but not both.
I want:
average :: (Num a, Fractional b) => [a] -> b
average xs = ...
But I can only get:
averageInt :: (Integral a, Fractional b) => [a] -> b
averageInt xs = fromIntegral (sum xs) / fromIntegral (length xs)
or
averageFrac :: (Fractional a) => [a] -> a
averageFrac xs = sum xs / fromIntegral (length xs)
and the second one seems to work. Until I try to pass a variable.
*Main> averageFrac [1,2,3]
2.0
*Main> let x = [1,2,3]
*Main> :t x
x :: [Integer]
*Main> averageFrac x
<interactive>:1:0:
No instance for (Fractional Integer)
arising from a use of `averageFrac ' at <interactive>:1:0-8
Possible fix: add an instance declaration for (Fractional Integer)
In the expression: average x
In the definition of `it': it = averageFrac x
Apparently, Haskell is really picky about its types. That makes sense. But not when they could both be [Num]
Am I missing an obvious application of RealFrac?
Is there way to coerce Integrals into Fractionals that doesn't choke when it gets a Fractional input?
Is there some way to use Either and either to make some sort of polymorphic average function that would work on any sort of numeric array?
Does Haskell's type system outright forbid this function from ever existing?
Learning Haskell is like learning Calculus. It's really complicated and based on mountains of theory, and sometimes the problem is so mindbogglingly complex that I don't even know enough to phrase the question correctly, so any insight will be warmly accepted.
(Also, footnote: this is based off a homework problem. Everybody agrees that averageFrac, above, gets full points, but I have a sneaking suspicion that there is a way to make it work on both Integral AND Fractional arrays)
So fundamentally, you're constrained by the type of (/):
(/) :: (Fractional a) => a -> a -> a
BTW, you also want Data.List.genericLength
genericLength :: (Num i) => [b] -> i
So how about removing the fromIntegral for something more general:
import Data.List
average xs = realToFrac (sum xs) / genericLength xs
which has only a Real constraint (Int, Integer, Float, Double)...
average :: (Real a, Fractional b) => [a] -> b
So that'll take any Real into any Fractional.
And note all the posters getting caught by the polymorphic numeric literals in Haskell. 1 is not an integer, it is any number.
The Real class provides only one method: the ability to turn a value in class Num to a rational. Which is exactly what we need here.
And thus,
Prelude> average ([1 .. 10] :: [Double])
5.5
Prelude> average ([1 .. 10] :: [Int])
5.5
Prelude> average ([1 .. 10] :: [Float])
5.5
Prelude> average ([1 .. 10] :: [Data.Word.Word8])
5.5
The question has been very well answered by Dons, I thought I might add something.
When calculating the average this way :
average xs = realToFrac (sum xs) / genericLength xs
What your code will do is to traverse the list twice, once to calculate the sum of its elements, and once to get its length.
As far as I know, GHC isn't able yet to optimize this and compute both the sum and length in a single pass.
It doesn't hurt even as a beginner to think about it and about possible solutions, for example the average function might be written using a fold that computes both the sum and length; on ghci :
:set -XBangPatterns
import Data.List
let avg l=let (t,n) = foldl' (\(!b,!c) a -> (a+b,c+1)) (0,0) l in realToFrac(t)/realToFrac(n)
avg ([1,2,3,4]::[Int])
2.5
avg ([1,2,3,4]::[Double])
2.5
The function doesn't look as elegant, but the performance is better.
More information on Dons blog:
http://donsbot.wordpress.com/2008/06/04/haskell-as-fast-as-c-working-at-a-high-altitude-for-low-level-performance/
Since dons has done such a good job at answering your question, I'll work on questioning your question....
For example, in your question, where you first run an average on a given list, getting a good answer. Then, you take what looks like the exact same list, assign it to a variable, then use the function the variable...which then blows up.
What you've run into here is a set-up in the compiler, called the DMR: the D readed M onomorphic R estriction. When you passed the list straight into the function, the compiler made no assumption about which type the numbers were, it just inferred what types it could be based on usage, and then picked one once it couldn't narrow the field down any more. It's kind of like the direct opposite of duck-typing, there.
Anyway, when you assigned the list to a variable, the DMR kicked in. Since you've put the list in a variable, but given no hints on how you want to use it, the DMR made the compiler pick a type, in this case, it picked one that matched the form and seemed to fit: Integer. Since your function couldn't use an Integer in its / operation (it needs a type in the Fractional class), it makes that very complaint: there's no instance of Integer in the Fractional class. There are options you can set in GHC so that it doesn't force your values into a single form ("mono-morphic", get it?) until it needs to, but it makes any error messages slightly tougher to figure out.
Now, on another note, you had a reply to dons' answer that caught my eye:
I was mislead by the chart on the last page of cs.ut.ee/~varmo/MFP2004/PreludeTour.pdf
that shows Floating NOT inheriting properties from Real, and I then assumed that
they would share no types in common.
Haskell does types differently from what you're used to. Real and Floating are type classes, which work more like interfaces than object classes. They tell you what you can do with a type that's in that class, but it doesn't mean that some type can't do other things, any more than having one interface means that a(n OO-style) class can't have any others.
Learning Haskell is like learning Calculus
I'd say learning Haskell is like learning Swedish - there are lots of little, simple things (letters, numbers) that look and work the same, but there are also words that look like they should mean one thing, when they actually mean something else. But once you get fluent in it, your regular friends will be amazed at how you can spout off this oddball stuff that makes gorgeous beauties do amazing tricks. Curiously, there are many folks involved in Haskell from the beginnings, who also know Swedish. Maybe that metaphor is more than just a metaphor...
:m Data.List
let list = [1..10]
let average = div (sum list) (genericLength list)
average
I'm amazed that after all of these years, no one has pointed out that Don Stewart's average doesn't work with complex numbers, while OP's averageFrac does work with complex numbers. Neither one is unambiguously superior to the other.
The fundamental reason why you can't write
average :: (Num a, Fractional b) => [a] -> b
is that it can be instantiated at a type like
average :: [Complex Double] -> Double
Haskell's numeric classes support conversions that are a little bit lossy, like Rational to Double, Double to Float, and Integer to Int, but don't support extremely lossy conversions like complex to real, or fractional to integral. You can't convert Complex Double to Double without explicitly taking (e.g.) the real part of it, which is not something that average should be doing. Therefore, you can't write average :: [Complex Double] -> Double. Therefore, you can't write average with any type that can be specialized to [Complex Double] -> Double.
The most Haskellish type for average is probably OP's averageFrac. Generally, functions that aren't dedicated to type conversion should be leaving the type conversion to the caller as much as possible. averageFrac will work with practically any numeric type, either directly or after coercion of the input list. The caller, being closer to the source of the data, is more likely to know whether it needs to be coerced or not (and if it doesn't know, it can leave the decision to its caller). In contrast, Don Stewart's average just doesn't support complex numbers, even with coercion. You'd either have to rewrite it from scratch or else call it twice with the real and imaginary projections of the list (and then write another wrapper for quaternions that calls it four times, etc.).
Yeah, Haskell's type system is very picky. The problem here is the type of fromIntegral:
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral will only accept an Integral as a, not any other kind of Num. (/), on the other hand only accepts fractional. How do you go about making the two work together?
Well, the sum function is a good start:
Prelude> :t sum
sum :: (Num a) => [a] -> a
Sum takes a list of any Num and returns a Num.
Your next problem is the length of the list. The length is an Int:
Prelude> :t length
length :: [a] -> Int
You need to convert that Int into a Num as well. That's what fromIntegral does.
So now you've got a function that returns a Num and another function that returns a Num. There are some rules for type promotion of numbers you can look up, but basically at this point you're good to go:
Prelude> let average xs = (sum xs) / (fromIntegral (length xs))
Prelude> :t average
average :: (Fractional a) => [a] -> a
Let's give it a trial run:
Prelude> average [1,2,3,4,5]
3.0
Prelude> average [1.2,3.4,5.6,7.8,9.0]
5.4
Prelude> average [1.2,3,4.5,6,7.8,9]
5.25

Haskell: Constrain function on type Double to only work with Integers

Suppose I'm writing a function that takes a list of integers and returns only those integers in the list that are less than 5.2. I might do something like this:
belowThreshold = filter (< 5.2)
Easy enough, right? But now I want to constrain this function to only work with input lists of type [Int] for design reasons of my own. This seems like a reasonable request. Alas, no. A declaration that constraints the types as so:
belowThreshold :: [Integer] -> [Integer]
belowThreshold = filter (< 5.2)
Causes a type error. So what's the story here? Why does doing filter (< 5.2) seem to convert my input list into Doubles? How can I make a version of this function that only accepts integer lists and only returns integer lists? Why does the type system hate me?
Check the inferred type of belowThreshold in ghci before adding your annoatation:
> :t belowThreshold
belowThreshold :: [Double] -> [Double]
It sounds like you expected Num a => [a] -> [a] when you said "constrain this function". You are actually changing the type of the function when you add the [Integer] -> [Integer] annotation.
To make this work, use an explicit conversion:
belowThreshold = filter ((< 5.2) . fromIntegral)
Now belowThreshold :: [Integer] -> [Integer] like you wanted. But the integers are converted to doubles before comparison to 5.2.
So why do you need the conversion? The type error probably misled you: the list of Integers wasn't being converted to Doubles by comparison to 5.2, the real problem is that only Doubles can be compared to Doubles, so you must pass a list of Doubles to belowThreshold. Haskell has no implicit conversions, not even between numbers. If you want conversions, you have to write them yourself.
I want to constrain this function to only work with input lists of type [Int] for design reasons of my own. This seems like a reasonable request.
Well, from the perspective of the type system, no. Is this reasonable code?
'c' < "foo"
What about this?
12 < "bar"
All of these values are instances of Ord, but you can't use them together with (<). Haskell has no implicit conversions. So even if two values are both instances of Num as well as Ord, you won't be able to compare them with (<) if they are of different types.
You are trying to compare an Integer to a double (5.2). Haskell doesn't like that. Try using
filter (< 6)
If you must use a double (let's say it is an argument), I would use ceiling:
filter (< (ceiling 5.2))
Now if you want a function that takes in the bounding value as 'any' (relevant) numeric value, you can make your own type class to ceiling the number for you.
class Ceilingable a where
ceil :: (Integral b) => a -> b
instance (RealFrac a) => Ceilingable a where
ceil = ceiling
instance (Integral a) => Ceilingable a where
ceil = fromIntegral
belowThreshold :: (Ceilingable a) => a -> [Integer] -> [Integer]
belowThreshold threshold = filter (< ceil threshold)
The syntax 5.2 is valid for any Fractional. Int is not an instance of Fractional, nor can or should it be. As what to do when converting an arbitrary Rational to an Int is underspecified.
The conversion to a Double from an arbitrary fraction, however makes perfectly good sense (within the range of the type).
Your expectation is driven by the presence of implicit coercions in many languages.
However, those come with a cost. You have to manually ensure that the entire system of coercions is confluent. Haskell does not do this, choosing instead to let numeric literal syntax leverage the type system. To convert between them you need to use fromIntegral to make explicit the need for coercion, this avoids relying on confluence and allows programmers to define new numeric types.
belowThreshold = filter (\x -> fromIntegral x < 5.2)
This is analogous to using an explicit conversion in C++, like ((double)x < 5.2). Although, this statement only works because of defaulting, because 5.2 could be used as a member of any Fractional, and the result of 'fromIntegral x' is any Num, a superclass of Fractional, so fromIntegral x < 5.2 is underspecified, it merely knows that it needs to compare two Fractional values of the same type and it chooses Double as a reasonable default, based on a 'default' statement.
Also note that Int is not the only Integral type, so the above method works on any list of Integral values:
belowThreshold :: Integral a => [a] -> [a]

Resources