scalaf#partialfunction

Scala's notion of "partial functions"' & the ".orElse" method in F#


In Scala there's the notion of a "partial function" that is fairly similar to what F#'s function keyword allows me to achieve. However Scala's partial functions also allow for composition via the orElse method as shown below:

def intMatcher: PartialFunction[Any,String] = {
  case _ : Int => "Int"
}

def stringMatcher: PartialFunction[Any,String] = {
  case _: String => "String"
}

def defaultMatcher: PartialFunction[Any,String] = {
  case _ => "other"
}

val msgHandler =
  intMatcher
  .orElse(stringMatcher)
  .orElse(defaultMatcher)

msgHandler(5) // yields res0: String = "Int"

I need to know if there's a way to achieve the same composition functionality in F#.


Solution

  • The way you wrote it in Scala is equivalent to using extension methods in C#. It is not particularly idiomatic to functional programming. To strictly use composable functions in F# you might do something like this.

    // reusable functions
    let unmatched input = Choice1Of2 input
    
    let orElse f =
        function
        | Choice1Of2 input -> f input
        | Choice2Of2 output -> Choice2Of2 output
    
    let withDefault value =
        function
        | Choice1Of2 _ -> value
        | Choice2Of2 output -> output
    
    // problem-specific functions
    let matcher isMatch value x =
        if isMatch x then Choice2Of2 value
        else Choice1Of2 x
    
    let isInt (o : obj) = o :? int
    let isString (o : obj) = o :? string
    
    let intMatcher o = matcher isInt "Int" o
    let stringMatcher o = matcher isString "String" o
    
    // composed function
    let msgHandler o =
        unmatched o
        |> orElse intMatcher
        |> orElse stringMatcher
        |> withDefault "other"
    

    Here, Choice1Of2 means that we haven't found a match yet and contains the unmatched input. And Choice2of2 means we found a match and contains the output value.