Reputation: 11
I'm trying to write a simple function to check whether one integer divides another by taking the modulus and checking if it's 0. My thought was something like
divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)
where divides a b would be true iff a divides b. However, this code gives me the error
Couldn't match expected type `a -> Bool' with actual type `Bool'
Expected type: b0 -> a -> Bool
Actual type: b0 -> Bool
In the first argument of `(.)', namely `(== 0)'
In the expression: (== 0) . mod
I really don't see why this code doesn't work. Please enlighten me!
Upvotes: 1
Views: 651
Reputation: 53881
The gist is, .
will only feed each function 1 argument, but flip mod
needs two. A simple solution is
(.:) = (.) . (.) -- the owl or boobs operator
divides = (0==) .: flip mod
where .:
is
(c -> d) -> (a -> b -> c) -> a -> b -> d
Upvotes: 6
Reputation: 11362
It looks like you're expecting the .
operator to carry over the fact that flip mod
takes two arguments to its result, ie. you expect this:
f :: a -> b -> c
g :: c -> d
g . f :: a -> b -> d
Unfortunately, it doesn't work that way. Functions always take a single argument, and multiple argument functions are "simulated" by having functions that return a function. For ex, a -> b -> c
can be read as a -> (b -> c)
. Therefore what happens is as follows:
f :: a -> (b -> c)
g :: (b -> c) -> d
g . f :: a -> d
Thus why g
(which is (== 0)
in your case) expects a function, and the type of your function actually is a -> Bool
and not a -> a -> Bool
.
Upvotes: 2
Reputation: 11963
To see what's wrong with your code, just eta-expand it manually:
divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)
-- divides x = ((==0) . (flip mod)) x
-- = ((==0) $ flip mod x)
-- = flip mod x == 0
That last line doesn't typecheck, because (==) :: a -> a -> Bool
, but divides x
should be of type a -> Bool
, not Bool
!
The easiest way to correct the code would be to write it in a more expanded form, for example:
divides :: (Integral a) => a -> a -> Bool
divides x = (==0) . (`mod` x)
If you really want to write it eta-reduced, here is what it would look like:
divides :: (Integral a) => a -> a -> Bool
divides = ((==0).) . (flip mod)
-- divides x = ((==0).) $ (`mod` x)
-- = (==0) . (`mod x`)
Upvotes: 4