Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting a tuple inline as parameters to a function with non-tuple arguments

Tags:

f#

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. :)

like image 309
McMuttons Avatar asked Jun 07 '13 10:06

McMuttons


4 Answers

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))

like image 87
Ramon Snir Avatar answered Oct 09 '22 03:10

Ramon Snir


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
like image 30
Lee Avatar answered Oct 09 '22 03:10

Lee


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
like image 3
Leaf Garland Avatar answered Oct 09 '22 04:10

Leaf Garland


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)
like image 2
Tomas Petricek Avatar answered Oct 09 '22 04:10

Tomas Petricek