Hi Bart,
yes - local values (variables) are not allowed in quotations and you can quote only global values that can be identified by some unique global identifier. I think that the reason for this is that a reference to some local value in a quotation would be at first, a difficult to represent and second, not very useful, because you wouldn't be able to access it's value or anything else (a bit different situation is when working with classes, but as far as I can see this is not your case).

In general, when you want to represent a quotation that depends on some argument, you can just quote a lambda function like this:

1
2
3
4
5
6
// instead of quoting a private value like in this example..
let quote2 (x) = 
    <@@ x @@>
// you can use the following...
let quote2 () = 
    <@@ fun x -> x @@>

The DLinq63 sample uses the "§" symbol, which does a bit different thing and is often very useful. It takes a value of the variable and splices it into the quotation, meaning that the quotation will not contain a reference to the variable, but a value - reference to an object:

1
2
3
 
let value = 32
let quot = <@@ §value + 10 @@>

To match a value spliced using the "§" symbol, you can use LiftedValue active pattern (while for matching a variable you can use Var and a top-level value reference is matched using AnyTopDefnUse).

By on 10/6/2007 6:32 AM ()

Hi Tomas,

Thanks for the help, funnily enough the way I came across this was trying to use a quotation inside a class.
The code I posted was an attempt to strip it down to the bare essentials. Seeing as I got the same issue using
global functions as when using class methods I posted the simplest code. The code below gives a better insight
into what I wanted to try.

type

RemoteExecutor =

class

member this.ParseAndExecute quote =

// Do Parse and execute quote somewhere

()

member this.AddNumbers a b =

let quote = <@@ a + b @@>

this.ParesAndExecute quote

end

What you said about local variables not being accessible is what I had an inkling would be the case. That said, does it

mean that quotations that contain a late bound value (not sure as to the correct term for this is) cannot be encapsulated

in any way?

I did attempt using the § symbol but get a “The value or constructor '~@' is not defined.”. L
Is the symbol being interpreted as something else? I did copy and paste it as I don’t know how to get it if VS.

A little bit more detail, or pointers to any info on how classes a treated differently would be greatly appreciated.

Thanks Heaps

Bart

By on 10/9/2007 6:45 AM ()

Hi Bart,
sorry for the slow reply. The reason why I mentioned classes as a special situation is that you can get the same error if you write something like:

1
2
3
4
5
6
 
type Test = class
    val f : int
    member x.Foo () =
        <@ x.f + 42 @>  
  end

... in this case you're accessing a local value (a member of the class), but there are situations where it would be useful to allow storing this as a quotation (for example if you want to translate the class to some other language (which supports classes) and translate the quotation to a member).

Anyway, when the "local values" are arguments to a member the situation should be the same as when working with functions. Note that in your example (if it were allowed to quote these local values) you would get something like App(App("+", Local("a")), Local("b")) - i.e. a quotation that represents application of "+" to "a" and then application of the result to "b". The problem would be that in your ParseAndExecute member, there wouldn't be any way for reading a value of "a" and "b", so you couldn't evaluate it (if this is what you wanted).

I'm not sure why you get “The value or constructor '~@' is not defined”. I think "§" doesn't work in FSI, so you may want to try compiling the code (and check that the file is saved using UTF-8 or some similar encoding).

Alternatively, you can use the following syntax to "lift" a value into an expression - it is less elegant, but it will work (BTW: I modified the code to use #light syntax where you can omit some keywords):

1
2
3
4
5
6
7
8
9
 
type RemoteExecutor = 
  member this.ParseAndExecute quote = 
    // Do Parse and execute quote somewhere
    ()

  member this.AddNumbers a b = 
    let quote = <@ _ + _ @> (lift a) (lift b)
    this.ParesAndExecute quote.Raw

The underscore in the quotation creates a 'hole' and the quotation is returned as a function. You can than call it with arguments (another quotations) that will be filled in the hole. Here I created a quotation that represents a "lifted" value of the argument using a "lift" function (from Microsoft.FSharp.Quotations.Typed module). Also, I'm using "<@ .. @>" instead of "<@@ .. @@>", because this makes the program safer (and "lift" function works better with typed version of quotations).

When calling "ParseAndExecute" you can extract the raw quotation (type Expr) from a typed quotation (type Expr<int>) using the "Raw" property.

By on 10/13/2007 1:20 PM ()

Many thanks Tomas,

Unfortunately after a heap of trying I am still can’t get the simplest examples going.

#light

open Microsoft.FSharp

open Microsoft.FSharp

open Microsoft.FSharp.Quotations.Typed

open Microsoft.FSharp.Quotations.Raw

let value = 32

let quote = <@@ §value + 10 @@>

The example you posted gives me a “This expression has type Quotations.Expr<'a> but is here used with type Quotations.Expr”

let quote = <@ _ + 10 @> (lift value) complies OK.

I tried using

let quote = <@ §value + 10 @>

I get “error: syntax error.”..... Not much to work with. L

When I tried to use a class below

type Quotes =

class

new() = {}

member this.Exec q =

print_any q

()

member this.Quote value =

let quote = <@ _ @> (lift value)

this.Exec quote.Raw

end

I get “error: type variable not found in environment.”

I’m really lost as to why I get these errors or what to do about them. Any insight would be greatly appreciated.

BTW I am compling this on VS 2008 Beta 2 and F# 1.9.2.9

Cheers

Bart

By on 10/20/2007 7:58 AM ()

Hi Bart,

You mention:

I tried using <?XML:NAMESPACE PREFIX = O />

let quote = <@ §value + 10 @>

I tried this just now and it worked for me. Make sure you save your file with UTF-8 encoding - the F# compiler currently only accepts UTF-8 encoded inputs.

For your second example, this is indeed a bug (and the error location is poor as well). It will work for any particular type instance, e.g. if you constaint "value" to be an integer.

1
2
3
4
5
6
7
8
9
10
11
 

type Quotes() = 
        member this.Exec q = 
            print_any q
            ()             

        member this.Quote (value:int) = 
            let quote = <@ _ @> (lift value)
            this.Exec quote.Raw

I've logged this as issue 1060 in our internal bug database. (At some point we hope to make this database accessible in some form so you'll be able to track our progress on this issue, but we haven't done that just yet.)

Kind regards

Don

By on 10/21/2007 9:25 AM ()

Happy days!!

Many thanks Tomas and Don. I had Western European codepage., and once the type constaint was added it came good.

For those who don't know off hand how to change the encoding (In Orcas at least) .
"Save as" the file, Click the dropdown on the save button and click "Save with encoding". Choose UTF-8

Also to type the § its ALT+0+1+6+7

Thanks again.
Bart

By on 10/22/2007 3:21 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper