ExcelDna F# and optional arguments - f#

For scalar (i.e. non array-like) optional arguments, I would use this pattern :
[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test1 ([<ExcelArgument(Description= "Optional. This is a double. Default is 42.0.")>] arg1 : obj) : double =
match arg1 with
| :? ExcelMissing -> 42.0 // the argument was missing
| :? double as d -> d // the argument was a double
| _ -> -1.0 // otherwise
I am not sure if this code is "idiomatic" within Excel-Dna / F# but it seems to "work".
However I am not sure how to proceed for optional array-like arguments. Eg :
[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test2 ([<ExcelArgument(Description= "Optional. This is a double. Default is [42, 42].")>] arg1 : obj[]) : double[] =
match arg1.[0] with
| :? ExcelMissing -> [42.0; 42.0] |> List.toArray // the argument was missing OR it was an empty array
| :? double as d -> arg1 |> castToDouble // the argument was an array and its first argument was a double
| _ -> Array.empty // otherwise
The above seems to work for most cases but does not allow to handle the edge-cases properly : eg if arg1 is an empty array. (castToDouble being a custom obj[] -> double[] conversion function)
What would be the right / idiomatic way to handle optional double arrays in F# / Excel-Dna and how could I then rewrite test_test2?
=========== EDIT ===
Following Govert's advice, I tried the following :
[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test3 ([<ExcelArgument(Description= "Optional. This is a double. Default is [42, 42].")>] arg1 : obj) : double[] =
match arg1 with
| :? (double[]) as ds -> [1.0; 2.0] |> List.toArray // the argument was a array of double elements
| :? ExcelMissing -> [42.0; 42.0] |> List.toArray // the argument was missing OR it was an empty array
| _ -> Array.empty // otherwise
... but unfortunately I get a #NUM! output when I pass an array of doubles (or of anything else). It's only when I pass nothing that I correctly get the [42.0, 42.0] array.

This covers all the possibilities:
[<ExcelFunction("describes the input argument")>]
let describe(arg1 : obj) : string =
match arg1 with
| :? double as d -> sprintf "Double: %f" d
| :? string as s -> "String: " + s
| :? bool as b -> sprintf "Boolean: %b" b
| :? ExcelError as err -> sprintf "ExcelError: %A" err
| :? (obj[,]) as arr -> sprintf "Array[%i, %i]" (Array2D.length1 arr) (Array2D.length2 arr)
| :? ExcelEmpty -> "<<Empty>>"
| :? ExcelMissing -> "<<Missing>>"
| _ -> "!? Unheard of ?!"

Related

F#: pattern matching on base types

I have a series of validation functions I want to put into an array to execute:
type result = {D: int; E: int; F: int; G: int}
type InvalidReason =
| AAA
| BBB
| CCC
| DDD
| EEE
type Validation =
| Valid
| Invalid of InvalidReason
let validators = [|AAA; BBB; CCC; DDD; EEE|]
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.contains(Validation.Invalid _)
The problem is that last line of code. I am getting an "Unexpected value _ in the expression." The following does work
|> Array.contains(Validation.Valid)
|> Array.contains(Validation.Invalid InvalidReason.AAA)
But I don't want to spell out each of the sub types for InvalidReasons. Is there some syntax I am overlooking?
The function Array.contains takes a value and checks if that value is in the array. What you're trying to do is to give it a whole bunch of values to check. Well, this won't work: the function only takes one. And it doesn't help that there is no syntax like that in F# :-)
You might use another function that takes multiple values, but a better way to accomplish what you want is to use a function that takes a predicate - Array.exists. Make yourself a predicate to check if a value is "invalid":
let isInvalid x = match x with
| Valid -> false
| Invalid _ -> true
And pass it to Array.exists:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists isInvalid
Or you could even put that function inline:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( fun x -> match x with
| Valid -> false
| Invalid _ -> true )
Or even shorter, using the function keyword:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( function | Valid -> false | Invalid _ -> true )
Or even shorter, getting rid of as much noise as possible:
let validateStuff result =
validators
|> Array.map(fun v -> v result)
|> Array.exists ( function Invalid _ -> true | _ -> false )

How to convert generic Discriminated Union to obj

Given a DU like
type Result<'a, 'b> = Ok of 'a | Error of 'b
and some functions
let doA () = Ok true
let doB () = Error <| exn "Fail"
let doC = function | 1 -> Ok "one" | x -> Error x
How do you define a function to cast the value?
toObjResult : x:obj -> Result<obj, obj> //where x is guaranteed to be Result<'a,'b>
Usage
let data =
[ doA() |> box
doB() |> box
docC 1 |> box
docC 2 |> box ]
|> List.map toObjResult
All attempts so far restrict the types of 'a and 'b to be obj
let toObjResult (x:obj) =
match x with
| :? Result<'a, 'b> as r ->
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
| _ -> Error <| (exn "Invalid type" |> box)
resulting in errors like
System.InvalidCastException: Unable to cast object of type 'Ok[System.Boolean,System.Object]' to type 'Result`2[System.Object,System.Object]'.
There is no way to do this without using reflection, enumerating all types, or modifying the type.
Using reflection can be slow, but lets you do what you want (see [the GenericType active pattern from this answer) and the answer from #robkuz shows how you can do this by listing all the cases that you want to cover - the problem is that this does not scale well.
Finally, if you were happy to modify your Result<'a, 'b> type, you could add a non-generic interface that lets you get the value as a boxed value:
type IBoxedResult =
abstract Boxed : Result<obj, obj>
and Result<'a, 'b> =
| Ok of 'a
| Error of 'b
interface IBoxedResult with
member x.Boxed =
match x with
| Ok v -> Ok (box v)
| Error v -> Error (box v)
Now you can cast obj to IBoxedResult and use Boxed to get the value as Reslt<obj, obj>:
[ box (Ok true)
box (Ok 1) ]
|> List.map (fun o -> (o :?> IBoxedResult).Boxed)
You have to match on the exact generic type params of your Result type in your matching expression
let matchR r =
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
let toObjResult (x:obj) =
match x with
| :? Result<bool, _> as r -> matchR r
| :? Result<string, int> as r -> matchR r
| :? Result<_, Exception> as r -> matchR r
| _ -> Error (box "Invalid type" )
sadly you can't match on unrealised type params (which is really bad)

Strange (?) type mismatch error in this function

Can someone explain why compiler is giving me this error
Type mismatch. Expecting a
'a [] -> string
but given a
'a [] -> 'a []
The type 'string' does not match the type ''a []'
on this code snippet:
let rotate s: string =
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
while the one below compiles just fine:
let s = "string"
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
Your first snippet defines function rotate with return type of string.
Try to change it to:
let rotate (s: string) =
[|for c in s -> c|]
|> Array.permute (function | 0 -> (s.Length-1) | i -> i-1)
In this form you define a function with one string argument (I suppose that's what you wanted) and inferred return type.

F# trying to create a better printf

I'm trying to create a print statement that can print any type. I want to use type pattern matching to achieve this.
This doesn't work:
let print x = match x with | :? int -> printf "INT"; | _ -> None;;
I get the message:
let print x = match x with | :? int -> printf "INT"; | _ -> None;;
-----------------------------^^^^^^
stdin(47,30): error FS0008: This runtime coercion or type test from
type
'a to
int involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types.
Further type annotations are needed.
So, i can't do type matching on an int? What other types can i not do type matching on? What does it mean that further type annotations are needed?
Type test is performed on reference types only. Therefore:
let print x =
match box x with
| :? int -> printf "INT"
| _ -> ()
or
let print (x: obj) =
match x with
| :? int -> printf "INT"
| _ -> ()
would work.
Notice that your function doesn't type check since None is of option type which is different from unit type of printf "INT".

F# Quotations - traversing into function calls represented by a Value

I've spent a few hours trying to get to grips with F# Quotations, but I've come across a bit of a road block. My requirement is to take simple functions (just integers,+,-,/,*) out of a discriminated union type and generate an expression tree that will eventually be used to generate C code. I know this is possible using Quotations with 'direct' functions.
My problem is that the expression tree seems to terminate with a "Value", and I can't figure out how to traverse into that value.
My questions is
whether this is actually possible in this situation? or are there any other approaches that are worth considering.
type FuncType =
| A of (int -> int -> int)
| B
| C
[<ReflectedDefinition>]
let add x y = x + y
let myFunc1 = A (fun x y -> x + y )
let myFunc2 = A add
let thefunc expr =
match expr with
| A(x) ->
<# x #>
| _ ->
failwith "fail"
printfn "%A" (thefunc myFunc1) // prints "Value (<fun:myFunc1#14>)"
printfn "%A" (thefunc myFunc2) // prints "Value (<fun:myFunc2#15>)"
printfn "%A" <# fun x y -> x + y #> // generates usable expression tree
Quotations represent the F# code that was quoted syntactically. This means that if you write something like <# x #>, the quotation will contain just Value case specifying that you quoted something which has the specified value. (Variables are automatically replaced with values if the variable is defined outside of the quotation).
You can only get quotation of code that was explicitly quoted using <# .. #> or of a function that was marked as ReflectedDefinition and is referred to by name in a quotation (e.g. <# add #> but not for example let f = add in <# f #>).
To be able to do what your snippet suggests, you'll need to store quotations in your FuncType too (so that the lambda function that you write is also quoted and you can get its body). Something like:
type FuncType =
| A of Expr<int -> int -> int>
| B | C
[<ReflectedDefinition>]
let add x y = x + y
let myFunc1 = A <# fun x y -> x + y #>
let myFunc2 = A <# add #>
let thefunc expr =
match expr with
| A(x) -> x
| _ -> failwith "fail"
This should work for functions marked as ReflectedDefinition too. To extract the body of the function you need to add something like (you'll need to substitute arguments of the function for parameters, but this should give you some idea):
match expr with
| Lambdas(_, body) ->
match body with
| Call(_, mi, _) when Expr.TryGetReflectedDefinition(mi) <> None ->
let func = Expr.TryGetReflectedDefinition(mi)
match func with
| Some(Lambdas(_, body)) ->
// 'body' is the quotation of the body
| _ -> failwith "Not supported function"
| _ -> failwith "Not supported function"
| _ -> failwith "Not supported expression"

Resources