6
votes

I have an maybe unusual question, but how does one match a function in F# using pattern matching?

Imagine the following:
I have multiple function signatures, which will be used multiple times, like:

binary function:  int -> int -> int
unary function:   int -> int
boolean function: int -> int -> bool
...

Now imagine the function evaluate, which itself takes a function f. The signature of f must be one of the listed above. How do I match such a case?


I have tried the following things:
Test No.1 : Using delegates and Unions:

type UnaryFunction = delegate of int -> int
type BinaryFunction = delegate of (int -> int) -> int
type BooleanFunction = delegate of (int -> int) -> bool

type Functions =
    | Unary of UnaryFunction
    | Binary of BinaryFunction
    | Boolean of BooleanFunction

// ...

let evaluate f = // signature: Functions -> string
    match f with
    | Unary u ->
        let test_result = u.Invoke 3
        sprintf "the result of the unary function is %d" test_result
    | Binary b ->
        let test_result = b.Invoke 315 42
        sprintf "the result of the binary function is %d" test_result
    | Boolean o ->
        let test_result = o.Invoke 315 42
        if test_result then "yeah" else "nope"

Test No.2 : Using type pattern matching and delegates:

type UnaryFunction = delegate of int -> int
type BinaryFunction = delegate of (int -> int) -> int
type BooleanFunction = delegate of (int -> int) -> bool

let evaluate f =
    match f with
    | ?: UnaryFunction as u ->
        let test_result = u.Invoke 3
        sprintf "the result of the unary function is %d" test_result
    | ?: BinaryFunction as b ->
        let test_result = b.Invoke 315 42
        sprintf "the result of the binary function is %d" test_result
    | ?: BooleanFunction as o ->
        let test_result = o.Invoke 315 42
        if test_result then "yeah" else "nope"
    | _ -> "invalid function type"


The problem with these examples is, that delegates of ... will be matched instead of actual functions. I would like to see somethink like this:
let evaluate f =
    match f with
    | ?: (int -> int) as u ->
        let test_result = u 3
        sprintf "the result of the unary function is %d" test_result
    | ?: ((int -> int) -> int) as b ->
        let test_result = b 315 42
        sprintf "the result of the binary function is %d" test_result
    | ?: ((int -> int) -> bool) as o ->
        let test_result = o 315 42
        if test_result then "yeah" else "nope"
    | _ -> "invalid function type"

Does F# has a special syntax for function pattern matching?
And if not, why so? Am I missing something, or isn't it also important to be able to match functions just as anything else, as this is a functional language?

1
Why do you need to use delegates instead of functions? - Fyodor Soikin
@FyodorSoikin: I tried it previously, but due to a typo (which I did not realize at that time), I could not defined types as functions. I therefore thought that it was impossible :/ - unknown6656

1 Answers

10
votes

Instead of using delegates, just define the work using functions directly:

type UnaryFunction = int -> int
type BinaryFunction = int -> int -> int
type BooleanFunction = int -> int -> bool

type Functions =
    | Unary of UnaryFunction    
    | Binary of BinaryFunction
    | Boolean of BooleanFunction

// ...

let evaluate f = // signature: Functions -> string
    match f with
    | Unary u ->
        let test_result = u 3
        sprintf "the result of the unary function is %d" test_result
    | Binary b ->
        let test_result = b 315 42
        sprintf "the result of the binary function is %d" test_result
    | Boolean o ->
        let test_result = o 315 42
        if test_result then "yeah" else "nope"

Once you've done this, you can call them as needed (as below, showing FSI output):

> evaluate (Unary (fun x -> x + 3));;
val it : string = "the result of the unary function is 6"

> let someBinaryFunction x y = x * y;;
val someBinaryFunction : x:int -> y:int -> int

> Binary someBinaryFunction |> evaluate;;
val it : string = "the result of the binary function is 13230"