F# quotations visualizer
I already explained what F# quotations are and I explained how you can do some simple manipulations with it. In this article I'd like to present an application that I wrote and that can be helpful when working with quotations. It displays clear graphical representation of given F# quotation (using Windows Forms TreeView control).
This application works with raw quotations (this means the internal representation that is used when
writing quotation compilers). You can get F# quotations using
<@@@@ ... @@@@> operator
and the type of raw quotations is
expr type is following discriminated union:
type expr = | ConstExpr of exprConstr * dtype list | VarExpr of exprVarName | QuoteExpr of expr | LambdaExpr of exprVar * expr | AppExpr of expr * expr | HoleExpr of dtype
You can see that there are only a few types of quotations, but when you are writing application
that works with quotations, you can use set of object that provide simplier view on quotations structure.
These objects (name starts with letters
ef) can be found in the
Raw namespace (see F# manual
All these objects have
Query method that expects parameter of type
expr and that either
splits given expression into several sub-expressions or returns
None (if parameter doesn't match).
So let's look at the example:
let q = <@@@@ if (a = 0) then 1 else 2 @@@@>
This is the quotation that represents conditional expression, but it is internally stored using
(one variant of discriminated union), but you can use the
efCond.Query method to test whether it is
conditional expression and you can also get expression that represents the condition and expressions representating
both true and false branches.
// Test whether q is conditional expression using efCond.Query match Raw.efCond.Query q with | Some (_,(cond,trueBranch,falseBranch)) -> // cond - 'expr' that represents condition // trueBranch - 'expr' that represents the true branch // falseBranch - 'expr' that represents the false branch print_string "If-then-else statement" | None -> print_string "Something else"
This was just a few words to explain what the application does and to help you understand the source code of the most interesting part of application that builds the TreeView tree.
The application contains a few interesting features that I'd like to mention. If you look at the right panel, it contains section called 'settings'. In this section you can configure how should the tree representation be built. Using the first checkbox you can say, whether the function calls in tree should be displayed as single function applications (more functional approach) or as series of function applications (more imperative approach). To see the difference look at the following screenshots:
If you check the second option, visualizer will call
before displaying the quotation tree. This function performs some simplifications on
quotation before it is displayed. At first, the top level definitions are expanded and
it also performs beta reduction which means that any local binding are replaced by
its value. For example
let a=5 in a+a will be reduced to
(This is the reason why complicated example from the first screenshot looks so simple
at the second and third screenshot)
I won't describe the complete source code (you can download it and look at it), but I'd like to describe how is the code organized so you can easilly find what you want. The application is divided into several files (FS file contains the implementation and FSI file contains interface of the module).
Main function that launches the application can be found in the
main.fs file. This file also contains a few quotations that are displayed
when application starts. The main form called can be found in the
module. This module also contains dialog box that is displayed when user clicks
on the "Add new quotation" link (this form is called
and class inherited from Windows Forms
TabPage that displays
expr in a
The last two modules are much more interesting. The
getExpressionTree that takes F# quotation and
builds the TreeView tree. This file contains code that matches given expression
with several expression families like
and other (but it is still not complete). The last module is
and it contains function that takes string entered by user and returns object
representation of F# quotation. This function simply calls
and loads the value from the compiled assembly using reflection.
The solution also contains one C# project (called Resources). I created this
project because the F# application contains resources and I wanted to use
desiner in Visual Studio to easily create resource files. The main F# application
just takes compiled resources (the file named
How to use it
Using is pretty simple, so I won't describe it, however there are a few details that I want
to mention. First, the application uses F# libraries (fslib.dll), but I created one package that
contains requiered libraries, so you can look at the application without installing F#.
Also if you want to be able to add F# quotations at runtime, you have to install F#, because
adding quotations uses F# compiler (
fsc.exe). You also have to set the correct
path to the
fsc.exe in application config file (