Search code examples
haskellinfix-notation

Haskell infix notation taking 2 arguments on the left


In Haskell, infix notation allows us to do the following:

divide :: Double -> Double -> Double
divide x y = x / y

foo = divide 10.0 3.0
bar = 10.0 `divide` 3.0 -- infix
-- foo and bar are equivalent

Is it possible to use/define infix notation that would take 2 arguments on the left?

sumAndDivideBy :: Double -> Double -> Double -> Double
sumAndDivideBy x y z = (x + y) / z

foo2 = sumAndDivideBy 3.0 5.0 2.0
bar2 = 3.0 `sumAndDivideBy` 5.0 $ 2.0 -- works but not what I wan't
bar3 = 3.0 5.0 `sumAndDivideBy` 2.0   -- does not work - impossible?

Solution

  • The short answer is that, no, you can't do that as you ask.

    As far as I understand it, if you have a function f :: x -> y -> z. then you can write applications of it in either the form

    f x0 y0
    

    or

    x0 `f` y0
    

    and they mean exactly the same thing.

    In the case of your function sumAndDivideBy :: Double -> Double -> Double -> Double, because of currying that is equivalent to Double -> (Double -> (Double -> Double)) if we are being completely explicit. Let me write that in a form intermediate between the two:

    sumAndDivideBy :: Double -> Double -> (Double -> Double)
    

    This fits exactly the schematic form I gave above, with x and y equal to Double and z to the function type Double -> Double. Which means that you can indeed use sumAndDivideBy in infix form, exactly as you did in the penultimate line of your example. In general you can do this with any function of more than 2 arguments, but the "infix" form only works if it goes between the first and second arguments.

    Of course, due to currying again, you can realise that sumAndDivideBy 3.0 is itself a function Double -> Double -> Double, which you can use in infix form, in exactly the same "position" you want it to be in. So you can do this:

    sumWithThreeAndDivide = sumAndDivideBy 3.0
    foo = 5.0 `sumWithThreeAndDivide` 2.0
    

    but it does necessitate defining a name for the partially-applied function, which I guess limits the use for the kind of things you're thinking about.

    I'm not sure what exactly you're aiming for though, given that your example can be very naturally rendered, with the divide function as you've shown it, as

    (3.0 + 5.0) `divide` 2.0
    

    Or, of course, since divide is identical to (/), just doing 3.0 + 5.0 / 2.0 as I assume you naturally would.