I am trying to make an immutable map of
in C#, I can turn a dictionary into a readonly one, achieving the same.
but it looks like, in F#, the first element decides the type of the rest of the map.
so I tried something ugly:
Map [
"key1", value1 |> obj
"key2", value2 |> obj
or
Map [
"key1", box value1
"key2", box value2
is there a better solution where the compiler would automatically box the items?
The problem I am trying to solve is to talk to an external C# library expecting a Dictionary and I'm trying to learn if the F# compiler can do this kind of things.
This question already has an answer, albeit for Dictionary<_,obj> rather than Map<_,obj>.
let (=>) k v = k, box v
// val ( => ) : k:'a -> v:'b -> 'a * obj
Map [ "key1" => 1; "key2" => 'a' ]
// val it : Map<string,obj> = map [("key1", 1); ("key2", 'a')]
Related
I have a JSON document that I'm parsing using Thoth.Json.Net. The document has an array containing a set of objects that each have a "type" attribute with a value that identifies their type. Each of these types needs a different decoder so I need to be able to provide some sort of filter based on the value of the "type" attribute. How can I do this?
Update:
After getting the "hack" that I describe above working, I revisited using the CE and decodeByType custom decoder, with each decoder returning a value from a Discriminated Union as mentioned by #tranquillity above. Once I had got my head around all the types the only thing I had to do was to specify the types for the Builder:
Builder: type DecoderBuilder () =
member __.Bind((decoder:Decoder<'a>), (func:('a -> Decoder<'b>))) =
Decode.andThen func decoder
This enabled the use of the CE to combine decoders easily as described by #brianberns below. I created a new file for the custom decoders and the Discriminated Union and found that I was able to extract the values from the JSON more closely to the domain model (making unrepresentable state impossible because an error will be returned if the JSON structure is invalid).
All in all cleaner, more functional, and elegant code. Thank you for the help.
I'm not a Thoth expert, but here's what I'd do. First, I find it easier to combine decoders using a computation expression:
type DecodeBuilder() =
member _.Bind(decoder, f) : Decoder<_> =
Decode.andThen f decoder
member _.Return(value) =
Decode.succeed value
member _.ReturnFrom(decoder : Decoder<_>) =
decoder
let decode = DecodeBuilder()
Then I invented two custom decoders, just as examples, and put them in a map by name. One reverses a string, and one decodes using the ROT13 cipher. Of course, you'll use your own custom decoders here instead:
let decodeReverse =
decode {
let! str = Decode.string
return str
|> Seq.rev
|> Seq.toArray
|> String
}
let decodeRot13 =
let rot13 c =
if 'a' <= c && c <= 'm' || 'A' <= c && c <= 'M' then
char (int c + 13)
elif 'n' <= c && c <= 'z' || 'N' <= c && c <= 'Z' then
char (int c - 13)
else c
decode {
let! str = Decode.string
return str
|> Seq.map rot13
|> Seq.toArray
|> String
}
let customDecoders =
Map [
"Reverse", decodeReverse
"Rot13", decodeRot13
]
Then, custom decoding is just a matter of decoding the "type" field, looking up the corresponding custom decoder, and using it to decode the "value" field:
let decodeByType =
decode {
let! typ = Decode.field "type" Decode.string
return! Decode.field "value" customDecoders.[typ]
}
Example usage:
Decode.fromString
(Decode.array decodeByType)
"""
[
{
"type" : "Reverse",
"value" : "edcba"
},
{
"type" : "Rot13",
"value" : "qrpbqr guvf"
}
]
"""
|> printfn "%A" // Ok [|"abcde"; "decode this"|]
I put the complete program here for reference.
Trying to learn F# and got stuck when trying to find a better approach of converting a csv file to a json array where each row + header is a json object in that array.
After some trial and error I finally caved and went for an ugly approach with mutable list and map. Are there any better ways this can be implemented?
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let mutable tempList = List.empty<Map<string,string>>
let heads =
match csvFile.Headers with
| Some h -> h
| None -> [|"Missing"|] // what to do here?
let nbrOfColumns = csvFile.NumberOfColumns
for row in csvFile.Rows do
let columns = row.Columns
let mutable tempMap = Map.empty<string,string>
for i = 0 to nbrOfColumns-1 do
tempMap <- tempMap.Add(heads.[i], columns.[i])
tempList <- tempMap :: tempList
System.Text.Json.JsonSerializer.Serialize(tempList)
This outputs the following which is the goal:
[
{
"Header1": "Row1Val1",
"Header2": "Row1Val2",
"Header3": "Row1Val3",
"Header4": "Row1Val4",
"Header5": "Row1Val5"
},
{
"Header1": "Row2Val1",
"Header2": "Row2Val2",
"Header3": "Row2Val3",
"Header4": "Row2Val4",
"Header5": "Row2Val5"
}
]
This is about as simple as I could make it, although a longer version might be more readable for you:
let csvFileToJsonList (csvFile: FSharp.Data.CsvFile) =
let heads = csvFile.Headers |> Option.defaultValue [||]
csvFile.Rows
|> Seq.map (fun row -> Seq.zip heads row.Columns |> Map)
|> System.Text.Json.JsonSerializer.Serialize
This produces the output in the original order, which I'm assuming is preferable (your solution reverses the order).
This also assumes some headers exist, otherwise the output will be empty objects.
Description: For each row use Seq.zip to produce a sequence of header-value tuples. Pass that to the Map constructor to create a map, providing a sequence of maps, which can be serialized.
Note that using dict instead of Map might be a bit faster.
You also could use CsvProvider to create a typed object (Row)
open FSharp.Data
type Persons =
CsvProvider<"David,Raab,19.02.1983",
Schema="First (string), Last (string), BirthDay(string)",
HasHeaders=true>
let parseCsv (reader:System.IO.TextReader) = [
let data = Persons.Load reader
for row in data.Rows do
Map [
("First", row.First)
("Last", row.Last)
("Birthday", row.BirthDay)
]
]
Returning a List of a map instead of Json, but i guess you will know how to change it to Serialze the data.
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.
I wrote the following function to view data in a grid from F# interactive:
open System.Windows.Forms
let grid x =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.DataSource <- x |> Seq.toArray
How can I make it work for both 1D and 2D seqs? say, grid [1,2,3] or grid[(1,0);(2,0);(3,0)];; works fine but grid [1;2;3];; would not work.
another question is, why do I have to add the `|>Seq.toArray to make it work?
DataGridView uses databinding that reflects over object properties and displays them in grid columns (possibly automatically inferred). [1,2,3] and [(1,0);(2,0);(3,0)] are lists of tuples so DataGridView can show tuple components, As opposite, [1;2;3] - list of integers, it doesn't contains any properties that exposes the actual value.
Seq.ToArray is necessary because DataSource expects IList, IListSource, IBindingList or IBindingListView (DataGridView.DataSource Property ). Array implements IList, F# list - doesn't.
As desco explains, the DataGridView control displays values of properties of the object.
This is pretty silly behavior for primitive types - for example if you specify [ "Hello"; "world!" ] as the data source, it will display column Length with values 5 and 6. That's definitely not what you'd want!
The best solution I could find is to explicitly check for strings and primitive types and wrap them in a simple type with just a single property (that will get displayed):
type Wrapper(s:obj) =
member x.Value = s.ToString()
let grid<'T> (x:seq<'T>) =
let form = new Form(Visible = true)
let data = new DataGridView(Dock = DockStyle.Fill)
form.Controls.Add(data)
data.AutoGenerateColumns <- true
if typeof<'T>.IsPrimitive || typeof<'T> = typeof<string> then
data.DataSource <- [| for v in x -> Wrapper(box v) |]
else
data.DataSource <- x |> Seq.toArray
grid [ 1 .. 10 ]
grid [ "Hello"; "World" ]
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.