3

To use an infix operator as a prefix function in OCaml, you can put parenthesis around it. for example, 1 + 2 is equivalent to (+) 1 2.

How do you do the opposite?

For example, in Haskell, a prefix function taking two parameters can be used as an infix operator by wrapping it in backticks. prefixFunction x y is equivalent to x `prefixFunction` y. Is there an equivalent in OCaml?

glennsl
  • 28,186
  • 12
  • 57
  • 75

3 Answers3

4

This isn't possible. It's simply not a feature of the language.

See the grammar for infix operators and more specifically of prefix and infix symbols in the OCaml manual.

glennsl
  • 28,186
  • 12
  • 57
  • 75
2

While the cut-and-dry answer to this question is that the language grammar simply doesn't support this, and that you should generally prefer the established OCaml idioms of using named functions, lambdas, |> and @@, and only occasionally Fun.flip..

The playful why-not answer which is, disclaimer, please don't use this in actual code, is that you can sort-of use the existing infix operator rules to your advantage, to achieve a similar effect:

external (|<) : 'a -> ('a -> 'b) -> 'b = "%revapply" (* 1 *)
external (>|) : ('a -> 'b) -> 'a -> 'b = "%apply"

let _ = assert (10 |<Int.dev>| 2 = 5)

(* 1: I use [external] declarations here because when the compiler sees a
 *    primitive, it has special compilation/optimization rules for it, unlike
 *    regular functions. Feel free to define the operators as [x |> f] and
 *    [f @@ x]/[f x] respectively. *)

This "hack" "works" because operators that start with |.. and those that start with >.. are left-associative and have the same precedence. You can choose anything as long as you make it so the "infix" function evaluates its left argument first.

This "hack" doesn't actually work because:

  1. It behaves badly in the presence of other operators.. I believe Haskell puts backticked functions at highest precedence unless they have declared fixity.. Up to you if allowing fixity overrides is a good choice.
    Try for yourself: change the assertion above from ... = 5 to 5 = ....
  2. It doesn't read well, There's no way (that I know of) to redefine one-character operators (even worse of an idea than making your own) to have this nice symmetric `f` syntax with its barely-noticeable backticks.
  3. It doesn't partially-apply at all.. One of the reasons backtick syntax is often-used in Haskell isn't particularly that it allows you to use functions in infix position, it's because of the presence of another important feature, operator sections. With this, it becomes shorter to write a backticked partially-applied function (`f`x) than it is to write the usual (as Chris points out) flipped function flip f x.

More in that final point's direction, I'd like to shout-out something implemented in ReasonML, an alternative syntax to OCaml, that I personally consider the cleanest solution: argument placeholders. It turns the idea of infix sections on binary functions into the more general n-ary partial application again, this time with control over position given to you. The only improvement I can see over this is also specifying the order of application for placeholders.
I've also never seen this in space-application languages f x y ..., only seen it in Reason and Scala, both have the f(x, y, ...) syntax (with Reason having this admittedly surprising, but sensible given design constraints, notion of functions with argument lists that are still curried).

I hope this has been useful!

Moth
  • 253
  • 2
  • 8
0

In addition to what glennsl has posted, the use of backticks to use a function as an infix operator in Haskell can be useful for situations where you wish to partially apply a function, but not the first argument.

Let's say I have the following OCaml. I can't partially apply foo because in foo x -> foo x 2 the x is not the second argument to foo.

let foo a b = a * 3 / b

let lst1 = [1; 2; 3; 4; 5]

let lst2 = List.map (fun x -> foo x 2) lst1

In Haskell I might write:

foo a b = a * 3 `div` b

lst1 = [1, 2, 3, 4, 5]

lst2 = map (`foo` 2) lst1
-- equivalent to:
-- lst2 = map (\x -> foo x 2) lst1

I can achieve a similar effect using Fun.flip.

let foo a b = a * 3 / b

let lst1 = [1; 2; 3; 4; 5]

let lst2 = List.map (Fun.flip foo 2) lst1
Chris
  • 26,361
  • 5
  • 21
  • 42