In C# I could create a string representation of an object graph fairly easily with expression trees.
public static string GetGraph<TModel, T>(TModel model, Expression<Func<TModel, T>> action) where TModel : class
{
var method = action.Body as MethodCallExpression;
var body = method != null ? method.Object != null ? method.Object as MemberExpression : method.Arguments.Any() ? method.Arguments.First() as MemberExpression : null : action.Body as MemberExpression;
if (body != null)
{
string graph = GetObjectGraph(body, typeof(TModel))
return graph;
}
throw new Exception("Could not create object graph");
}
In F# I've been looking at Quotations to attempt to do the same thing, and can't quite figure it out. I've attempted converting the quotation into an Expression using the PowerPack libraries, but have had no luck so far, and the information on the internet seems fairly sparse on this topic.
If the input is:
let result = getGraph myObject <# myObject.MyProperty #>
the output should be "myobject.MyProperty"
You can see what you get from quotation expression in fsi session:
> let v = "abc"
> <# v.Length #>;;
val it : Expr<int>
= PropGet (Some (PropGet (None, System.String v, [])), Int32 Length, [])
> <# "abc".Length #>;;
val it : Expr<int>
= PropGet (Some (Value ("abc")), Int32 Length, [])
You can find description of all active patterns available to parse qoutations into
manual\FSharp.Core\Microsoft.FSharp.Quotations.Patterns.html
under your F# installation directory or at msdn site
There is nice Chris Smith's book "Programming F#" with chapter named "Quotations" :)
So, after all, just try to write simple parser:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns
let rec getGraph (expr: Expr) =
let parse args =
List.fold_left (fun acc v -> acc ^ (if acc.Length > 0 then "," else "") ^ getGraph v) "" args
let descr s = function
| Some v -> "(* instance " ^ s ^ "*) " ^ getGraph v
| _ -> "(* static " ^ s ^ "*)"
match expr with
| Int32 i -> string i
| String s -> sprintf "\"%s\"" s
| Value (o,t) -> sprintf "%A" o
| Call (e, methodInfo, av) ->
sprintf "%s.%s(%s)" (descr "method" e) methodInfo.Name (parse av)
| PropGet(e, methodInfo, av) ->
sprintf "%s.%s(%s)" (descr "property" e) methodInfo.Name (parse av)
| _ -> failwithf "I'm don't understand such expression's form yet: %A" expr
P.S. And of course you will need some code to translate AST to human readable format.
I'm unsure what the state of things was back when you asked this question, but today you can convert an F# Quotation to an Expression using the PowerPack like so:
<# "asdf".Length #>.ToLinqExpression()
Also, I've been developing a library Unquote which is able to decompile many F# Quotations into F# single-line non-light syntax code. It can easily handle simple instance PropertyGet expressions like your required input / output:
> decompile <# "asdf".Length #>;;
val it : string = ""asdf".Length"
See my answer to a similar question for more information or just visit Unquote's home page.
Related
With reference to Is there an equivalent of C#'s nameof(..) in F#?
how can the nameof function used or extended for the following case?
let nameof (q:Expr<_>) =
match q with
| Patterns.Let(_, _, DerivedPatterns.Lambdas(_, Patterns.Call(_, mi, _))) -> mi.Name
| Patterns.PropertyGet(_, mi, _) -> mi.Name
| DerivedPatterns.Lambdas(_, Patterns.Call(_, mi, _)) -> mi.Name
| _ -> failwith "Unexpected format"
let any<'R> : 'R = failwith "!"
let s = _nameof <# System.Char.IsControl #> //OK
type A<'a>() =
static member MethodWith2Pars(guid:Guid, str:string) = ""
static member MethodWith2Pars(guid:Guid, ba:byte[]) = ""
let s1 = nameof <# A<_>.MethodWith2Pars #> //Error FS0503 A member or object constructor 'MethodWith2Pars' taking 1 arguments is not accessible from this code location. All accessible versions of method 'MethodWith2Pars' take 2 arguments
let s2 = nameof <# A<_>.MethodWith2Pars : Guid * string -> string #> //Same error
The compiler gives the following error:
Error FS0503 A member or object constructor 'MethodWith2Pars' taking 1 arguments is not accessible from this code location. All accessible versions of method 'MethodWith2Pars' take 2 arguments
The answer you linked is a bit outdated. F# 5.0 (released just recently) offers the true nameof feature. See the announcement: https://devblogs.microsoft.com/dotnet/announcing-f-4-7/#nameof
This feature also existed in preview since F# 4.7: https://devblogs.microsoft.com/dotnet/announcing-f-4-7/#nameof
You can write your code like this:
open System
type A() =
static member MethodWith2Pars(guid:Guid, str:string) = ""
static member MethodWith2Pars(guid:Guid, ba:byte[]) = ""
let s1 = nameof (A.MethodWith2Pars : Guid * byte[] -> string)
let s2 = nameof (A.MethodWith2Pars : Guid * string -> string)
The type annotation is needed due to overloading. Not sure why there is a generic type parameter on the class declaration, but it's not used anywhere so I just removed it.
I have a type that I'm trying to understand by writing unit tests against it, however I can't reason what to do with PrintfFormat
type ValueFormat<'p,'st,'rd,'rl,'t,'a> = {
format: PrintfFormat<'p,'st,'rd,'rl,'t>
paramNames: (string list) option
handler: 't -> 'a
}
with
static member inline construct (this: ValueFormat<_,_,_,_,_,_>) =
let parser s =
s |> tryKsscanf this.format this.handler
|> function Ok x -> Some x | _ -> None
let defaultNames =
this.format.GetFormatterNames()
|> List.map (String.replace ' ' '_' >> String.toUpperInvariant)
|> List.map (sprintf "%s_VALUE")
let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>")
let formatTokens = this.format.PrettyTokenize names
(parser, formatTokens)
I feel confident that I can figure everything out but PrintfFormat is throwing me with all those generics.
The file I'm looking at for the code I want to unit test is here for the FSharp.Commandline framework.
My question is, what is PrintfFormat and how should it be used?
A link to the printf.fs file is here. It contains the definition of PrintfFormat
The PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> type, as defined in the F# source code, has four type parameters:
'Result is the type that your formatting/parsing function produces. This is string for sprintf
'Printer is a type of a function generated based on the format string, e.g. "%d and %s" will give you a function type int -> string -> 'Result
'Tuple is a tuple type generated based on the format string, e.g. "%d and %s" will give you a tuple type int * string.
'State and 'Residue are type parameters that are used when you have a custom formatter using %a, but I'll ignore that for now for simplicity (it's never needed unless you have %a format string)
There are two ways of using the type. Either for formatting, in which case you'll want to write a function that returns 'Printer as the result. The hard thing about this is that you need to construct the return function using reflection. Here is an example that works only with one format string:
open Microsoft.FSharp.Reflection
let myformat (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Printer =
unbox <| FSharpValue.MakeFunction(typeof<'Printer>, fun o ->
box (o.ToString()) )
myformat "%d" 1
myformat "%s" "Yo"
This simply returns the parameter passed as a value for %d or %s. To make this work for multiple arguments, you'd need to construct the function recursively (so that it's not just e.g. int -> string but also int -> (int -> string))
In the other use, you define a function that returns 'Tuple and it needs to create a tuple containing values according to the specified formatting string. Here is a small sample that only handles %s and %d format strings:
open FSharp.Reflection
let myscan (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Tuple =
let args =
fmt.Value
|> Seq.pairwise
|> Seq.choose (function
| '%', 'd' -> Some(box 123)
| '%', 's' -> Some(box "yo")
| _ -> None)
unbox <| FSharpValue.MakeTuple(Seq.toArray args, typeof<'Tuple>)
myscan "%d %s %d"
Can somebody help me with article of Tomas Petricek: http://tomasp.net/blog/fsharp-dynamic-lookup.aspx/#dynfslinks?
The problem is that it is severely outdated. I understand that namespaces
open Microsoft.FSharp.Quotations.Typed
open Microsoft.FSharp.Quotations.Raw
are gone. So I removed the openings. But there are still errors. "Typed" is not defined. "RecdGet" is not defined. And I suspect they are not the last. I'm trying to prove to my boss that F# is good to use for database normalization. Dynamic lookup of fields would really helped me to deal with similarly named fields having different prefixes.
There is also post of Tomas on fpish: https://fpish.net/topic/None/57493, which I understand predates the article
Here's a rough equivalent:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
type DynamicMember<'t,'u> = Expr<'t -> 'u>
let getValueReader (expr:DynamicMember<'recdT, 'fieldT>) =
// Match the quotation representing the symbol
match expr with
| Lambda(v, PropertyGet (Some (Var v'), pi, [])) when v = v' ->
// It represents reading of the F# record field..
// .. get a function that reads the record field using F# reflection
let rdr = Reflection.FSharpValue.PreComputeRecordFieldReader pi
// we're not adding any additional processing, so we just
// simply add type conversion to the correct types & return it
((box >> rdr >> unbox) : 'recdT -> 'fieldT)
| _ ->
// Quotation doesn't represent symbol - this is an error
failwith "Invalid expression - not reading record field!"
type SampleRec = { Str : string; Num : int }
let readStrField = getValueReader <# fun (r : SampleRec) -> r.Str #>
let readNumField = getValueReader <# fun (r : SampleRec) -> r.Num #>
let rc = { Str = "Hello world!"; Num = 42 }
let s, n = readStrField rc, readNumField rc
printfn "Extracted: %s, %d" s n
I'd like to generate a type with static functions, that I can then use in functions that become quotations using the ReflectedDefinition attribute. It seems to me a convenient way of translating something into FSharp types, using FSharp to compose the domain of functions and types, and spit the composed code back into its native form, having received the benefit of type checking, VS intellisense, higher order functions, etc. To try and get started I have this type provider, largely copy->pasted from various articles
[<TypeProvider>]
type CSoundTypeProvider(config: TypeProviderConfig) as this =
inherit ProvidedTypes.TypeProviderForNamespaces()
let namespaceName = "TestNamespace"
let thisAssembly = Assembly.GetExecutingAssembly()
// config.
let intType = typeof<int>
let providedParam = ProvidedTypes.ProvidedParameter("prm", intType)
let providedFunction = ProvidedTypes.ProvidedMethod("TestMethod", [providedParam], intType, IsStaticMethod=true
, InvokeCode = fun args ->
// The 'args' parameter represents expressions that give us access to the
// instance on which the method is invoked and other parameters (if there are more)
let instance = args.[0]
// Now we can return quotation representing a call to MethodInfo 'p' with 'instance'
instance)
let csoundProvidedWrapper = ProvidedTypes.ProvidedTypeDefinition(thisAssembly, namespaceName, "TestType", None)
do csoundProvidedWrapper.AddMember(providedFunction)
do this.AddNamespace(namespaceName, [csoundProvidedWrapper])
And testing it with this reflected definition:
[<ReflectedDefinition>]
let myfn i j =
let k = i * j
let x = k + 2
let f = TestNamespace.TestType.TestMethod k
let ret = f + 2
ret
I'm parsing the reflected definition like this:
<# myfn #> |> println
println is a function (copied from another article) that has many of the active patterns for parsing quotations like Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList), which gets me an experssion tree of all of the code, except for the provided static method. Is what I'm trying to do even possible? If so, what's the active pattern I've likely missed from my println function here:
let println expr =
let rec print expr = match expr with
| Patterns.Application(expr1, expr2) ->
// Function application.
print expr1
printf " "
print expr2
| Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList) ->
print n
| Patterns.Call(exprOpt, methodInfo, exprList) ->
// Method or module function call.
match exprOpt with
| Some expr -> print expr
| None -> printf "%s" methodInfo.DeclaringType.Name
printf ".%s(" methodInfo.Name
if (exprList.IsEmpty) then printf ")" else
print exprList.Head
for expr in exprList.Tail do
printf ","
print expr
printf ")"
| DerivedPatterns.Int32(n) ->
printf "%d" n
| Patterns.Lambda(param, body) ->
// Lambda expression.
printf "fun (%s:%s) -> " param.Name (param.Type.ToString())
print body
| Patterns.Let(var, expr1, expr2) ->
// Let binding.
if (var.IsMutable) then
printf "let mutable %s = " var.Name
else
printf "let %s = " var.Name
print expr1
printf " in "
print expr2
| Patterns.PropertyGet(_, propOrValInfo, _) ->
printf "%s" propOrValInfo.Name
| DerivedPatterns.String(str) ->
printf "%s" str
| Patterns.Value(value, typ) ->
printf "%s" (value.ToString())
| Patterns.Var(var) ->
printf "%s" var.Name
| _ -> printf "%s" (expr.ToString())
print expr
If I can't do this, what approach would you recommend for generating FSharp definitions that I can use in quotations? I've largely been influenced by the FunScript project, but hoping to avoid the step where it seems each Typescript definition has to get compiled into a seperate DLL.
Most of the type provider demos out there use erased type providers which do not produce actual .NET types. When you use an erased type provider, the generated methods are erased and replaced with the code you provided in the method's InvokeCode.
Let's say you have a method Foo that erases to someFunc with "Foo" as an argument:
myObj.Foo() ~> someFunc(myObj, "Foo")
In quotations, you will also see the erased version (both in direct <# .. #> and in ReflectedDefinition):
<# myObj.Foo() #> ~> <# someFunc(myObj, "Foo") #>
The way FunScript type provider works is that it generates some dummy code that contains the function name so that it can then generate the corresponding JavaScript. Say you have:
<# win.Alert(arg) #> ~> <# invokeFunction("alert", win, arg) #>
To do the same sort of thing, you'll need to define a function like invokeFunction and to generate appropriate InvokeCode. Then you can look for calls to invokeFunction in the generated quotation and do whatever special thing you need to do there. It is a bit hard to see what exactly are you trying to do, but this should at least point you in the right direction.
I'm currently learning F# and hitting a few stumbling blocks; I think a lot of it is learning to think functionally.
One of the things I'm learning at the moment are computation expressions, and I want to be able to define a computation expression that handles some tracking state, e.g:
let myOptions = optionListBuilder {
let! opt1 = {name="a";value=10}
let! opt2 = {name="b";value=12}
}
I want to be able to have it so that myOptions is a Option<'T> list, so each let! bind operation effectively causes the builder to "track" the defined options as it goes along.
I don't want to have to do it using mutable state - e.g. having a list maintained by the builder and updated with each bind call.
Is there some way of having it so that this is possible?
Update: The resultant Option<'T> list type is just representative, in reality I'll likely have an OptionGroup<'T> type to contain a list as well as some additional information - so as Daniel mentioned below, I could use a list comprehension for a simple list.
I wrote a string builder computation expression here.
open System.Text
type StringBuilderUnion =
| Builder of StringBuilder
| StringItem of string
let build sb =
sb.ToString()
type StringBuilderCE () =
member __.Yield (txt : string) = StringItem(txt)
member __.Yield (c : char) = StringItem(c.ToString())
member __.Combine(f,g) = Builder(match f,g with
| Builder(F), Builder(G) ->F.Append(G.ToString())
| Builder(F), StringItem(G)->F.Append(G)
| StringItem(F),Builder(G) ->G.Append(F)
| StringItem(F),StringItem(G)->StringBuilder(F).Append(G))
member __.Delay f = f()
member __.Zero () = StringItem("")
member __.For (xs : 'a seq, f : 'a -> StringBuilderUnion) =
let sb = StringBuilder()
for item in xs do
match f item with
| StringItem(s)-> sb.Append(s)|>ignore
| Builder(b)-> sb.Append(b.ToString())|>ignore
Builder(sb)
let builder1 = new StringBuilderCE ()
Noticed the underlying type is immutable (the contained StringBuilder is mutable, but it doesn't have to be). Instead of updating the existing data, each yield combines the current state and the incoming input resulting in a new instance of StringBuilderUnion You could do this with an F# list since adding an element to the head of the list is merely the construction of a new value rather than mutating the existing values.
Using the StringBuilderCE looks like this:
//Create a function which builds a string from an list of bytes
let bytes2hex (bytes : byte []) =
string {
for byte in bytes -> sprintf "%02x" byte
} |> build
//builds a string from four strings
string {
yield "one"
yield "two"
yield "three"
yield "four"
} |> build
Noticed the yield instead of let! since I don't actually want to use the value inside the computation expression.
SOLUTION
With the base-line StringBuilder CE builder provided by mydogisbox, I was able to produce the following solution that works a charm:
type Option<'T> = {Name:string;Item:'T}
type OptionBuilderUnion<'T> =
| OptionItems of Option<'T> list
| OptionItem of Option<'T>
type OptionBuilder () =
member this.Yield (opt: Option<'t>) = OptionItem(opt)
member this.Yield (tup: string * 't) = OptionItem({Name=fst tup;Item=snd tup})
member this.Combine (f,g) =
OptionItems(
match f,g with
| OptionItem(F), OptionItem(G) -> [F;G]
| OptionItems(F), OptionItem(G) -> G :: F
| OptionItem(F), OptionItems(G) -> F :: G
| OptionItems(F), OptionItems(G) -> F # G
)
member this.Delay f = f()
member this.Run (f) = match f with |OptionItems items -> items |OptionItem item -> [item]
let options = OptionBuilder()
let opts = options {
yield ("a",12)
yield ("b",10)
yield {Name = "k"; Item = 20}
}
opts |> Dump
F# supports list comprehensions out-of-the-box.
let myOptions =
[
yield computeOptionValue()
yield computeOptionValue()
]