Here's my attempt to write a function that splits a list of even length into two equal halves.
halve :: [a] -> ([a], [a])
halve x
| even len = (take half x, drop half x)
| otherwise = error "Cannnot halve a list of odd length"
where
len = length x
half = len / 2
I am getting the following error:
No instance for (Fractional Int) arising from a use of ‘/’
In the expression: len / 2
In an equation for ‘half’: half = len / 2
In an equation for ‘halve’:
I don't understand the error but I have a suspicion that Haskell needs to be told in advance that len is something you can divide by 2. So, how do I rectify the example? Is my code anywhere near idiomatic haskell? I'd appreciate any other comments regarding my code.
The /
is used for when you're happy to have a non-integer answer. Since you've already checked the number's even, you can hapily use integer division with div
:
halve :: [a] -> ([a], [a])
halve x | even len = (take half x, drop half x)
| otherwise = error "Cannnot halve a list of odd length"
where len = length x
half = len `div` 2
(Personally I'd be happy to halve an odd length list inexactly and avoid an error message, but that's up to you.)
This distinction is indicated by the types:
(/) :: Fractional a => a -> a -> a
div :: Integral a => a -> a -> a
so you can only use /
when the type supports non-integer division, and you can only use div
when it's a whole-number type. That way you can't make a mistake thinking you're doing one sort of division when you're actually doing another.
Well done, by the way, you're thinking stuff through well.
Actually, the "No instance for ..." error message is almost always because something's the wrong type. I most frequently get it when I've put arguments in the wrong order. In this case you've had is for using the othetr sort of divition when yout type is Int
.
It says "No instance" because the function you're trying to use works for a class of types, but the type of the data you're giving isn't in (an instance of) that class. The compiler sees this as a missing instance declaration, where more often than not it's just a mistake and it's the wrong type altogether. I very rarely intend to make something an instance of a class and then forget, whereas I more often put arguments in the wrong place.