8

Here's code that works fine:

let f x y z = x + y + z

let g x y = f x y
let h x z = z |> f x

So I can write expression "h 1", and FSI displays:

val it : (int -> int -> int) = <fun:it@110-3>

If I call "h 1 2 3", the arguments are applied in the right order.
But if the last argument has a different type, things get different:

let ff x y (z : string) = x + y

let gg x y = ff x y
let hh x (z : string) = z |> ff x

Now the last function hh causes an error message:

Script.fsx(119,10): error FS0001: Type mismatch. Expecting a string -> 'a but given a int -> string -> int. The type string does not match the type int

I understand why this happens - "z" is appended to "ff x" making it a second argument. But then I'd expect in the first example expression "h 1 2 3" not to work properly (being executed as "f 1 3 2"). But it works just fine.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
Vagif Abilov
  • 9,835
  • 8
  • 55
  • 100
  • 1
    Are you sure `h 1 2 3` executes as `f 1 2 3` and not `f 1 3 2`? After all, 1+2+3 == 1+3+2 == 6. Maybe try with a non-transitive operator? – tzaman Jul 07 '10 at 13:11
  • FWIW, OCaml's labelled arguments allow you to partially apply out of order. – J D Jul 08 '10 at 23:28

1 Answers1

9

The functions ff and gg in your example are the same - the pipelining operator provides value for a first argument of a function on the right-hand side. In your example, the function on the right hand side is ff x and by using the pipelining operator, you specify the value for argument y:

let ff x y (z : string) = 
  printfn "%s" z
  x + y

// These two functions are the same:
let gg x y = ff x y
let hh x y = y |> ff x

There is no stnadard syntax for specifying other than first parameters when using partial function application. However, you can write a higher-order function or a custom operator to do that. For example:

// Takes a function 'f' of type 'b -> 'a -> 'c
// and a value 'v' of type 'a and creates a function
// that takes the first argument ('b -> 'c)
let (|*>) v f = (fun mid -> f mid v);;

let gg x y = ff x y     // Specifies arguments x and y
let hh x z = z |*> ff x // Specifies arguments x and z

I named the operator |*> to denote that it skips one argument. You could define operators that specify value of other arguments similarly (e.g. |**> to skip the first two arguments).

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Tomas, thank you for the answer. Use of custom operator seems to be a way to go! – Vagif Abilov Jul 07 '10 at 14:38
  • 1
    I think you have the arguments backward in that operator. I think it should be (fun last -> f v last). Also, function application take precedence over operators, so that last line should be: (z |*> ff) x Try testing this with subtraction or division, rather than addition. – YotaXP Jul 07 '10 at 16:10
  • @YotaXP: Both of the things you mentioned are intentional. If you wrote the operator the way you describe (e.g. `fun last -> f v last`) you wouldn't need lambda function at all, because that would be equivalent to just `f v` - which would be standard `|>` operator. Regarding the second point - the intention is that whne you write `z |*> ff x`, you specify `z` as the second argument of a function `ff x` (and the first argument remains to be specified). In other words, `z |*> ff x` is equivalent to `fun a -> ff x a z`. – Tomas Petricek Jul 07 '10 at 16:47
  • @YotaXP: Perhaps we understand the original question differently? – Tomas Petricek Jul 07 '10 at 16:48
  • 1
    It would be nice to have a standard set of operators for this type of thing, or at least an agreed-upon nomenclature for constructing such operators on the fly. – TechNeilogy Aug 01 '10 at 14:03