While trying to grasp the potentials of the collection features in F#, I encountered this one:

let needSpecialDocument country = (not country.IsEea) && (not country.IsInSchengen) 
// could also be: not (country.IsEea || country.IsInSchengen)
let wantToMoveTo country = country.Name = "CC"

let potentialDestinations =
    |> Seq.filter needSpecialDocument2
    |> Seq.filter wantToMoveTo

Is there a way to combine the two filters into one? I managed the one below but it feels like there is a more fsharpish way to do so..

|> Seq.filter (fun c -> (needSpecialDocument c) && (wantToMoveTo c))

Test data:

type Country = {Name : string; IsEea : bool; IsInSchengen : bool}
let uk = {Name = "UK"; IsEea = false; IsInSchengen = false}
let ir = {Name = "IR"; IsEea = true; IsInSchengen = false}
let fr = {Name = "FR"; IsEea = true; IsInSchengen = true}
let ch = {Name = "CH"; IsEea = false; IsInSchengen = true}
let cc = {Name = "CC"; IsEea = false; IsInSchengen = false}
let countries = [uk;ir;fr;ch;cc]

Nope, that's pretty much the way.

If you really, really want to make this shorter and less cluttered, and if you face similar situations multiple times in your codebase, you could make yourself a special operator for combining predicates:

let (.&&.) f g c = f c && g c

Then you can use this operator in your filter:

|> Seq.filter (needSpecialDocument .&&. wantToMoveTo)

But base on my own experience I wouldn't advise this. You make the program slicker and cooler looking, but you're losing some readability. Now whoever reads your program will have to look up the meaning of .&&.. Programs are read more often than they are written.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.