3

I am trying to define a function to find the absolute difference of two numbers, such that both

absoluteDifference 2 5
absoluteDifference 5 2

return 3.

Here is my best effort so far:

absoluteDifference :: Num a => a -> a -> a
absoluteDifference = abs . (-)

In my head, this applies abs to the result of subtracting two numbers. However, this gives me the error

* Could not deduce (Num (a -> a)) arising from a use of `abs'
    (maybe you haven't applied a function to enough arguments?)
  from the context: Num a
    bound by the type signature for:
               absoluteDifference :: Num a => a -> a -> a
    at C:\Users\Adam\dev\daily-programmer\e311\e311.hs:3:1-42
* In the first argument of `(.)', namely `abs'
  In the expression: abs . (-)
  In an equation for `absoluteDifference':
      absoluteDifference = abs . (-)

Which I don't understand. I could trivially implement the function as

absoluteDifference a b = abs $ a - b

but I want to know how to compose the functions.

Adam Hammes
  • 820
  • 1
  • 8
  • 22

4 Answers4

5

The info for (.)

Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c   -- Defined in ‘GHC.Base’

shows that it accepts functions with types a -> b

but (-) has the type

Prelude> :i (-)
class Num a where
  ...
  (-) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 -

so, it is possible to define another composition operator that accepts functions having the above type, and then they can be composed.

of' :: (a -> a) -> (a -> a -> a) -> a -> a -> a
of' f g a b = f (g a b)

abdiff = abs `of'` (-)

abdiff 1 10
9

note: as user @david-young points out correctly, of' can be more general by specifying the type as below:

of' :: (a -> b) -> (c -> d -> a) -> c -> d -> b
of' f g x y = f (g x y)
Haleemur Ali
  • 26,718
  • 5
  • 61
  • 85
3

Besides defining a custom operator, as suggested by Haleemur Ali's answer, one alternative is making the definition less point-free by having a single-argument function as the second argument of (.).

absoluteDifference a = abs . (-) a

Given how similar are the roles of the two arguments in your function, from a readability point of view it doesn't make much sense to write it in this way (though it might work better in other cases).

Another possibility is making it more point-free (by having a function-modifying function as the first argument of (-)):

absoluteDifference = (abs .) . (-)

While this is a nice parlour trick, this sort of code with (.) sections is rather cryptic, and it is generally a good idea to avoid it in "real" code.

Community
  • 1
  • 1
duplode
  • 33,731
  • 7
  • 79
  • 150
1

Why not an owl operator?

(...) = (.) . (.)
absoluteDifference = abs ... (-)
xgrommx
  • 461
  • 3
  • 15
  • 1
    Why not variadic composition? ;) http://stackoverflow.com/questions/9656797/variadic-compose-function – Shersh May 20 '17 at 14:31
1

Actually your answer is pretty close. All you need is to amend it as follows;

absDiff :: Num a => a -> a -> a
absDiff n = abs . (n-)

*Main> absDiff 3 9
6
*Main> absDiff 9 3
6
Redu
  • 25,060
  • 6
  • 56
  • 76