5
votes

I've got a function that takes two parameters, for example:

let f a b = a = b

Then I have a second function that returns a tuple:

let g = (a, b)

I want to pass in a and b in the tuple from g as parameters to f in one line. I could do it in two statements, but the reason I want to do this is that my calling function does an or and I'd rather not call f unless the first case is false, to save on unnecessary processing.

let calling =
  someboolean || 
  f g // want to split result of g to parameters for f without calling g twice

Any tips on how to do this? I know I could have f take a tuple instead, but I'd like to retain the option for currying.

I hope I explained this well enough. :)

4
Here's a nice, organized reference list of F# symbols and operators, if you need more info about the other answers - Jwosty
I would have marked several answers if I could, but I picked what I thought was the most elegant solution to the particular question. That said, I think Thomas's suggestion about refactoring the the f and g calls is probably the most "correct". Thanks all! - McMuttons

4 Answers

8
votes

You can also do:

let calling = someBoolean || g ||> f

Because:

(||>) : ('a * 'b -> ('a -> 'b -> 'c) -> 'c)

(And similarly (|||>) : ('a * 'b * 'c -> ('a -> 'b -> 'c -> 'd) -> 'd))

5
votes

You can define a function which converts a curried function into one which takes a pair argument:

uncurry f (a, b) = f a b

let calling = someBoolean || (uncurry f) g
3
votes

You can extract from the tuple inline, you'll still get the benefit of the short-circuiting.

let calling = someBoolean || let a,b = g in f a b
2
votes

As already mentioned, you could define the uncurry combinator to convert function taking two arguments into a function taking tuple.

However I'd recommend not doing that - that style of programming is not really idiomatic in F# (unlike, say, in Haskell) and I think it makes code hard to read, debug and maintain.

So, what to do instead?

  • If the two values logically belong together (represent some entity used elsewhere in your code) then change f to take a tuple too.

  • If they are just two values, then use let and pattern matching to decompose the tuple. This will be longer, but you'll have to name the components, which will improve readability.

In your sample g is actually a value so you can write just:

let someThing, otherThing = g
boolThing || (f someThing otherThing)