More on F# quotations
08 Apr 2009 10:59 AM UncategorizedAlright, so i threw that blurb out there a few days back, with little more than zOMG! THIS IS COOL!!!ONE!11!. I figured a bit more detail wouldn't hurt.
One of the things that has made F# a bit more difficult to learn for me is that outside of the more basic concepts, everything is explained on a rather theoretical level. It makes sense, really - that's where functional came from, but it does make it more difficult to visualize the feature and understand their applicability. Let's see if i can do any better.
So - f# quotations are simply the full representation of the syntax tree of a fragment of code, available run-time. That means that you have access to anything within <@ @> or marked with a ReflectedDefinition attribute. The common use case that you read everywhere is that you can write code in f# and then execute it elsewhere. And that's certainly cool, but it's only one aspect. One that i've found incredibly useful is the ability to gather more information from dynamically loaded code than previously possible.
With standard reflection you get to see the shell. You get member names, method signatures (as an ordered list of types) and inheritance info (there's more, but these are the core elements). However, with quotations, i can see much more. I can get parameter names, i can get local variables i can get the full source of the block i'm evaluating!
My use for this? In bistro, I used to make the developer decorate his class with member attributes that gave me information about how that member was used. Now, I can pull that information straight from a function signature, and not require any additional markup. Here's how:
Sample target function:
#light open Microsoft.FSharp.Reflection open System.Reflection module NestedProgram = module Program = [<ReflectedDefinition>] let public sample f_name p2 = printf "sample {%A}\r\n" f_name
Code:
#light open System open System.Reflection open DefaultControllers.NestedProgram.Program open Microsoft.FSharp.Quotations.Patterns open Microsoft.FSharp.Quotations.DerivedPatterns open Microsoft.FSharp.Quotations open Microsoft.FSharp.Reflection let strip (text: string) = match text.IndexOf "@" with | -1 -> text | _ as i -> text.[..i-1] let rec get_parms exp = match exp with | Lambda (var,body) -> [strip var.Name] @ get_parms body | _ -> [] let get_info (t:System.Type) = if not <| FSharpType.IsModule t then failwith <| sprintf "%A is not a module" t else let funcs = t.GetMethods(BindingFlags.Static ||| BindingFlags.Public) Array.iter (fun (m: MethodInfo) -> match Expr.TryGetReflectedDefinition m with | Some ex -> printf "\t%s.%s %s\r\n" t.FullName m.Name (String.concat " " (get_parms ex)) | None -> ()) funcs let rec searchTypes t = if FSharpType.IsModule t then get_info t AppDomain.CurrentDomain.GetAssemblies() |> Array.iter (fun (asm: Assembly) -> printf "asm: %s\r\n" <| asm.GetName().Name Array.iter searchTypes (asm.GetTypes()) ) ignore <| System.Console.Read()
This code will go through the entire loaded assembly list, find all types and give me the function signatures. How i consume that is now up to me, but it's there for the taking.
As a side note - I'm going to try and blog more about the real-world applicability of f#. I think that the notion of f# or functional programming not being applicable to web development and the like is a misconception, and hopefully i'll be able to illustrate that.
Hey Alex I appreciate your blog.
… real-world … yes.
Look forward to more.
Especially as VS ‘10, Net 4 and WPF 4 roll-out.
Have you seen Jon Harrop’s latest article?
“Aperiodic tilings”
He has a one free offer.
Full disclosure: I subscribe, I think it’s goodness.
Thanks, Art
Thanks for the support!
No, i actually haven’t heard of him. Went out and googled, and it looks interesting. I think i’ll poke around on there some more. Thanks for the pointer. Is it only available through the f# journal?
Yes, (that’s how Jon buys baby new shoes) but you can get one taste free. See link below.
He has a one free offer. (I’m not his agent; I subscribe to F# Journal.)
Jon’s article: #48 Aperiodic Tilings (31st March 2009), The F# Journal
http://fsharpnews.blogspot.com/2009/03/free-article-but-which-one.html
“Many sets of polygons can be used to tile an infinite 2D plane. The term “aperiodic tilings” …of mathematical and scientific interest because they give rise to unexpected diffraction patterns when they appear in quasicrystalline materials but also because they are often beautiful … article describes a simple program that visualizes tilings using Windows Presentation Foundation where the tilings are described using generic rewrite rules implemented in terms of a .NET interface…”
Hi Alex
I copied the F# code to VS2008 F# project and got this error:
The namespace or module DefaultControllers not defined.
open DefaultControllers.NestedProgram.Program
Do you use VS?
oh – i had the two code snippets sitting in different files, the first one being in DefaultControllers.fs. Since there was no explicit namespace declaration, it took the fully qualified name to be DefaultControllers.NestedProgram.Program. Just change that to match whatever namespace you’re scanning, or just paste the first snippet into the second one…