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

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"

Related

Injecting a variable definition into F# quotation

I have a custom variable definition, that I want to insert into a quotation. Is it even possible with the quotations syntax sugar?
What I wanted to do:
open Microsoft.FSharp.Quotations
let var = Var("myvar", typeof<int>)
let op = <## fun l -> match l with
| [] -> 0
| %%myvar :: _ -> ... ##>
I've also tried <## let %%myvar = ... ##> with a similar purpose.
In both cases I got FS0010 "Unexpected prefix operator in binding", or "... in pattern matching".
Is there a way to inject an existing Var like this? Or do I have to resort to manually generating the entire expression?
PS: I am using the whole thing to translate some other AST into an F# quotation.
What you describe in your question is really kind of nonsensical. You cannot splice a Var into an expression. Only a value of type Expr can be spliced. If you created an instance of Expr our of your var via the Expr.Var constructor, then the splicing would be possible:
let var = Expr.Var( Var("myvar", typeof<int>) )
let op = <## fun l -> %%var ##>
But this won't let you do what you're trying to do: you can't splice an expression in a pattern position (the left side of an arrow -> inside a match is what we call a "pattern", and so is the left side of equal sign = inside a let). You can only splice expressions, not other parts of the syntax. F# code quotations are not quite as free-for-all as Lisp macros or TemplateHaskell.
Admittedly, it is not entirely clear what you're actually trying to do.
One possibility of your true intent that comes to mind is this: you want to match this variable on the left side of the arrow ->, then pass it to some other function which would construct the right side of the arrow ->. Something like this:
let mkRightSide var = <## %%var + 42 ##>
let var = Expr.Var( Var("myvar", typeof<int>) )
let op = <## fun l -> match l with
| [] -> 0
| %%var :: _ -> %%(mkRightSide var) // Doesn't compile
##>
Which would yield the following quotation:
fun l -> match l with
| [] -> 0
| myvar :: _ -> myvar + 42
If this is your intent, then I suggest having mkRightSide return a function, which would simply take myvar as a parameter:
let mkRightSide = <## fun myvar -> myvar + 42 ##>
let op = <## fun l -> match l with
| [] -> 0
| (myvar:int) :: _ -> (%%mkRightSide) myvar ##>
The above would yield the following quotation:
fun l -> match l with
| [] -> 0
| myvar :: _ -> (fun myvar -> myvar + 42) myvar
Note 1: the type annotation on myvar is necessary because your quotations are untyped. Since mkRigthSide carries no type information, the compiler can't infer myvar to be int and makes it generic instead, which causes type mismatch when the splicing is attempted.
Note 2: the parentheses around (%%mkRightSide) are necessary. Without them, the compiler would understand it as %%(mkRightSide myvar), because function application has a higher priority than the %% operator.
If I am wrong in guessing your intent, please clarify it, and I'll be happy to amend the answer.

Simple closure function

I have following code
let f2 x:int =
fun s:string ->
match x with
| x when x > 0 -> printfn "%s" s
| _ -> printfn "%s" "Please give me a number that is greater than 0"
And the compiler complain:
Unexpected symbol ':' in lambda expression. Expected '->' or other token.
What am I doing wrong?
You have to put parentheses around your type annotations:
let f2 (x : int) =
fun (s : string) ->
match x with
| x when x > 0 -> printfn "%s" s
| _ -> printfn "%s" "Please give me a number that is greater than 0"
Also be aware if you omit the parentheses around x like in your example, this would mean the function f2 returns an int, not constrain the type of x to be int.
Update for the comment:
Why if I omit the parentheses around x, this would mean the function f2 returns an int?
Because that is how you specify the return type of functions.
What would be this in C#:
ReturnTypeOfFunction functionName(TypeOfParam1 firstParam, TypeOfParam2 secondParam) { ... }
would look like this in F#:
let functionName (firstParam : TypeOfParam1) (secondParam : TypeOfParam2) : ReturnTypeOfFunction =
// Function implementation that returns object of type ReturnTypeOfFunction
A more detailed explanation can be found on MSDN.
You have two instances of the same problem. When defining a function, putting :*type* at the end of the signature indicates that the function returns that type. In this case you're indicating that you have a function f2 which takes a parameter and returns an int. To fix it you need to put parenthesis around the annotation. That syntax doesn't work in a lambda, so you simply get a compile error instead.
Or let the compiler infer the types. Try this:
let f2 x =
fun s ->
match x with
| x when x > 0 -> printfn "%s" s
| _ -> printfn "%s" "Please give me a number that is greater than 0"

f# how to filter mixed data type for a specific type

I m trying to filter a mixed data type for a specific type, say float (ideally this would be dynamic though)
here my example:
let testobj = [8.0 , 1.0, "bla" ; 8.0 , 1.0, "bla"]
let testfun data = data |> List.filter (fun a ->
match a.GetType() with
| float -> a
| _ -> 0.0)
now this should return [8.0 , 1.0, 0.0 ; 8.0 , 1.0, 0.0] for testobj but I m gettting an error that the function is of type bool
This isn't what you want to do.
Seriously.
F# wants lists to be homogeneous and your list is not homogeneous. float and string don't share a common base class so you're not going to get a list from it.
What F# wants you to do is to use a discriminated union for this. So if you have this type:
type Composite =
| Num of float
| Str of string
you can define your list like this:
let data = [ Num(8.0); Num(1.0); Str("bla"); Num(8.0); Num(1.0); Str("bla") ]
and from there you can pattern match on the types and your function looks like this:
let testfun d = d |> List.map (fun a ->
match a with
| Num x -> a
| _ -> Num(0.0) )
data|> testfun |> printfn "%A"
And the output will be:
[Num 8.0; Num 1.0; Num 0.0; Num 8.0 ; Num 1.0 ; Num 0.0;]
If you want floats in the end and not Composites, do this:
let testfun1 d = d |> List.map (fun a ->
match a with
| Num x -> x
| _ -> 0.0 )
which sheds the composite type. And everything (and I mean everything) in that code is type strong and type-safe.
From a real-world maintenance point of view, I would eschew the _ case in the matches and instead use all my types, reasoning that if I extend Composite to include another type I would want the compiler to scream at me and look at each function that uses it rather than silently assuming that 0.0 or Num(0.0) is really what I wanted.
For example, if I added integers to that type, this would do exactly the wrong thing if I wanted to sum the contents of a list of composites.
Given that you're stuck/hell-bent on a weakly-typed data set, then you want something like this:
let testfun2 d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> x
| _ -> 0.0
)
let data:Object[] = [|8.0; 1.0; "bla"; 8.0; 1.0; "bla"|]
data |> testfun2 |> printfn "%A"
which will print what you expect. Note that I'm using proper Array syntax and not list syntax.
However this is feeling really wonky for F#. See how I have to adorn a and d with types? In my previous code, the language can figure it all out. If I don't adorn either, I get compiler errors because we're really going against the grain of the type system.
If I were you, I would be inclined to do something like this first:
let recast d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> Num x
| :? string as x -> Str x
| _ -> raise (ArgumentException("that was unexpected: " + a.GetType().Name))
)
which turns this into an Array of Composite which is now type strong. If you tack on |> Array.toList after the Array.map, you get a list (if you want that).

How to flatten input of mixed 'T and seq<'T> into single seq<'T>

I need a function that could take an arbitrary number of arguments, each could be either of type 'T or seq<'T>. Inside the function I need to process it as a single seq<'T> with all inputs combined in the same order as they sere supplied.
The obvious way was to have something like:
module Test =
let flatten ([<ParamArray>] args) =
let flat = seq {
for a in args do
match box a with
| :? int as x -> yield x
| :? seq<int> as sq ->
for s in sq do
yield s
| _ -> failwith "wrong input type"
}
flat // this should be seq<int>
but I cannot make it work in FSI even with the simplest case
let fl = Test.flatten 1;;
----------------------^
...: error FS0001: The type 'int' is not compatible with the type 'seq<'a>'
What is wrong here and how to get it work as needed? Probably this could be done in some completely different way?
From msdn :
In F#, parameter arrays can only be defined in methods. They cannot be
used in standalone functions or functions that are defined in
modules.
So instead of a module, declare a type with a static method.
open System
type Test() =
static member flatten ([<ParamArray>] args: obj[]) =
let flat = seq {
for a in args do
match box a with
| :? int as x -> yield x
| :? seq<int> as sq ->
for s in sq do
yield s
| _ -> failwith "wrong input type"
}
flat
If you have other let bindings you can still declare a module with the same name.
Also note that in the second guard of the match you can avoid the for loop by doing:
| :? seq<int> as sq -> yield! sq
And box is not required.

Is it possible to differentiate between typed and untyped nested quotations?

For example, given <# let x = <# 1 #> in x #> and <# let x = <## 1 ##> in x #>, I can match both with Patterns.Let(_, (Patterns.Quote(_) as q), _) -> q but I can't differentiate between the typed and untyped q.
Interesting. It seems that quotations are always stored in the typed form.
The type of the <## 1 ##> sub-expression inside the quotation is always Expr<int>. However, the type of the variable x differs in your two quotations:
match q1 with
| Patterns.Let(v, (Patterns.Quote(_) as q), _) when v.Type = typeof<Expr> -> "untyped"
| Patterns.Let(_, (Patterns.Quote(_) as q), _) -> "typed"
| _ -> "other"
But I'm not sure how to use this to differentiate between the two cases in general. It seems that you can only do that if you look at the context (and there are just too many possible context...)

Resources