0

I've just been doing some validation on value to see it is a product of three. Great use the modulus function. I want to pipe to it. Great use a partial application. But apparently not.

This is an example from my fsi in vs code.

> 27 % 3
-
- ;;
val it : int = 0

> (%) 3 27
- ;;
val it : int = 3

I really didn't expect to get a different result from an infix vs a partial.

Here is the operation in a pipe for context:

...
|> Seq.length // 27
|> (%) 3 // 3
Craig.C
  • 561
  • 4
  • 17

2 Answers2

6

Because you have the operands flipped. (%) 3 27 actually means 3 % 27, not 27 % 3, i.e. you want (%) 27 3.

LSM07
  • 787
  • 2
  • 7
  • 21
  • Agreed. Not a bug. Found that pretty quick and put in an answer. Thought it was still useful to have such a thing as a record. Pretty common beginner mistake I would have thought. – Craig.C Jun 02 '19 at 19:10
3

Partial application of an infix doesn't work as I expected. The statement in my qustion is incorrect and this isn't a bug. It might be a fairly common missunderstanding for beginers so its worth a good explaination.

(%) x y = x % y

Therefore

 (%) 27 3
 = 27 % 3
 = 0

The confusion comes when piping in the final value, the y. you should not expect

y
|> (%) x

to result in

 y % x

but rather

x % y

This is a little bit confusing particularly if you have used an infix operator, which does treats inputs symetrically (e.g +,=,<>,*), without questioning too deeply. You must take care that order of values supplied to an infix opperator are correct, even if it looks right at first inspection.

The clearest and most verbose way to handle an infix opperator, which accepts values in the opposite order to which you wish to supply them, is to just write out a lambda. However, there is also the option to back pipe '<|'.

Here is a snippet of code which was causing me a bug due to my misuse of the partially applied infix.

...
|> Seq.length // 27
|> (%) 3 // 3 % 27 = 3

It could be written with a backpipe to perform as expected

...
|> Seq.length // 27
|> (%) <|3 // 27 % 3 = 0

or more clearly with a lambda

...
|> Seq.length // 27
|> (fun x -> x % 3 // 27 % 3 = 0
Craig.C
  • 561
  • 4
  • 17
  • 1
    I downvoted this answer because it's incorrect. You assert that `(%) x y = y % x`, but the opposite is true. `(%) x y = x % y`. The actual source of your confusion is the `|>` operator: `y |> f x` is not equivalent to `f y x`, but to `f x y`. So `27 |> (%) 3` is equivalent to `(%) 3 27` which is equivalent to `3 % 27`. This caught me off-guard just last week with an `append` function: I wrote `a |> append b` thinking that it was equivalent to `append a b`, but in fact it's equivalent to `append b a`, and my result was in the wrong order. – rmunn Jun 03 '19 at 16:37
  • @rmunn. You're right. I'll correct. This definitely deserves a post. Its a bit of a trap until you get your head aroind it. – Craig.C Jun 11 '19 at 07:05
  • 1
    Now that it's edited and correct, it's a useful answer, so I've reversed my downvote to an upvote. – rmunn Jun 11 '19 at 11:15