Question

I have googlet a bit, and I haven't found what I was looking for. As expected. My question is, is it possible to define a F# pipeline placeholder? What I want is something like _ in the following:

let func a b c = 2*a + 3*b + c

2 |> func 5 _ 6

Which would evaluate to 22 (2*5 + 3*2 + 6).

For comparison, check out the magrittr R package: https://github.com/smbache/magrittr

Was it helpful?

Solution

This is (unfortunately!) not supported in the F# language - while you can come up with various fancy functions and operators to emulate the behavior, I think it is usually just easier to refactor your code so that the call is outside of the pipeline. Then you can write:

let input = 2
let result = func 5 input 6

The strength of a pipeline is when you have one "main" data structure that is processed through a sequence of steps (like list processed through a sequence of List.xyz functions). In that case, pipeline makes the code nicer and readable.

However, if you have function that takes multiple inputs and no "main" input (last argument that would work with pipelines), then it is actually more readable to use a temporary variable and ordinary function calls.

OTHER TIPS

I don't think that's possible, but you could simply use a lambda expression, like

2 |> (fun b -> func 5 b 6)

Here's a point-free approach:

let func a b c = 2*a + 3*b + c
let func' = func 5 >> (|>) 6
let result = 2 |> func'
// result = 22

I have explained it in details here.

Be aware, however, that someone who would work with your code will not quickly grasp your intent. You may use it for purposes of learning the deeper aspects of the language, but in real-world projects you will probably find a straightforward approach suitable better:

let func' b = func 5 b 6

You could use a new function like that:

let func a b c = 2*a + 3*b + c
let func2 b = func 5 b 6

2 |> func2

@Dominic Kexel's right on the money. If the object isn't really the placement of a placeholder in the chain of arguments, which could have been achieved by a lambda function, but changing their order, then it's more a case of flip than pipe.

From the simple two-argument case

let flip f b a = f a b
// val flip : f:('a -> 'b -> 'c) -> b:'b -> a:'a -> 'c

we need to derive a function

let flip23of3 f a c b = f a b c
// val flip23of3 : f:('a -> 'b -> 'c -> 'd) -> a:'a -> c:'c -> b:'b -> 'd

in order to flip the second and third argument. This could have also been written

let flip23of3' f = f >> flip

let func a b c = 2*a + 3*b + c
2 |> flip23of3 func 5 6
// val it : int = 22

I have given it a try myself. The result is not perfect, but it is as close as I have gotten:

let (|.|) (x: 'a -> 'b -> 'c) (y: 'b) = fun (a: 'a) -> x a y

let func (a:string) b (c:int) = 2.*(float a) + b + 5.*(float c)

let foo = func "4" 9. 5
printfn "First: %f" foo

let bar =
    "4"
    |> ((func |.| 9.) |.| 5)

printfn "Second: %f" bar

let baz =
    9.
    |> (func "4" |.| 5)
printfn "Third: %f" baz

The output is, as expected

First: 42.000000
Second: 42.000000
Third: 42.000000
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top