LA.27
LA.27

Reputation: 2248

Going more idiomatic with F#

A very simple example of what I'm trying to do: I know it's possible to write:

let myFunc = anotherFunc

instead of

let myFunc = fun x -> anotherFunc x

I've got two functions fDate1, fDate2 - both of type DateTime -> bool. I need to construct a function that takes a date and verifies if any of fDate1, fDate2 returns true. For now I've invented the following expression:

let myDateFunc = fun x -> (fDate1 x) || (fDate2 x)

Is there a better way of doing these (e.g. using '>>' or high order funcions) ?

Upvotes: 3

Views: 311

Answers (3)

Be Brave Be Like Ukraine
Be Brave Be Like Ukraine

Reputation: 7735

As other answers say, your current approach is fine. What is not said is that idiomatic style often produces less readable code. So if you are working in a real project and expect other developers to understand your code, it is not recommended to go too far with unnecessary function composition.

However, for purposes of self-education, you may consider the following trick, a bit in FORTH style:

// Define helper functions
let tup x = x,x
let untup f (x,y) = f x y
let call2 f g (x,y) = f x, g y

// Use
let myFunc =
    tup
    >> call2 fDate1 fDate2
    >> untup (||)

Here, you pass the original value x through a chain of transformations:

  • make a tuple of the same value;
  • apply each element of the tuple to corresponding function, obtaining a tuple of results;
  • "fold" a tuple of booleans with or operator to a single value;

There are many drawbacks with this approach, including that both of fDate1 and fDate2 will be evaluated while it may not be necessary, extra tuples created degrading performance, and more.

Upvotes: 1

Tomas Petricek
Tomas Petricek

Reputation: 243126

I don't think there is anything non-idiomatic with your code. In my opinion, one of the strong points about F# is that you can use it to write simple and easy-to-understand code. From that perspective, nothing could be simpler than writing just:

let myDateFunc x = fDate1 x || fDate2 x

If you had more functions than just two, then it might make sense to write something like:

let dateChecks = [ fDate1; fDate2 ]
let myDateFunc x = dateChecks |> Seq.exists (fun f -> f x)

But again, this only makes sense when you actually need to use a larger number of checks or when you are adding checks often. Unnecessary abstraction is also a bad thing.

Upvotes: 8

pad
pad

Reputation: 41290

You can define a choice combinator:

let (<|>) f g = fun x -> f x || g x

let myDateFunc = fDate1 <|> fDate2

In general, you should use explicit function arguments. The elaborated form of myDateFunc can be written as:

let myDateFunc x = fDate1 x || fDate2 x

Upvotes: 4

Related Questions