I am trying to figure out to modify quotations and then evaluate them. Here I am starting basic and just trying to create a quotation using the Quotations api. The quotation binds OK, but I get an error when evaluating.
#r #"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.dll"
#r #"FSharpPowerPack-2.0.0.0\bin\FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
open Microsoft.FSharp.Linq
let hardway =
Expr.Let(
new Var("x", typeof<int>),
Expr.Value(10),
Expr.GlobalVar("x").Raw)
hardway.EvalUntyped()
Binding session to 'FSharp.PowerPack.Linq.dll'...
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer`1 comparer, TValue k, MapTree`2 m)
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 459
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 704
at Microsoft.FSharp.Linq.QuotationEvaluation.ConvExpr(ConvEnv env, FSharpExpr inp) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 677
at Microsoft.FSharp.Linq.QuotationEvaluation.CompileImpl[a](a e, Boolean eraseEquality) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 837
at Microsoft.FSharp.Linq.QuotationEvaluation.Expr.EvalUntyped(FSharpExpr ) in d:\codeplex\fspowerpack\May2010\src\FSharp.PowerPack.Linq\Linq.fs:line 854
at <StartupCode$FSI_0009>.$FSI_0009.main#()
Stopped due to error
To get this working using global variables, you'd need to write it like this:
let hardway =
Expr.Let(
Var.Global("x", typeof<int>),
Expr.Value(10),
(Expr.GlobalVar<int>("x")) )
hardway.EvalUntyped()
Var.Global and Expr.Global use some shared global dictionary of variables that the F# quotations library uses to make it possible to get the same variable instance without explicitly passing Var values around (as in Stringer's solution).
However, I think that creating Var value only once and then keeping a reference to the object (and ussing the same object in the expression) leads to more readable code, so I'd prefer Stringer's solution.
A few points about my code:
You need to use Var.Global instead of new Var because the second option doesn't store the variable in the global dictionary.
You need to specify the type explicitly in Expr.GlobalVar - if you don't do that, F# will use obj and that's a different variable (they are indexed by name and type).
I don't know how to use GlobalVar so I let others answer on this. Here's a workaround in waiting for a better solution:
let hardway =
let v = new Var("x", typeof<int>)
Expr.Let(
v,
Expr.Value(10),
Expr.Var(v))
let res = hardway.EvalUntyped() // res is 10
Unquote has a custom reflection-based evaluation engine which allows you to evaluate synthetic quotations by passing in a variable environment rather than needing to make the variable binding part of the expression itself. So you could do the following:
open Swensen.Unquote
open Microsoft.FSharp.Quotations
let unquoteway = Expr.Var(Var("x", typeof<int>))
let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)
This is interesting because the environment you pass in is the very environment used for all variable bindings and resolutions throughout the expression evaluation so variable scoping rules are honored:
let unquoteway =
Expr.NewTuple(
[Expr.Var(new Var("x", typeof<int>))
Expr.Let(new Var("x", typeof<string>), Expr.Value("hello"), Expr.Var(new Var("x", typeof<string>)))])
let environment = Map.ofList [("x", box 10)]
unquoteway.Eval(environment)
//FSI output:
val unquoteway : Expr = NewTuple (x, Let (x, Value ("hello"), x))
val environment : Map<string,obj> = map [("x", 10)]
val it : obj = (10, "hello")
Related
Let's say I wanted to have an alias of sprintf, I would simply do this:
namespace FSharp
module Core =
let specialsprintf x y =
sprintf x y
This would bring me the same compilation-time advantages (compared to its C# cousin API System.String.Format) of sprintf such as type-checking, checking number of parameters passed is correct, etc.
However, let's say I wanted to disable this compilation-time niceties and write a simple version of sprintf by calling String.Format underneath. Could this be possible? I know the goal sounds stupid but I want to do this mental exercise to make sure I understand how F# typing works here. If I do this (supposing we only can pass one parameter):
namespace FSharp
module Core =
let specialsprintf x y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
It doesn't even compile, the error is:
~/FSharpPlayground.fs(17,17): Error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. (FS0072) (FSharpPlayground)
Mmmm why?
Ok, if I specify the type like this:
namespace FSharp
module Core =
let specialsprintf
#if NORMAL_FSHARP
x
#else
(x: string)
#endif
y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
Then I end up with a compilation error in the caller:
~/FSharpPlaygroundUse.fs(48,48): Error FS0001: This expression was expected to have type 'obj []' but here has type 'string' (FS0001)
I guess I need now to qualify the type of y now, but not sure how to do it in case I wanted to extend it to be able to use 2 arguments instead of just 1 (I don't manage to make it work with the ParamArray attribute). Something tells me that I probably also need an uncurry function but I'm a bit lost :-/
I'm assuming that what you want is something like sprintf but variadic, and without type checking the format.
There's no 'uncurrying' or variable argument functions for F#, unfortunately.
That being said, there's the option of using a parameter array. ParamArray is only valid on class members not bindings, so we can settle for a static member which is similar in scope to a let fn () =.
type SpecialPrint =
static member sprintf (format, [<ParamArray>] args) =
let index = ref -1
let stringFormat = Regex.Replace(format, "%[a-z]", (fun _ -> sprintf "{%d}" (Interlocked.Increment index)))
String.Format(stringFormat, args)
With;
let result = SpecialPrint.sprintf ("Hello %s%s", "World", "!") //Hello World!
I need to call bool.TryParse in F# and I'm having a little difficulty with the compiler / Ionide.
Ex.
let value = true
let parsable = bool.TryParse("True", &value)
There error I'm seeing in Ionide for VSCode looks like the following.
val value : bool Full name:
value
Assembly: example3
The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In'F#
Compiler(1)
This is the first example that I've used call by ref keywords and syntax in F# so I'm not sure what I'm doing wrong and the byrefs documentation doesn't seem to be of much help on understanding this particular scenario.
It turns out that the main thing I was missing in my example was that value wasn't mutable as it would need to be when called in this context.
Working example:
let mutable value = true
let parsable = bool.TryParse("True", &value)
This solution came to me after reading a slightly related GitHub issue related to Span<T> and then also playing around in dotnet fsi which at least gave me the following clue.
let parsable = bool.TryParse("True", &value);;
-------------------------------------^^^^^^
stdin(34,38): error FS3230: A value defined in a module must be mutable in order to take its address, e.g. 'let mutable x = ...'
As it turns out however F# also seems to have sntaxtic sugar around the Try-Parse pattern which I began to recall after playing around with this example further. This reduced into the below alternative solution to calling bool.TryParse.
let value = true
let (parsable, _) = bool.TryParse "True"
Alternatively without having to bind parsable and to specify the default value within a single expression the following example may be more elegant.
let value = match bool.TryParse "True" with
| true, value -> value
| false, _ -> true
Perhaps there are pros and cons to the different ways of calling bool.TryParse and other Try-Parse methods but the important thing is that I found some solutions that work and get me past the initial stumbling blocks with regard to lack of F# documentation on the subject.
As you have already discovered, the error can be fixed by making the 'value' a mutable variable.
Saying that, the last solution solution you shared (using pattern matching) looks the nicest and safest.
If you happen to do many of these parsing operations, I would suggest extracting some utility functions. That will avoid having to correctly pattern match on (true, value) rather than (false, value) by mistake.
Sample code:
open System
module Option =
let ofTry<'a> (res:(bool*'a)) : 'a option =
match res with
| true, res -> Some res
| false, _ -> None
module Result =
let ofTry<'a,'b> (err:'b) (res:(bool*'a)) : Result<'a, 'b> =
res
|> csharpToOption
|> Option.toResult err
module Samples =
let withPatternMatch =
match Int32.TryParse "5" with
| true, value -> value |> Some
| false, _ -> None
let withOptionHelper = Int32.TryParse "5" |> Option.ofTry
let withResultHelper = Int32.TryParse "5" |> Result.ofTry "Not a number"
I have a Deedle DataFrame of type Frame<int,string> that contains some missing values. I would like to convert the missing values into empty strings "". I tried to use the valueOr function but that did not help. Is there a way to do this?
Here is my DataFrame:
let s1 = Series.ofOptionalObservations [ 1 => Some("A"); 2 => None ]
let s2 = Series.ofOptionalObservations [ 1 => Some("B"); 2 => Some("C") ]
let df = Frame.ofColumns ["A", s1; "BC", s2]
Typing df;; in FSI yields some information including
ColumnTypes = seq [System.String; System.String];. So the values of df are of type string and not string option.
This is the function valueOr:
let valueOr (someDefault: 'a) (xo: 'a option) : 'a =
match xo with
| Some v -> v
| None -> someDefault
I defined an auxiliary function emptyFoo as:
let emptyFoo = valueOr ""
The signature of emptyFoo is string option -> string. This means emptyFoo should not be acceptable to the compiler in the following command:
let df' = Frame.mapValues emptyFoo df
This is because the values of df are of type string and not string option.
Still, the compiler does not complain and the code runs. However, df' still has a missing value.
Is there a way to transform the missing value into the empty string?
The Deedle documentation for Frame.mapValues:
Builds a new data frame whose values are the results of applying the specified function on these values, but only for those columns which can be converted to the appropriate type for input to the mapping function
So the mapping does nothing because strings are found, rather than string options.
I noticed another function that seems to do exactly what you want.
let df' = Frame.fillMissingWith "" df
The key thing I noticed was that Deedle shows those missing values as <missing>, suggesting that it uses it's own representation (as opposed to option for example). With that knowledge I guessed that the library would provide some way of manipulating missing values, so I explored the API by doing Frame. in my IDE and browsing the list of available functions and their documentation.
I'm just beginning F# and haven't really done functional programming since my programming languages class 15 years ago (exception being "modern" C#).
I'm looking at this F# snippet using LINQPad 4:
let add x y = x + y
let lazyPlusOne x = lazy add x 1
let e = lazyPlusOne 15
Dump e
let plusOne x = add x 1
let f = plusOne 15
Dump f
The output it produces is:
Lazy<Int32>
Value is not created.
IsValueCreated False
Value 16
16
I understand the lazy keyword to delay evaluation until needed, same as C# delayed execution.
What is the meaning of: "Value is not created" here?
If you use lazy keyword to construct a lazy value (as in your lazyPlusOne function), then the result is a value of type Lazy<int>. This represents a value of type int that is evaluated only when it is actually needed.
I assume that Dump function tries to print the value including all its properties - when it starts printing, the value is not evaluated, so ToString method prints Value is not created. Then it iterates over other properties and when it accesses Value, the lazy value is evaluated (because its value is now needed). After evaluation, the property returns 16, which is then printed.
You can replace Dump with an F#-friendly printing function (or just use F# Interactive, which is extremely convenient way to play with F# inside Visual Studio with the usual IntelliSense, background error checking etec.)
F#-friendly printing function like printfn "%A" doesn't access the Value property, so it doesn't accidentally evaluate the value. Here is a snippet from F# Interactive:
> let a = lazy (1 + 2);;
val a : Lazy<int> = Value is not created. // Creates lazy value that's not evaluated
> a;;
val it : Lazy<int> = Value is not created. // Still not evaluated!
> a.Value;; // Now, the lazy value needs to be evaluated (to get the Value)
val it : int = 3
> a;; // After evaluation, the value stays cached
val it : Lazy<int> = 3
As of 'Dump e', 'lazyPlusOne 15' has not been evaluated. The 'let e = lazyPlusOne 15' does not require the evaluation of 'lazyPlusOne 15'. We don't yet need to know what e evaluates to yet.
The dump is triggering the evaluation and that is semantically different that just dumping the value after the evaluation.
The Google yields plenty of example of adding and deleting entries in an F# dictionary (or other collection). But I don't see examples to the equivalent of
myDict["Key"] = MyValue;
I've tried
myDict.["Key"] <- MyValue
I have also attempted to declare the Dictionary as
Dictionary<string, mutable string>
as well several variants on this. However, I haven't hit on the correct combination yet... if it is actually possible in F#.
Edit: The offending code is:
type Config(?fileName : string) =
let fileName = defaultArg fileName #"C:\path\myConfigs.ini"
static let settings =
dict[ "Setting1", "1";
"Setting2", "2";
"Debug", "0";
"State", "Disarray";]
let settingRegex = new Regex(#"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))")
do File.ReadAllLines(fileName)
|> Seq.map(fun line -> settingRegex.Match(line))
|> Seq.filter(fun mtch -> mtch.Success)
|> Seq.iter(fun mtch -> settings.[mtch.Groups.Item("key").Value] <- mtch.Groups.Item("value").Value)
The error I'm getting is:
System.NotSupportedException: This value may not be mutated
at Microsoft.FSharp.Core.ExtraTopLevelOperators.dict#37-2.set_Item(K key, V value)
at <StartupCode$FSI_0036>.$FSI_0036_Config.$ctor#25-6.Invoke(Match mtch)
at Microsoft.FSharp.Collections.SeqModule.iter[T](FastFunc`2 action, IEnumerable`1 sequence)
at FSI_0036.Utilities.Config..ctor(Option`1 fileName)
at <StartupCode$FSI_0041>.$FSI_0041.main#()
stopped due to error
f# has two common associative data structures:
The one you are most used to, the mutable Dictionary which it inherits that's to it's presence in the BCL and uses a hashtable under the hood.
let dict = new System.Collections.Generic.Dictionary<string,int>()
dict.["everything"] <- 42
The other is known as Map and is, in common functional style, immutable and implemented with binary trees.
Instead of operations that would change a Dictionary, maps provide operations which return a new map which is the result of whatever change was requested. In many cases, under the hood there is no need to make an entirely new copy of the entire map, so those parts that can be shared normally are. For example:
let withDouglasAdams = Map.add "everything" 42 Map.empty
The value withDouglasAdams will remain forever as an association of "everything" to 42. so if you later do:
let soLong = Map.remove "everything" withDouglasAdams
Then the effect of this 'removal' is only visible via the soLong value.
F#'s Map is, as mentioned, implemented as a binary tree. Lookup is therefore O(log n) whereas a (well behaved) dictionary should be O(1). In practice a hash based dictionary will tend to outperform the tree based one in almost all simple (low number of elements, low probability of collision) as such is commonly used. That said the immutable aspect of the Map may allow you to use it in situations where the dictionary would instead require more complex locking or to write more 'elegant' code with fewer side effects and thus it remains a useful alternative.
This is not however the source of your problem. The dict 'operator' returns an explicity immutable IDictionary<K,T> implementation (despite not indicating this in it's documentation).
From fslib-extra-pervasives.fs (note also the use of options on the keys):
let dict l =
// Use a dictionary (this requires hashing and equality on the key type)
// Wrap keys in an Some(_) option in case they are null
// (when System.Collections.Generic.Dictionary fails). Sad but true.
let t = new Dictionary<Option<_>,_>(HashIdentity.Structural)
for (k,v) in l do
t.[Some(k)] <- v
let d = (t :> IDictionary<_,_>)
let c = (t :> ICollection<_>)
let ieg = (t :> IEnumerable<_>)
let ie = (t :> System.Collections.IEnumerable)
// Give a read-only view of the dictionary
{ new IDictionary<'key, 'a> with
member s.Item
with get x = d.[Some(x)]
and set (x,v) = raise (NotSupportedException(
"This value may not be mutated"))
...
What error do you get? I tried the following and it compiles just fine
let map = new System.Collections.Generic.Dictionary<string,int>()
map.["foo"] <- 42
EDIT Verify that this code ran just fine as well .