1

I'm a bit confused concerning the dot operator. I've got the following code (for testing):

test :: Int -> Int -> Int
test x y = f1 . f2 x y 
           where f1 n = n+1
                 f2 x' y' = x' * y'

And I figured it would first execute (f2 x y) and then f1 on that result, but instead it throws an error. Could anyone tell me the exact definition of the dot operator and what equals f1 . f2 x y? (when written without the dot operator)

Best regards, Skyfe.

EDIT: If the dot operator yields a complete new function I figured the following code should work:

test :: Int -> Int -> Int
test x y = f1 . f2 x
           where f1 n = n+1
                 f2 x' y' = x' + y'

But also that code returns an error.

user2999349
  • 859
  • 8
  • 21

3 Answers3

7

Infix operators always have lower precedence than function application in Haskell, so this

f1 . f2 x

parses like this

f1 . (f2 x)

but, f2 x is not of type function (well, it could be if f2 returns a function, but that is not so in general, or in your problem). Since (.) acts on functions, this won't work.

Use ($) instead

f1 $ f2 x
jamshidh
  • 12,002
  • 17
  • 31
  • Aah thanks I get it! So that means the dot operator creates a new function from 2 functions, but then why wouldn't my 2nd code work? f1 . f2 x would thus be parsed f1 . (f2 x), where f2 x would be a function still expecting one parameter, which would be the y parameter just like f1. – user2999349 Nov 05 '14 at 01:02
  • 1
    @user2999349, you need to say `test x =` instead of `test x y =` in that case. – luqui Nov 05 '14 at 01:21
  • 2
    @user2999349- @luqui beat me to it, the problem isn't the parameters you are passing into (.), it is a mismatch in types in what is expected for the type of `test x y` (should be an Int) and what `f1 . f2 x` actually is (it is `(Int->Int)`). You can either put the `y` in the RHS (ie- make both sides type `Int`), or remove it from the LHS (ie- make both sides type `(Int->Int)` to make the definition consistent. – jamshidh Nov 05 '14 at 02:53
2

One common approach is to combine (.) with ($):

f1 . f2 $ x

This can be extended easily to build up longer "pipelines":

f1 . f2 . f3 . f4 $ x

and then, if you find yourself needing that same combo elsewhere, you need only cut and paste:

fs = f1 . f2 . f3 . f4

... fs x ... fs y
dfeuer
  • 48,079
  • 5
  • 63
  • 167
2

(I think the other answers come up with $ too quickly)

As you already know,

f1 . f2 x

is parsed as

f1 . (f2 x)

Write

(f1 . f2) x

instead to do what it reads: compose f2 and f1 and then apply this composed function to x. Now

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

looks like it is superfluous. Its primary purpose is that it has the lowest precedence, so you can avoid parentheses:

foo . bar . baz $ x + y * z = (foo . bar . baz) (x + y * z)

See also: Haskell: difference between . (dot) and $ (dollar sign)

Community
  • 1
  • 1
Franky
  • 2,339
  • 2
  • 18
  • 27