1

I was trying to define a function that determines if a number is a multiple of 3, I first did the easy case

isMultipleOfThree num = (==0) (rem num 3)

but actually even in that simple case, my first guess was to write my solution like

isMultipleOfThree num = (==0).(rem num 3)

which returns the error

Non type-variable argument in the constraint: Integral (a -> b) (Use FlexibleContexts to permit this) When checking that ‘isMultipleOfThree’ has the inferred type isMultipleOfThree :: forall b a. (Eq b, Integral (a -> b), Num b) => (a -> b) -> a -> Bool

and then tried to make it more "polymorphic":

The correct answer was as follows, but I thought that I was supposed to use a space instead of the composition operator... and then I just "guessed" I would try with the composition operator:

esMultiploDeTres = (==0).(flip (rem) 3)

So I guess that I would add to my original question: "what is a space between two functions?"

newbie
  • 1,199
  • 1
  • 10
  • 25
  • Not strictly a duplicate, but [this](/questions/940382/what-is-the-difference-between-dot-and-dollar-sign) question and its answers should shed some light. Note that that is about `(.)` vs `($)` but apart from precedence `$` is basically the same as a space. – Robin Zigmond Jul 06 '21 at 16:14

2 Answers2

4

(.) is defined simply as

# Apply g to x, then apply f to the result.
f . g = \x -> f (g x)

which means

(f . g) x == f (g x)

Juxtaposition represents function application, while the . represents function composition.

Higher-order functions, such as (.), can take other functions as arguments, which means you can apply such a function to another function. f . g is an infix expression, equivalent to the prefix expression (.) f g, where (.) is applied to f, and that result is applied to g.

chepner
  • 497,756
  • 71
  • 530
  • 681
3
isMultipleOfThree num = (==0) (rem num 3)

The (== 0) is called an operator section. It's equivalent to \x -> x == 0, hence this is the same as

isMultipleOfThree num = (\x -> x == 0) (rem num 3)

And we immediately apply the lambda, so we get

isMultipleOfThree num = rem num 3 == 0

Now, on the other hand, your second example is

isMultipleOfThree num = (\x -> x == 0) . (rem num 3)

Now we're not applying the lambda immediately. We're applying the (.) function, which is defined something like

(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = \y -> f (g y)

Hence, we have

isMultipleOfThree num = (\y -> (\x -> x == 0) ((rem num 3) y))

Now the lambda on x is getting applied to an argument, so we can simplify the inner one

isMultipleOfThree num = (\y -> (rem num 3) y == 0)

And the parentheses around rem are extraneous, hence

isMultipleOfThree num = (\y -> rem num 3 y == 0)

So we're applying rem, a function of two arguments, to three arguments. Hence your error.

If you want to use (.) to define your function, we can. But the right-hand side needs to have an argument left out.

isMultipleOfThree = (== 0) . (\x -> rem x 3)

or

isMultipleOfThree = (== 0) . (`rem` 3)

Note that we don't mention your function argument num anymore. The composition on the right-hand side is expecting an argument. It's going to do (rem 3)on that argument and then compare the result against zero.(.)works on functions, and both sides of the(.)` operator should have an argument missing.

Note that what you might have been thinking of is ($), which is defined roughly as

($) :: (a -> b) -> (a -> b)
f $ x = f x

This really is just function application. It's not composition. We could easily write your original function as

isMultipleOfThree num = (== 0) $ (rem num 3)

The ($) actually does behave like juxtaposition. The only point of it is to change operator precedence. We can omit parentheses in this case

isMultipleOfThree num = (== 0) $ rem num 3

and this will still work, whereas if we omit parentheses in your original function

isMultipleOfThree num = (==0) rem num 3 -- Wrong!

Now we're trying to apply the (==0) function to three arguments, which is definitely not correct.

amalloy
  • 89,153
  • 8
  • 140
  • 205
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116