Reputation: 2459
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
Upvotes: 6
Views: 681
Reputation: 243126
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.
Upvotes: 6
Reputation: 5751
@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
Upvotes: 0
Reputation: 6382
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
Upvotes: 1
Reputation: 7735
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
Upvotes: 1
Reputation: 2459
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
Upvotes: -1
Reputation: 101142
I don't think that's possible, but you could simply use a lambda expression, like
2 |> (fun b -> func 5 b 6)
Upvotes: 2