How do i apply both hard-coded and method classes in Elmish? - f#

I am formatting a web application made using F# and the SAFE stack. I am using a variable to determine a CSS class to change the formatting of a tag, but I also need two hard-coded CSS classes, and I am unsure how to have both.
I have this:
let statusTag (state:Appointment.State) =
span [ Class (state.ToString()) ] [ str (sprintf "%A" state) ]
And i need it to work more like this:
let statusTag (state:Appointment.State) =
span [ Class "status text" + (state.ToString()) ] [ str (sprintf "%A" state) ]
But i dont know how to do this in F#
Any help would be appreciated

The only thing that seems wrong with your attempt is that you need extra parentheses around the expression that constructs the string with the names of the classes (on the other hand, you do not need it around the state.ToString() call). The following should do the trick:
let statusTag (state:Appointment.State) =
span [ Class("status text" + state.ToString()) ] [ str (sprintf "%A" state) ]

Related

How can I make a Map[string, obj] in F#?

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')]

Dealing with .NET generic dictionaries in F#?

I am not a functional programmer.
I am learning F#.
I got a problem here.
Let me start from following piece of code:
type XmlNode(tagName, innerValue) =
member this.TagName = tagName
member this.InnerValue = innerValue
member this.Atts = Dictionary<string, obj>()
I don't use F# dict because (as I know) that one is readonly, however I obviously need to modify my attributes.
So I am really struggling to make it pure functional way:
type XmlNode with member this.WriteTo (output:StringBuilder) =
output.Append("<" + this.TagName) |> ignore
//let writeAtts =
// List.map2 (fun key value -> " " + key + "=" + value.ToString())
(List.ofSeq this.Atts.Keys) (List.ofSeq this.Atts.Values)
// |> List.reduce (fun acc str -> acc + " " + str)
//output.Append((writeAtts)) |> ignore
output.Append(">" + this.InnerValue + "</" + this.TagName + ">") |> ignore
output
The code I commented out was my (probably stupid) attemp to use mapping and reduction to concat all the atts in the single correctly formatted string. And that compiles OK.
But when I try to access my Atts property:
[<EntryPoint>]
let main argv =
let root = new XmlNode("root", "test")
root.Atts.Add("att", "val") // trying to add a new KVP
let output = new StringBuilder()
printfn "%O" (root.WriteTo(output))
Console.ReadLine()|>ignore
0 // return an integer exit code
...new attribute does not appear inside the Atts property, i.e. it remains empty.
So:
1) help me to make my code more functional.
2) and to understand how to deal with modificable dictionaries in F#.
Thank you.
First, your immediate problem: the way you defined the Atts property, it's not one value that is "stored" somewhere and is accessible via property. Instead, your definition means "every time somebody reads this property, create a new dictionary and return it". This is why your new attribute doesn't appear in the dictionary: it's a different dictionary every time you read root.Atts.
To create a property with a backing field and initial value, use member val:
type XmlNode(...) =
...
member val Atts = Dictionary<string,object>()
Now, answers to some implied questions.
First order of business: "modify the attributes" and "purely functional" are contradictory ideas. Functional programming implies immutable data. Nothing changes ever. The way to advance your computation is to create a new datum at every step, without overwriting the previous one. This basic idea turns out to be immensely valuable in practice: safer threading, trivial "undo" scenarios, trivial parallelization, trivial distribution to other machines, and even reduced memory consumption via persistent data structures.
Immutability is a very important point, and I urge you not to glance over it. Accepting it requires a mental shift. From my own (and other people I know) experience, it is very hard coming from imperative programming, but it is well worth it.
Second: do not use classes and properties. Technically speaking, object-oriented programming (in the sense of message passing) is not contradictory to functional, but the Enterprise flavor that is used in practice and implemented in C++, Java, C# et al., is contradictory, because it emphasizes this idea that "methods are operations that change an object's state", which is not functional (see above). So it's better to avoid object-oriented constructs, at least while you're learning. And especially since F# provides much better ways to encode data:
type XmlNode = { TagName: string; InnerValue: string; Atts: (string*string) list }
(notice how my Atts is not a dictionary; we'll come to this in a bit)
Similarly, to represent operations on your data, use functions, not methods:
let printNode (node: XmlNode) = (* we'll come to the implementation later *)
Third: why do you say that you "obviously" need to modify the attributes? The code you've shown does not call for this. For example, using my definition of XmlNode above, I can rewrite your code this way:
[<EntryPoint>]
let main argv =
let root = { TagName = "root"; InnerValue = "test"; Atts = ["att", "val"] }
printfn "%s" (printNode root)
...
But even if that was a real need, you shouldn't do it "in place". As I've described above while talking about immutability, you should not mutate the existing node, but rather create a new node that differs from the original one in whatever way you wanted to "modify":
let addAttr node name value = { node with Atts = (name, value) :: node.Atts }
In this implementation, I take a node and name/value of an attribute, and produce a new node whose Atts list consists of whatever was in the original node's Atts with the new attribute prepended.
The original Atts list stays intact, unmodified. But this does not mean twice the memory consumption: because we know that the original list never changes, we can reuse it: we create the new list by only allocating memory for the new item and including a reference to the old list as "other items". If the old list was subject to change, we couldn't do that, we would have to create a full copy (see "Defensive Copy"). This strategy is known as "Persistent Data Structure". It is one of the pillars of functional programming.
Finally, for string formatting, I recommend using sprintf instead of StringBuilder. It offers similar performance benefits, but in addition provides type safety. For example, code sprintf "%s" 5 will not compile, complaining that the format expects a string, but the final argument 5 is a number. With this, we can implement the printNode function:
let printNode (node: XmlNode) =
let atts = seq { for n, v in node.Atts -> sprintf " %s=\"%s\"" n v } |> String.concat ""
sprintf "<%s%s>%s</%s>" node.TagName atts node.InnerValue node.TagName
For reference, here's your complete program, rewritten in functional style:
type XmlNode = { TagName: string; InnerValue: string; Atts: (string*string) list }
let printNode (node: XmlNode) =
let atts = seq { for n, v in node.Atts -> sprintf " %s=\"%s\"" n v } |> String.concat ""
sprintf "<%s%s>%s</%s>" node.TagName atts node.InnerValue node.TagName
[<EntryPoint>]
let main argv =
let root = { TagName = "root"; InnerValue = "test"; Atts = ["att", "val"] }
printfn "%s" (printNode root)
Console.ReadLine() |> ignore
0

F# Data: JSON Parser. Using JsonExtensions

It is my first question on SO...so do not judge strictly =)
Usually all my questions techout in chat rooms (believe me, a lot of them =)).
Recently, we are talking about the RosettaCode. And I wondered to complement some of the tasks code to F#
One of them is JSON.
One of the possible solutions is the use of "F# Data: JSON Parser". So my question is linked with it.
This code works well:
open FSharp.Data
open FSharp.Data.JsonExtensions
type Person = {ID: int; Name:string}
let json = """[ { "ID": 1, "Name": "First" }, { "ID": 2, "Name": "Second" }]"""
json |> printfn "%s"
match JsonValue.Parse(json) with
| JsonValue.Array(x) ->
x |> Array.map(fun x -> {ID = System.Int32.Parse((x?ID).ToString()); Name = (string x?Name)})
| _ -> failwith "fail json"
|> Array.iter(fun x -> printfn "%i %s" x.ID x.Name)
Print:
[ { "ID": 1, "Name": "First" }, { "ID": 2, "Name": "Second" }]
1 "First"
2 "Second"
But it
{ID = System.Int32.Parse((x?ID).ToString()); Name = (string x?Name)}
doesn't look good.
This I read about JsonExtensions,
but when I use
{ID = (x?ID.AsInteger()) ; Name = (x?Name.AsString()) }
I get compile errors:
The field, constructor or "AsInteger" is not defined
The field, constructor or "AsString" is not defined
Strangely, thing is that I see accessibility through "open FSharp.Data.JsonExtensions"
So, question: How to use JsonExtensions?
I tried to reproduce this using a minimal example, but I do not get the error - can you try the following minimal sample?
#r "...../FSharp.Data.dll"
open FSharp.Data.JsonExtensions
open FSharp.Data
JsonValue.Parse("A").AsArray()
|> Array.map (fun a -> a?ID.AsInteger())
I do not get auto-completion on a?ID. (which is a limitation of the editor), but it compiles fine.
The only reason why I think this could be not working is if you had another open declaration that would import another implementation of the ? operator that is not returning JsonValue.
The JsonValue API is certainly not as nice as just using the type provider - so if you can, I'd probably go for the type provider instead (the low-level API is good if you need to iterate over everything in JSON recursively).

Delete third element in F# list

I am writing a function to return a list minus the third value.
Here is my current code:
let listString = [ "1"; "2"; "3"; "4" ];;
let del3 (listA :'a) = [listA.Head; listA.Tail.Head] # [listA.Tail.Tail.Tail];;
del3 listString
and I am getting the error:
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.
What should I change to fix the error?
I think a simpler approach based on a pattern match might be better
let del3 = function |a::b::c::d -> a::b::d | _ -> failwith "insufficient input"
You need to let the compiler know that listA is a list. Also Tail returns a list, so for the second list you're appending you don't want to wrap the tail in a list, otherwise you're going to have a list of a list:
let listString = [ "1"; "2"; "3"; "4" ]
let del3 (listA :'a list) = [listA.Head; listA.Tail.Head] # listA.Tail.Tail.Tail
del3 listString;;
A solution to handle lists of all sizes:
let del3 = function
| a::b::c::tail -> a::b::tail
| list -> list
When accessing members, methods or properties of an object, F# needs to know the type of that object. It can't just infer the type from the fact that you're accessing a property named Head because there might be many different classes that have such a property.
To fix this problem, either give listA a type annotation or use List.head and List.tail instead of the properties.

F# collection initializer syntax

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.

Resources