File and line numbers in F# code quotations - f#

Is there a way to extract the file name and line number from code quotation so that we may add add debug information for transformations of the quoted code. Any alternative ways?

Try something like this:
let sourceInfo (e:Quotations.Expr) =
let (|Val|_|) e : 't option =
match e with
| Quotations.Patterns.Value(:? 't as v,_) -> Some v
| _ -> None
let (|Tup|_|) = Quotations.Patterns.(|NewTuple|_|)
e.CustomAttributes
|> List.tryPick (function | Tup [Val("DebugRange")
Tup [Val(file:string)
Val(startLine:int)
Val(startCol:int)
Val(endLine:int)
Val(endCol:int)]]
-> Some(file,startLine,startCol,endLine,endCol)
| _ -> None)
sourceInfo <# "test" #>

This is now built into F#
https://msdn.microsoft.com/en-us/library/dd233234.aspx
__LINE__
__SOURCE_DIRECTORY__
__SOURCE_FILE__

Related

How can I use TryParse in a guard expression in match?

I have built a toy spreadsheet to help learn F#. When I process the text for a new cell I store it as a discriminated type. To parse it I feel I should be able to do something like:
let cv =
match t with
| _ when t.Length=0 -> Empty
| x when t.[0]='=' -> Expr(x)
| x when t.[0]='\"' -> Str(x)
| (true,i) when Int32.TryParse t -> IntValue(i) // nope!
| _ -> Str(t)
I have tried quite a few combinations but I cannot get TryParse in the guard. I have written a helper:
let isInt (s:string) =
let mutable m:Int64 = 0L
let (b,m) = Int64.TryParse s
b
I can now write:
| _ when Utils.isInt t -> IntValue((int)t)
This seems like a poor solution as it discards the converted result. What the correct syntax to get TryParse into the guard?
I think an active pattern will do what you want:
let (|Integer|_|) (str: string) =
let flag, i = Int32.TryParse(str)
if flag then Some i
else None
let cv =
match t with
| _ when t.Length=0 -> Empty
| x when t.[0]='=' -> Expr(x)
| x when t.[0]='\"' -> Str(x)
| Integer i -> IntValue(i)
| _ -> Str(t)
But if you really want TryParse in the guard condition (and you don't mind parsing twice), you could do this:
| x when fst (Int32.TryParse(t)) -> IntValue (Int32.Parse(x))

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.

Pattern matching numeric strings

I have a function that pattern matches its argument, which is a string:
let processLexime lexime
match lexime with
| "abc" -> ...
| "bar" -> ...
| "cat" -> ...
| _ -> ...
This works as expected. However, I'm now trying to extend this by expressing "match a string containing only the following characters". In my specific example, I want anything containing only digits to be matched.
My question is, how can I express this in F#? I'd prefer to do this without any libraries such as FParsec, since I'm mainly doing this for learning purposes.
You can use active patterns: https://msdn.microsoft.com/en-us/library/dd233248.aspx
let (|Integer|_|) (str: string) =
let mutable intvalue = 0
if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
else None
let parseNumeric str =
match str with
| Integer i -> printfn "%d : Integer" i
| _ -> printfn "%s : Not matched." str
One way would be an active pattern
let (|Digits|_|) (s:string) =
s.ToCharArray() |> Array.forall (fun c -> System.Char.IsDigit(c)) |> function |true -> Some(s) |false -> None
then you can do
match "1" with
|Digits(t) -> printf "matched"
I would use regular expressions combined with active patterns. With regular expressions you can easily match digits with \d and active patterns makes the syntax nice inside your match.
open System.Text.RegularExpressions
let (|ParseRegex|_|) regex str =
let m = Regex("^"+regex+"$").Match(str)
if (m.Success) then Some true else None
let Printmatch s =
match s with
| ParseRegex "w+" d -> printfn "only w"
| ParseRegex "(w+|s+)+" d -> printfn "only w and s"
| ParseRegex "\d+" d -> printfn "only digis"
|_ -> printfn "wrong"
[<EntryPoint>]
let main argv =
Printmatch "www"
Printmatch "ssswwswwws"
Printmatch "134554"
Printmatch "1dwd3ddwwd"
0
which prints
only w
only w and s
only digis
wrong

Create Discriminated Union Case from String

I'm trying to create DU cases from strings. The only way I can see doing this is by enumerating over the DU cases via Microsoft.FSharp.Reflection.FSharpType.GetUnionCases and then picking the UnionCase that matches the string (by using .Name) and then making the actual DU case out of that by using FSharpValue.MakeUnion.
Isn't there an easier/more elegant way of doing this? In my scenario I have a DU with a couple of hundred cases for keywords. I have to read the strings (keywords) from a file and make the types out of them. I did some "optimization" by putting the cases into a Map but I was hoping there'd be a better way of doing this.
I have the following, for example:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let mkKeywords (file: string) =
use sr = new StreamReader(file)
let caseMap =
FSharpType.GetUnionCases(typeof<Keyword>)
|> Array.map (fun c -> (c.Name, FSharpValue.MakeUnion(c, [||]) :?> Keyword))
|> Map.ofArray
[
while not sr.EndOfStream do
let l = sr.ReadLine().Trim()
match caseMap.TryFind l with
| Some c -> yield c
| None -> failwith <| "Could not find keyword: " + l
]
I found this handy code snippet...
open Microsoft.FSharp.Reflection
let toString (x:'a) =
let (case, _ ) = FSharpValue.GetUnionFields(x, typeof<'a>)
case.Name
let fromString<'a> (s:string) =
match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
|[|case|] -> Some(FSharpValue.MakeUnion(case,[||]) :?> 'a)
|_ -> None
... which makes it easy to tack on two lines of code to any DU...
type A = X|Y|Z with
override this.ToString() = FSharpUtils.toString this
static member fromString s = FSharpUtils.fromString<A> s
I would use pattern matching like this:
type Keyword =
| FOO
| BAR
| BAZ
| BLAH
let matchKeyword (word:string) : Keyword option =
match word with
| "FOO" -> Some FOO
| "BAR" -> Some BAR
| "BAZ" -> Some BAZ
| "BLAH" -> Some BLAH
| _ -> None
And maybe auto generate the match statement first time using regex in my editor, but only because you have hundreds of cases. But i am not sure if its a better solution then yours.
As the cases have no value, another option is to use enums:
type Keyword =
| FOO = 0
| BAR = 1
| BAZ = 2
| BLAH = 3
let strings = ["FOO";"BAR"]
let keywords =
[for s in strings -> s, Keyword.Parse(typeof<Keyword>, s)]
|> Map.ofList
Then you can simply use Enum.Parse.

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