BBH1023
BBH1023

Reputation: 515

F# pattern match to a range of numbers

I have a function getFullFitness

let getFullFitness population = 
     ResizeArray(population |> Seq.map snd) |> Seq.sum

and I pattern match in the function realTick

let realTick population = 
    match(getFullfitness population) with
    |(50) -> population
    | _ -> childGeneration population

Question is on the line |(50) -> population. Since getFullFitness returns an integer sum, how do i match values between 0 and 50 in realTick?

Upvotes: 5

Views: 6009

Answers (3)

user3841986
user3841986

Reputation:

If you are choosing between two ranges of numbers like in your example, I would just use a if-then-else expression:

let realTick population =
  let fitness = getFullFitness population
  if 0 <= fitness && fitness <= 50 then
    population
  else
    childGeneration population

or a simple guard:

let realTick population =
  match getFullFitness population with
   | fitness when 0 <= fitness && fitness <= 50 ->
     population
   | _ ->
     childGeneration population

If your actual choice is much more complicated, then you might want to use active patterns. Unlike @pad, I would use a parameterized active pattern:

let (|BetweenInclusive|_|) lo hi x =
  if lo <= x && x <= hi then Some () else None

let realTick population =
  match getFullFitness population with
   | BetweenInclusive 0 50 ->
     population
   | _ ->
     childGeneration population

One higher-order active pattern I've found occasionally useful is a general purpose predicate:

let (|Is|_|) predicate x =
  if predicate x then Some () else None

Using Is you could write something like this:

let lessEq lo x = x <= lo
let greaterEq hi x = hi <= x

let realTick population =
  match getFullFitness population with
   | Is (greaterEq 0) & Is (lessEq 50) ->
     population
   | _ ->
     childGeneration population

Note that, while something like this is overkill in a simple example like this, it can be convenient in more complicated scenarios. I personally used active patterns similar to this to implement a simplification pass in an optimizing compiler that pattern matched over a large number of cases of primitive operations and properties of the parameters given to those primitives.

Upvotes: 10

pad
pad

Reputation: 41290

In F#, a recommended way to pattern match on ranges is to use active patterns. If we carefully manipulate pattern names, it will look quite close to what we want:

let (|``R0..50``|_|) i =
    if i >= 0 && i <= 50 then Some() else None

let realTick population = 
    match(getFullfitness population) with
    | ``R0..50`` -> population
    | _ -> childGeneration population

Pattern matching on ranges is supported in OCaml, but it's unlikely to be added to F#. See the related User Voice request at http://fslang.uservoice.com/forums/245727-f-language/suggestions/6027309-allow-pattern-matching-on-ranges.

Upvotes: 10

John Palmer
John Palmer

Reputation: 25516

One way is to use a guard -

|t when t < 50 -> ...

Upvotes: 17

Related Questions