Related
I am completely at loss why this code doesn't mutate a member variable in a sequence of types:
for p in prescrs do
p.ATC <- "A"
for c in p.Drug.Components do
for s in c.Substances do
s.DoseTotal.Adjust <- adjustKg
s.DoseTotal.Time <- "DAY"
s.DoseTotal.Unit <- s.DrugConcentration.Unit
s.DoseRate.Adjust <- adjustKg
s.DoseRate.Time <- "DAY"
s.DoseRate.Unit <- s.DrugConcentration.Unit
prescrs is a sequence of Prescriptions which is a very simple 'POCO' defined as a type with member values. I don't have clue why this doesn't work.
I tried a simple test case like:
type IterTest () =
member val Name = "" with get, set
member val IterTests = [] |> List.toSeq : IterTest seq with get, set
let iterseq =
[
new IterTest(Name = "Test1")
new IterTest(Name = "Test2")
]
|> List.toSeq
iterseq |> Seq.iter(fun x -> x.IterTests <- iterseq)
iterseq |> Seq.iter(fun x ->
x.IterTests
|> Seq.iter(fun x' -> x'.Name <- "itered"))
But here the result is as expected. So, can't even quite reproduce my problem???
Found a solution (without really understanding the problem above). When I first convert the prescrs sequence to a list like:
let prescrs = prescrs |> Seq.toList
and then do the imperative looping, properties do get mutated.
Try this sample:
type Mutable() =
member val Iterated = false with get, set
let muts = Seq.init 5 (fun _ -> printfn "init"; Mutable())
let muts2 = muts // try again with let muts2 = muts |> List.ofSeq
printfn "Before iter"
for a in muts2 do
printfn "iter"
a.Iterated <- true
printfn "After iter"
muts2 |> List.ofSeq
and check how iter and init are interleaved.
Seqs are lazy, but are not cached once computed. So even if you imperatively try to mutate some of the elements in your prescrs sequence, it all goes away once you pull prescrs again. If you change prescrs into a concrete collection type like list before doing the mutation, you no longer hit the same problem. Note that things might get even trickier if what you have is a seq inside a seq inside a seq.
The best idea would be to avoid mutation in the first place though.
Given a list kinda like (simplified):
type foo(n:string,m:string,l:string) =
member f.name=n
member f.val1=m
member f.val2=l
let dates = [
foo("a","aa","aaa")
foo("b","bb","bbb")
]
How can a a immutable dictionary-type structure (eg, Map, IDictionary...any others?) of the form key:foo.name,value:foo be made?
My best guess was
let fooDict = for f in foo do yield f.name,f
But that for-comprehension syntax can only be used to make a list, array, or seq?
To create an immutable dictionary (the interface is mutable, but will throw an exception if you try to modify it)
[ for f in dates -> f.name,f ] |> dict
or
dates |> Seq.map (fun f -> f.name, f) |> dict
To create an immutable Map:
[ for f in dates -> f.name,f ] |> Map.ofSeq
or
dates |> Seq.map (fun f -> f.name, f) |> Map.ofSeq
I ended up with the more verbose (and ignorant of pipes):
Map.ofList([for f in foo do yield (f.name,f)])
Check out the dict function -- it takes a sequence of key-value tuples and creates an immutable dictionary from them.
With a list like the one you provided, you could use Seq.map to create the sequence, then pipe it into dict.
I'm reading Expert F# book and I found this code
open System.Collections.Generic
let divideIntoEquivalenceClasses keyf seq =
// The dictionary to hold the equivalence classes
let dict = new Dictionary<'key,ResizeArray<'T>>()
// Build the groupings
seq |> Seq.iter (fun v ->
let key = keyf v
let ok,prev = dict.TryGetValue(key)
if ok then prev.Add(v)
else let prev = new ResizeArray<'T>()
dict.[key] <- prev
prev.Add(v))
dict |> Seq.map (fun group -> group.Key, Seq.readonly group.Value)
and the example use:
> divideIntoEquivalenceClasses (fun n -> n % 3) [ 0 .. 10 ];;
val it : seq<int * seq<int>>
= seq [(0, seq [0; 3; 6; 9]); (1, seq [1; 4; 7; 10]); (2, seq [2; 5; 8])]
first for me this code is really ugly, even if this is safe, It looks more similar to imperative languages than to functional lang..specially compared to clojure. But the problem is not this...I'm having problems with the Dictionary definition
when I type this:
let dict = new Dictionary<'key,ResizeArray<'T>>();;
I get this:
pruebafs2a.fs(32,5): error FS0030: Value restriction. The value 'dict' has been inferred to have generic type
val dict : Dictionary<'_key,ResizeArray<'_T>> when '_key : equality
Either define 'dict' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
is It ok?...
thanks so much
improve question:
Ok I've been reading about value restriction and I found this helpfull information
In particular, only function definitions and simple immutable data
expressions are automatically generalized
...ok..this explains why
let dict = new Dictionary<'key,ResizeArray<'T>>();;
doesn't work...and show 4 different techniques, although in my opinion they only resolve the error but aren't solutions for use generic code:
Technique 1: Constrain Values to Be Nongeneric
let empties : int list [] = Array.create 100 []
Technique 3: Add Dummy Arguments to Generic Functions When Necessary
let empties () = Array.create 100 []
let intEmpties : int list [] = empties()
Technique 4: Add Explicit Type Arguments When Necessary (similar to tec 3)
let emptyLists = Seq.init 100 (fun _ -> [])
> emptyLists<int>;;
val it : seq<int list> = seq [[]; []; []; []; ...]
----- and the only one than let me use real generic code ------
Technique 2: Ensure Generic Functions Have Explicit Arguments
let mapFirst = List.map fst //doesn't work
let mapFirst inp = List.map fst inp
Ok, in 3 of 4 techniques I need resolve the generic code before can work with this...now...returning to book example...when the compile knows the value for 'key and 'T
let dict = new Dictionary<'key,ResizeArray<'T>>()
in the scope the code is very generic for let key be any type, the same happen with 'T
and the biggest dummy question is :
when I enclose the code in a function (technique 3):
let empties = Array.create 100 [] //doesn't work
let empties () = Array.create 100 []
val empties : unit -> 'a list []
I need define the type before begin use it
let intEmpties : int list [] = empties()
for me (admittedly I'm a little dummy with static type languages) this is not real generic because it can't infer the type when I use it, I need define the type and then pass values (not define its type based in the passed values) exist other way define type without be so explicit..
thanks so much..really appreciate any help
This line
let dict = new Dictionary<'key,ResizeArray<'T>>();;
fails because when you type the ;; the compiler doesn't know what 'key and 'T are. As the error message states you need to add a type annotation, or allow the compiler to infer the type by using it later or make it a function
Examples
Type annotation change
let dict = new Dictionary<int,ResizeArray<int>>();;
Using types later
let dict = new Dictionary<'key,ResizeArray<'T>>()
dict.[1] <- 2
using a function
let dict() = new Dictionary<'key,ResizeArray<'T>>();;
This actually doesn't cause an issue when it's defined all together. That is, select the entire block that you posted and send it to FSI in one go. I get this:
val divideIntoEquivalenceClasses :
('T -> 'key) -> seq<'T> -> seq<'key * seq<'T>> when 'key : equality
However, if you type these individually into FSI then as John Palmer says there is not enough information in that isolated line for the interpreter to determine the type constraints. John's suggestions will work, but the original code is doing it correctly - defining the variable and using it in the same scope so that the types can be inferred.
for me this code is really ugly, even if this is safe, It looks more similar to imperative languages than to functional lang.
I agree completely – it's slightly tangential to your direct question, but I think a more idiomatic (functional) approach would be:
let divideIntoEquivalenceClasses keyf seq =
(System.Collections.Generic.Dictionary(), seq)
||> Seq.fold (fun dict v ->
let key = keyf v
match dict.TryGetValue key with
| false, _ -> dict.Add (key, ResizeArray(Seq.singleton v))
| _, prev -> prev.Add v
dict)
|> Seq.map (function KeyValue (k, v) -> k, Seq.readonly v)
This allows sufficient type inference to obviate the need for your question in the first place.
The workarounds proposed by the other answers are all good. Just to clarify based on your latest updates, let's consider two blocks of code:
let empties = Array.create 100 []
as opposed to:
let empties = Array.create 100 []
empties.[0] <- [1]
In the second case, the compiler can infer that empties : int list [], because we are inserting an int list into the array in the second line, which constrains the element type.
It sounds like you'd like the compiler to infer a generic value empties : 'a list [] in the first case, but this would be unsound. Consider what would happen if the compiler did that and we then entered the following two lines in another batch:
empties.[0] <- [1] // treat 'a list [] as int list []
List.iter (printfn "%s") empties.[0] // treat 'a list [] as string list []
Each of these lines unifies the generic type parameter 'a with a different concrete type (int and string). Either of these unifications is fine in isolation, but they are incompatible with each other and would result in treating the int value 1 inserted by the first line as a string when the second line is executed, which is clearly a violation of type safety.
Contrast this with an empty list, which really is generic:
let empty = []
Then in this case, the compiler does infer empty : 'a list, because it's safe to treat empty as a list of different types in different locations in your code without ever impacting type safety:
let l1 : int list = empty
let l2 : string list = empty
let l3 = 'a' :: empty
In the case where you make empties the return value of a generic function:
let empties() = Array.create 100 []
it is again safe to infer a generic type, since if we try our problematic scenario from before:
empties().[0] <- [1]
List.iter (printfn "%s") (empties().[0])
we are creating a new array on each line, so the types can be different without breaking the type system.
Hopefully this helps explain the reasons behind the limitation a bit more.
Is there a shorter way of creating an IDictionary<_,obj>, possibly without boxing every value? This is what I have.
let values =
[ "a", box 1
"b", box "foo"
"c", box true ]
|> dict
Dictionary<_,obj>.Add can be called without boxing, but I couldn't figure out a way to use it that's shorter than what I have.
I'm hoping for something other than defining a boxing operator.
EDIT
Based on Brian's suggestion, here's one way to do it, but it has its own problems.
let values =
Seq.zip ["a"; "b"; "c"] ([1; "foo"; true] : obj list) |> dict
Here's a solution, following kvb's suggestion (probably the most concise, and clearest, so far):
let inline (=>) a b = a, box b
let values =
[ "a" => 1
"b" => "foo"
"c" => true ]
|> dict
Here's the slickest thing I was able to whip up. It has more characters than your boxing version, but possibly feels a little less dirty. Note that the ^ is right-associative (it's the string concat operator inherited from ocaml), which lets it work like ::, and it has stronger precedence than ,, which is why the parenthesis are needed around the tuples.
let inline (^+) (x1:'a,x2:'b) (xl:('a*obj) list) =
(x1,box x2)::xl
let values =
("a", 1) ^+ ("b", "foo") ^+ ("c", true) ^+ []
|> dict
I had a similar problem in FsSql and I just tucked away boxing in a function:
let inline T (a,b) = a, box b
let values = dict [T("a",1); T("b","foo"); T("c",true)]
Here's another "solution" which is inspired from Brian's suggestion but it uses reflection so there is a time and safety cost.
let unboxPair (pair:obj) =
let ty = pair.GetType()
let x = ty.GetProperty("Item1").GetValue(pair,null) :?> string
let y = ty.GetProperty("Item2").GetValue(pair,null)
x,y
let unboxPairs (pairs:obj list) =
pairs |> List.map unboxPair
let values =
unboxPairs
["a", 1
"b", "foo"
"c", true]
|> dict
A variation of Stephen's idea:
open System
open System.Collections.Generic
type Dictionary<'a,'b> with
member this.Add([<ParamArray>] args:obj[]) =
match args.Length with
| n when n % 2 = 0 ->
for i in 1..2..(n-1) do
this.Add(unbox args.[i-1], unbox args.[i])
| _ -> invalidArg "args" "even number of elements required"
let d = Dictionary<string,obj>()
d.Add(
"a", 1,
"b", "foo",
"c", true
)
Yet another solution, simply define a bunch of overloaded extension members on Dictionary<'a,'b>:
open System.Collections.Generic
type Dictionary<'a,'b> with
member this.Add(x1,y1,x2,y2) =
this.Add(x1,y1)
this.Add(x2,y2)
member this.Add(x1,y1,x2,y2,x3,y3) =
this.Add(x1,y1,x2,y2)
this.Add(x3,y3)
member this.Add(x1,y1,x2,y2,x3,y3,x4,y4) =
this.Add(x1,y1,x2,y2,x3,y3)
this.Add(x4,y4)
member this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5) =
this.Add(x1,y1,x2,y2,x3,y3,x4,y4)
this.Add(x5,y5)
member this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6) =
this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5)
this.Add(x6,y6)
//etc.
let values =
let d = Dictionary<_,obj>()
d.Add("a", 1,
"b", "foo",
"c", true)
d
Of course values here is not immutable like in your question, but I'm sure you could employ the same strategy in that goal.
let v : (string*obj) list = [...]
let values = dict v
Is one way, the type signature on the left of the list literal will auto-upcast each element.
What is the collection initializer syntax in F#? In C# you can write something like:
new Dictionary<string, int>() {
{"One", 1},
{"two", 2}}
How do I do the same thing in F#? I suppose i could roll my own syntax, but seems like there should be a built-in or standard one already.
To elaborate a bit on collection initialization in F#, here are a few examples:
read-only dictionary
dict [ (1, "a"); (2, "b"); (3, "c") ]
seq (IEnumerable<T>)
seq { 0 .. 99 }
list
[1; 2; 3; 4; 5]
set
set [1; 2; 3; 4; 5]
array
[| 1; 2; 3; 4; 5 |]
As Jared says, there is no built-in support for this for arbitrary collections. However, the C# code is just syntactic sugar for Add method calls, so you could translate it to:
let coll = MyCollectionType()
["One", 1; "Two", 2] |> Seq.iter coll.Add
If you want to get fancy, you could create an inline definition to streamline this even further:
let inline initCollection s =
let coll = new ^t()
Seq.iter (fun (k,v) -> (^t : (member Add : 'a * 'b -> unit) coll, k, v)) s
coll
let d:System.Collections.Generic.Dictionary<_,_> = initCollection ["One",1; "Two",2]
I don't believe F# has an explicit collection initializer syntax. However it's usually very easy to initialize F# collections. For example
let map = [ ("One", 1); ("Two", 2) ] |> Map.ofSeq
Getting to BCL collections is usually a bit more difficult because they don't always have the handy conversion functions. Dictionary<TKey, TValue> works though because you can use the LINQ method
let map =
let list = [ ("One", 1); ("Two", 2) ]
System.Linq.Enumerable.ToDictionary(list, fst, snd)
You can use the same :
open System.Collections.Generic
Dictionary<int, string>(dict [ (1, "a"); (2, "b"); (3, "c") ])
Cheers.
The lack of a collection initializer is annoying for some XAML-centric APIs like Workflow 4.0 which rely on collection initializers instead of ctors, e.g.
new Sequence { Activities = { WriteLine { Text = "In the sequence!" } } };
In such cases, imperative .Add() is awkward because the value is conceptually declarative even though it's technically mutable/imperative. However, there's no common base class for the set of all activities which declare an Activities child: the "Activities" member is a pattern and not an interface, so you can't just write a normal helper function which adds children to any activity. Fortunately, F# member constraints come to the rescue.
In order to write this:
Sequence() |> add [Sequence(DisplayName="InnerSeq"); WriteLine(Text = InArgument<_>("In the sequence!"))]
You first need to define an inline helper function called "add":
let inline add (children: Activity seq) =
let inline doAdd (activity: ^Activity) : ^Activity when ^Activity : (member get_Activities : unit -> Activity Collection) =
let collection = (^Activity : (member get_Activities : unit -> Activity Collection) (activity))
for child in children do
collection.Add(child)
activity
doAdd
This still isn't quite as nice as the C# syntax but at least it's still declarative. IMHO this is not so much as a fault with F# as with collection-initializer-centric APIs, but at least F# allows a workaround.
Given that the C# collection initializer syntax is syntactic sugar for calling .Add and that implies a mutable collection - I'm not sure you'll see any such syntax in F#. It's initialize all in one go as per JaredPar's answer, or do it manually.