Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern match a function in F#

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?

like image 745
unknown6656 Avatar asked Aug 30 '16 17:08

unknown6656


People also ask

What is pattern matching in F#?

Pattern matching is ubiquitous in F#. It is used for binding values to expressions with let , and in function parameters, and for branching using the match..with syntax.

Is pattern matching a function?

Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns. When defining functions, you can define separate function bodies for different patterns.

What is pattern matching give an example?

For example, x* matches any number of x characters, [0-9]* matches any number of digits, and . * matches any number of anything. A regular expression pattern match succeeds if the pattern matches anywhere in the value being tested.

Which command is for pattern matching?

Pattern matching is used by the shell commands such as the ls command, whereas regular expressions are used to search for strings of text in a file by using commands, such as the grep command.


1 Answers

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"
like image 58
Reed Copsey Avatar answered Feb 07 '23 12:02

Reed Copsey