When are let bindings in code quotations replaced with their values? - f#

If I run the first example from MSDN (https://msdn.microsoft.com/en-us/library/dd233212.aspx) in the F# Interactive window, I get the expected output:
fun (x:System.Int32) -> x + 1
a + 1
let f = fun (x:System.Int32) -> x + 10 in f 10
But if I run it in the Main from my program, all let bindings are replaced by their constant values:
[<EntryPoint>]
let main argv =
let a = 2
// exprLambda has type "(int -> int)".
let exprLambda = <# fun x -> x + 1 #>
// exprCall has type unit.
let exprCall = <# a + 1 #>
println exprLambda
println exprCall
println <## let f x = x + 10 in f 10 ##>
Result:
fun (x:System.Int32) -> x + 1
2 + 1
let f = fun (x:System.Int32) -> x + 10 in f 10
Is this normal or a bug? Are the rules for this documented? What can I do to force it to the expected output?
Edit:
This answer (https://stackoverflow.com/a/4945137/1872399) states (Variables are automatically replaced with values if the variable is defined outside of the quotation). but I couldn't find any mention of this elsewhere.
Edit 2: What I really want to do
This code (https://gist.github.com/0x53A/8848b04c2250364a3c22) goes into the catch-all case and fails with not implemented:parseQuotation:Value (Variable "ax1") (I expected it to go into | Var(var) ->) so not only constants known at compile-time, but also function parameters are expanded to their values.
Edit 3:
I ran the working version (https://gist.github.com/0x53A/53f45949db812bde5d97) under the debugger, and it looks like that one is actually the bug:
The quotation is {Call (None, op_Addition, [PropertyGet (None, a, []), Value (1)])} witha = Program.a, so this seems to be a side-effect of the fact that let bindings in modules are compiled into properties. If I am correct, I should maybe file a doc-bug at Microsoft...

In general, the problem with quoting of variables is that they escape their scope. That is, having a variable foo in your quotation does not really make any sense if you do not have any way to find out what does the foo variable refer to.
So, for example, the following is OK, because the variable x is defined by the lambda:
<# fun x -> x #>
But if you have something like the following, it does not make sense to capture variable x because once the function returns, x is no longer in scope:
fun x -> <# x #>
This is the same to the situation you're describing - top-level bindings become static members of a module and so those can be captured, but local variables are not available after the expression evaluates and so they are replaced by values. So, the general rules are:
Accessing top-level bindings is quoted as getter of a static member
Accessing variables defined inside the quotations is captured as variable access
Accessing local variables of a function captures the value of the variable
There are definitely cases where being able to capture the variable name would be useful. One example that I really wanted to be able to do is to let people write for example:
plot(years, GDP)
The idea is that the plot function would get a quotation with variable names (which can then be used e.g. for plot axis). There is actually an F# 4.0 change proposal that lets you do this.

Related

Function that returns another function executes the body of outer function on every call of the returned function

It is actually pretty unxpected to me but consider this snippet in F#:
let f x =
printfn $"{x}"
fun x' -> x'
let y<'t> = f 1 //> val y<'t> : (obj -> obj)
y 2
//>
//1
//val it: obj = 2
what I would expect is that it will print "1" only when you bind f 1 to "y" (and that would tell me that "f" body only executes once) but seem like it executes "f" body on the every call of "y". Is it unavoidable effect related to auto curring or I'm missing something and there is a way to bypass outer function body execution on the every call of the returned function?
The hint as to what's going on here is the fact that 't has been constrained to obj and the signature of y is (obj -> obj). That's the F# compiler effectively say, "I give up, these have no real types, it is whatever it is" and emitting something that can execute at runtime but without any real type safety.
A side effect of this is that because it can't "pin down" y to a known signature, it cannot evaluate f, so it just emits y as a direct call to f, since you've effectively told the compiler that this is fine by parameterizing it with 't (which ends up just being obj, or "whatever").
Why is this happening? Value restriction!
I suspect you've evaluated this in F# Interactive block-by-block. The line of code that defines let y = f 1 is not possible to compile with more information. You can do so in two ways:
Use y with a real type that will pin its signature to the type you're using it as.
Give it an explicit signature like let y: int -> int = f 1 so that it's pinned down to a concrete type.
That's why if you execute this entire snippet in FSI or run it as a program, things work exactly like you'd expect:
let f x =
printfn $"{x}"
fun x' -> x'
let y = f 1
y 2
y 3
This is because y is generic.
Every time you refer to y, you choose a particular 't to go with that. For example:
let a = y<int>
let b = y<string>
a and b cannot be the same value, because they have been obtained from different instantiations of y. They have to be two different values. And this in turn means that y itself cannot be a single value. It has to be a function.
And that's what it is under the hood: it's compiled as a function, and every time you refer to it, the function is instantiated with the generic parameter you chose, and the body of the function is executed to obtain the result.
If you remove the generic parameter and give y a concrete type, the issue should go away:
let y = f 1 : obj -> obj

Why does F# require type placeholders for ToDictionary?

given
[
1,"test2"
3,"test"
]
|> dict
// turn it into keyvaluepair sequence
|> Seq.map id
|> fun x -> x.ToDictionary<_,_,_>((fun x -> x.Key), fun x -> x.Value)
which fails to compile if I don't explicitly use the <_,_,_> after ToDictionary.
Intellisense works just fine, but compilation fails with the error: Lookup on object of indeterminate type based on information prior to this program point
So, it seems, Intellisense knows how to resolve the method call.
This seems to be a clue
|> fun x -> x.ToDictionary<_,_>((fun x -> x.Key), fun x -> x.Value)
fails with
Type constraint mismatch.
The type 'b -> 'c is not compatible with type IEqualityComparer<'a>
The type 'b -> 'c' is not compatible with the type 'IEqualityComparer<'a>'
(using external F# compiler)
x.ToDictionary((fun x -> x.Key), id)
works as expected as does
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
I've replicated the behavior in FSI and LinqPad.
As a big fan of and avid reader of Eric Lippert I really want to know
what overload resolution, (or possibly extension methods from different places) are conflicting here that the compiler is confused by?
Even though the types are known ahead, the compiler's getting confused between the overload which takes an element selector and a comparer. The lambda compiles to FSharpFunc rather than the standard delegate types in C# like Action or Func, and issues do come up translating from one to the other. To make it work, you can :
Supply a type annotation for the offending Func
fun x -> x.ToDictionary((fun pair -> pair.Key), (fun (pair : KeyValuePair<_, _>) -> pair.Value)) //compiles
or name the argument as a hint
fun x -> x.ToDictionary((fun pair -> pair.Key), elementSelector = (fun (pair) -> pair.Value))
or force it to pick the 3 argument version:
x.ToLookup((fun pair -> pair.Key), (fun (pair) -> pair.Value), EqualityComparer.Default)
Aside
In your example,
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
you would explicitly need to annotate vMap because the compiler cannot find out what type the property exists on without another pass. For example,
List.map (fun x -> x.Length) ["one"; "two"] // this fails to compile
This is one of the reasons why the pipe operator is so useful, because it allows you to avoid type annotations:
["one"; "two"] |> List.map (fun x -> x.Length) // works
List.map (fun (x:string) -> x.Length) ["one"; "two"] //also works
The short answer:
The extension method ToDictionary is defined like this:
static member ToDictionary<'TSource,_,_>(source,_,_)
but is called like this:
source.ToDictionary<'TSource,_,_>(_,_)
The long answer:
This is the F# type signature of the function you are calling from msdn.
static member ToDictionary<'TSource, 'TKey, 'TElement> :
source:IEnumerable<'TSource> *
keySelector:Func<'TSource, 'TKey> *
elementSelector:Func<'TSource, 'TElement> -> Dictionary<'TKey, 'TElement>
But I only specified two regular parameters: keySelector and elementSelector. How come this has a source parameter?!
The source parameter is actually not put in the parenthesis, but is passed in by saying x.ToDictionary, where x is the source parameter. This is actually an example of a type extension. These kinds of methods are very natural in a functional programming language like F#, but more uncommon in an object oriented language like C#, so if you're coming from the C# world, it will be pretty confusing. Anyway, if we look at the C# header, it is a little easier to understand what is going on:
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector
)
So the method is defined with a "this" prefix on a first parameter even though it is technically static. It basically allows you to add methods to already defined classes without re-compiling or extending them. This is called prototyping. It's kinda rare if you're a C# programmer, but languages like python and javascript force you to be aware of this. Take this example from https://docs.python.org/3/tutorial/classes.html:
class Dog:
tricks = [] # mistaken use of a class variable
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # unexpectedly shared by all dogs
['roll over', 'play dead']
The method add_trick is defined with self as a first parameter, but the function is called as d.add_trick('roll over'). F# actually does this naturally as well, but in a way that mimics the way the function is called. When you declare:
member x.doSomething() = ...
or
member this.doSomething() = ...
Here, you are adding function doSomething to the prototype (or class definition) of "x"/"this". Thus, in your example, you actually have three type parameters, and three regular parameters, but one of them is not used in the call. All you have left is to declare the key selector function, and the element selector function, which you did. That's why it looks weird.

How to pass a "Function" type in FunScript?

I am encountering this Function type that I need to pass to a JQueryAnimationOptions object. I usually would pass a lambda to callbacks but these seem to be incompatible. I looked up every sample I could find in the FunScript repo. and couldn't find any workaround.
It also said the the Function is actually an interface (for what?) when used as a return statement Error: Invalid use of interface type.
So how to pass a callback argument with this Function type?
the code:
[<FunScript.JS>]
module Main
open FunScript
open FunScript.TypeScript
let sayHelloFrom (name:string) =
Globals.window.alert("Hello, " + name)
let jQuery (selector:string) = Globals.jQuery.Invoke selector
let main() =
let options = createEmpty<JQueryAnimationOptions>()
options.duration <- 3000
options.complete <- (fun _ -> sayHelloFrom("F#"))
let properties = createEmpty<Object>()
properties.Item("opacity") <- 1
let mainContent = jQuery "#mainContent"
mainContent.animate(properties, options) |> ignore
mainContent.click(fun e -> sayHelloFrom("F#") :> obj)
This works more or less as you would expect when passing lambdas between F# and C#. In F#, functions can be curried, while in C# (and JavaScript) cannot. So when you need to send a lambda from F# to C# you need to convert it first. In F# this is done by wrapping the lambda like this:
open System.Linq
open System.Collections.Generic
let ar = [|1;2;3|]
let f = fun (x: int) (y: int) -> x + y
let acc = ar.Aggregate( System.Func<int,int,int>(f) )
Actually, the F# compiler can deduce the types most of the times, so you only need to write: System.Func<_,_,_>(f). Furthermore, when passing a F# lambda to a method expecting a C# lambda, the compiler makes the wrapping automatically for you. Then the previous example becomes:
let ar = [|1;2;3|]
let acc = ar.Aggregate( fun x y -> x + y )
(Of course, in this case it would be better to use the idiomatic Array.reduce. This is just a contrived example.)
This works exactly the same when interacting with JS using FunScript. The only thing you need to be aware of is how F# lambdas get translated to JS. To allow currying, a lambda with two or more parameters like fun x y -> x + y becomes:
function (x) {
return function (y) {
return x + y;
}
}
Which may be a problem because the native JS will expect the following signature: function (x, y). In that case, you would have to wrap the lambda with System.Func<_,_,_>() as when interacting with C# (remember this is done automatically if you pass the lambda to a method).
However, lambdas with just one parameter don't suppose any problem: fun x -> x*x becomes function (x) { return x*x; }. In that case you don't need to wrap them (it doesn't hurt to do it anyway) and it's enough just to use unbox to appease the F# compiler when necessary. Just please be aware the FunScript compiler ignores unbox in the final JS code so there'll be no type check at all at runtime.
I hope the explanation is clear. Please add a comment if it isn't and I'll edit the answer.
Nevermind , I found the solution, I had to unbox the lambda:
options.complete <- unbox<Function> (fun _ -> sayHelloFrom("F#"))

F# and lisp-like apply function

For starters, I'm a novice in functional programming and F#, therefore I don't know if it's possible to do such thing at all. So let's say we have this function:
let sum x y z = x + y + z
And for some reason, we want to invoke it using the elements from a list as an arguments. My first attempt was just to do it like this:
//Seq.fold (fun f arg -> f arg) sum [1;2;3]
let rec apply f args =
match args with
| h::hs -> apply (f h) hs
| [] -> f
...which doesn't compile. It seems impossible to determine type of the f with a static type system. There's identical question for Haskell and the only solution uses Data.Dynamic to outfox the type system. I think the closest analog to it in F# is Dynamitey, but I'm not sure if it fits. This code
let dynsum = Dynamitey.Dynamic.Curry(sum, System.Nullable<int>(3))
produces dynsum variable of type obj, and objects of this type cannot be invoked, furthermore sum is not a .NET Delegate.So the question is, how can this be done with/without that library in F#?
F# is a statically typed functional language and so the programming patterns that you use with F# are quite different than those that you'd use in LISP (and actually, they are also different from those you'd use in Haskell). So, working with functions in the way you suggested is not something that you'd do in normal F# programming.
If you had some scenario in mind for this function, then perhaps try asking about the original problem and someone will help you find an idiomatic F# approach!
That said, even though this is not recommended, you can implement the apply function using the powerful .NET reflection capabilities. This is slow and unsafe, but if is occasionally useful.
open Microsoft.FSharp.Reflection
let rec apply (f:obj) (args:obj list) =
let invokeFunc =
f.GetType().GetMethods()
|> Seq.find (fun m ->
m.Name = "Invoke" &&
m.GetParameters().Length = args.Length)
invokeFunc.Invoke(f, Array.ofSeq args)
The code looks at the runtime type of the function, finds Invoke method and calls it.
let sum x y z = x + y + z
let res = apply sum [1;2;3]
let resNum = int res
At the end, you need to convert the result to an int because this is not statically known.

F# Function with parameter constraints

I ran into an error similar to this forum post on hubfs, which solved my problem but spawned off some questions about the code in that thread.
let test x = printfn "n"
let finall x = x : 'a -> unit
let i x = finall test x
Can someone explain to me what line 2 is accomplishing?
I see that the type of finall is
finall: ('a -> unit) -> ('a -> unit)
So its just a function that takes in a function and returns that function.
What would be the reason to do lines 2 and 3?
Can you later define a function body to finall?
it appears that you don't have to parenthesize the call on the third line, is that a result of line 2?
Yeah, the code on that thread does not make much sense. 'finall' is basically the identity function (let id x = x) except that it constrains its argument to be a function-returning-unit rather than some arbitrary value. Basically it doesn't do anything useful, you could just as easily write
let test x = printfn "n"
let i x = test x
I expect that this snippet maybe came from someone who started with an error message they didn't understand, and tried to strip it down to a tiny sample repro.
(Regarding function calls, you never need parens to call a let-bound function in F#:
f x
is a call, and function application works in the normal way to support currying, which means
f x y
means
(f x) y
which is what is happening on the 'finall test x' line.)

Resources