Is there a shorthand for Boolean `match` expressions? - f#

Is there a shorthand for the match expression with isVertical here?
let bulmaContentParentTile isVertical nodes =
let cssClasses =
let cssDefault = [ "tile"; "is-parent" ]
match isVertical with
| true -> cssDefault # [ "is-vertical" ]
| _ -> cssDefault
div [ attr.classes cssClasses ] nodes
I assume that an expression like match isVertical with is so common that there is a shorthand like the one we have for function, no?

Yes, it's just an if-expression:
let cssClasses =
let cssDefault = [ "tile"; "is-parent" ]
if isVertical then
cssDefault # [ "is-vertical" ]
else cssDefault
Quoting from the F# docs:
Unlike in other languages, the if...then...else construct is an expression, not a statement. That means that it produces a value, which is the value of the last expression in the branch that executes.

It's a bit off-topic but you can build your list by using Sequence Expressions which is IMHO more readable for this use case.
let cssClasses = [
"tile"
"is-parent"
if isVertical then
"is-vertical"
]

Related

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

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

(F#) Inbuilt function to filter a list if it does not contain a specific value

My question is regarding list filtering in F#. Is there a built in function that allows the filtering of lists where it only returns those that do not satisfy a condition?
let listOfList = [ [1;2;3;4;5]; [6;7;8;9;10]; [11;2;5;14;1] ]
let neededValue = 1
I know that F# features List.Contains() however I want to only return lists which do not satisfy the condition.
let sortedLists = listOfList |> List.filter(fun x -> x <> x.Contains(neededValue)
This obviously does not work because in this instance I'm comparing a list to whether a list contains a specific value. How would I do this? My desired output in this instance would be:
sortedLists = [ [6;7;8;9;10] ]
You were so close! Change x <> to not <|, and it will work.
let listOfList = [ [1;2;3;4;5]; [6;7;8;9;10]; [11;2;5;14;1] ]
let neededValue = 1
let sortedLists = listOfList |> List.filter(fun x -> not <| x.Contains(neededValue))
The not function allows you to negate a boolean value, so that the types in the filter expression match up.
In f# it's more idiomatic to use
List.contains neededValue x
instead of
x.Contains(neededValue)
So I would express it like this
let sortedLists =
listOfList
|> List.filter (List.contains neededValue >> not)

Is a pattern match the only way to get data associated with a union case?

Let's say you have this union:
type Thing =
| Eagle
| Elephant of int
And your code has a list of Elephants, as in
let l = [Elephant (1000); Elephant (1200)]
And you wanted to iterate over l, and print out the data associated with each Elephant. Is there a way to do so without using a pattern match?
In your example, you say that you have a list of elephants - which is true in this case - but the type of l is really a list of Thing values and so it can contain both elephants and eagles. This is why you need to use pattern matching - to handle all possible cases.
If you regularly need to use list that contain only elephants, then it might make sense to define a separate type of elephants. Something like:
type ElephantInfo = { Size : int }
type Thing =
| Elephant of ElephantInfo
| Eagle
Now you can create a list of type list<ElephantInfo> which can contain just elephants and so you don't need pattern matching:
let l1 = [ {Size=1}; {Size=2} ]
for el in l1 do printfn "%d" el.Size
On the other hand, if you want to mix elephants and eagles, you'll create list<Thing> and then use pattern matching:
let l2 = [ Elephant {Size=1}; Eagle ]
You could do this:
l
|> List.collect (function Elephant x -> [x] | _ -> [])
|> List.iter (printfn "%i")
Prints
1000
1200
It still uses pattern matching, but it's fairly minimal.
You have of course the option of going full Ivory Tower (® Scott Wlaschin)
As in about:
type Thing =
| Eagle
| Elephant of int
type MaybeElephantBuilder() =
member this.Bind(x, f) =
match x with
| Eagle -> 0
| Elephant a -> f a
member this.Return(x) = x
let maybeElephant = new MaybeElephantBuilder()
let l =
[ Elephant(1000)
Elephant(1200)
]
let printIt v =
let i =
maybeElephant {
let! elephantValue = v
return elephantValue
}
printfn "%d" i
l |> Seq.iter printIt
It will even handle the stuff with the Eagles thrown in there!
Well...
Remove the non-Eagles and the code will fly...
let l =
[ Eagle
Leadon
Elephant(1000)
Eagle
Meisner
Elephant(1200)
Eagle
Felder
]
l |> Seq.iter printIt
But no. Its not nice. Its not short. Its more for fun (if that!) than anything else. Its probably the worst misuse of F# computation expressions ever too!
And you will need pattern matching somewhere.
Thx Scott! And Petricek.
Computation Expression Zoo for real! ;-)
You can use reflection from Microsoft.FSharp.Reflection Namespace but it is much more cumbersome and slow.
Pattern matching is probably the easiest way to get data from discriminated union.
(Also you have a list of Things all its members happen to be of Elephant union case).
There's a way to place the pattern match into the header of the function (or a let binding). It is still a pattern match, though.
// This function takes a tuple:
// the first argument is a Thing,
// the second is "default" weight to be processed if the first one is NOT an Elephant
let processElephant (Elephant weight, _ | _, weight) =
weight
let [<Literal>] NON_ELEPHANT_WEIGHT = -1
// usage:
let totalWeight =
[Elephant (1000); Elephant (1200)]
|> List.sumBy (fun el -> processElephant(el, NON_ELEPHANT_WEIGHT))
This question and its answers provide with more details.

F# pattern match directly against let binding

Is it possible in F# to pattern match directly against a let binding?
For example, this compiles without any warnings:
let value =
match arg with
| 1 -> "value1"
| 2 -> "value2"
| _ -> failwith "key not found"
Whereas the following gives the warning "This rule will never be matched" against the lines matching key2 and _:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
Is this because although they're immutable, the let bindings are unlike C# const variables?
just use capital letters and [<Literal>] them and it works as expected.
let [<Literal>] X = 0
let [<Literal>] Y = 1
let bla arg =
match arg with
| X -> "zero"
| Y -> "one"
| somethingelse -> somethingelse.ToString()
the lower case name by convention typically means a wildcard that is bound to the name.
The reason you're getting that error is because of what F# is doing when you use a variable name in the pattern clause of a match expression.
Let's say I have
match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"
I think it's key here to note that, despite not defining x or y prior to the match, this code will still work. This is because x and y are just short codes which makes writing match expressions easier. Behind the scenes, the F# compiler is actually converting that x when x = 0 into "let binding" where x is bound to arg. x can then be used in the x = 0 expression and in the expression after the ->.
Going back to the problem you ran into:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
The reason this won't work, is because in the match expression, F# is rebinding key1 to the value of arg, so key1 -> "value1" is equivalent toif arg1 = arg1 then "value1". The first pattern will always be matched; so, key2 and _ will never be reached.
I'm not sure how clear my explanation is, so I'll also throw in a second approach to explaining what's happened:
if you translate the match expression into an if-else it would look like this:
let key1 = 1
let key2 = 2
let value =
if let key1 = arg in arg = key1 then
"value1"
else if let key2 = arg in arg = key2 then
"value2"
else
failwith "key not found"
(why yes, F# will let you throw let bindings into if expressions)
This if/else expression is equivalent to your match expression. In this form it becomes clear that the first condition will always evaluate to true.
I won't put it in here, but it may help to look at the code quotation of a match expression. I didn't really get what was going on with match expressions until I saw what the abstract syntax tree they generated looked like.
You can only use literals if you want to match against a particular value in a pattern matching case. An identifier means binding -- i.e. the actual value in this pattern matching case will be bound to the identifier that will be visible in the scope of this case.
As #DanielFabian has shown, you can define your own literals and give them names.
If the value you need to match against isn't known at compile time, you can use guards like so:
match arg with
| x when x = key1 -> "value1"
| x when x = key2 -> "value2"
| _ -> // etc
See the MSDN article on pattern matching for more details.
There are two main issues raised by the code you are trying to use.
Firstly pattern matching:
match arg with
| _ -> "value"
matches arg with anything and then returns "value"
match arg with
| a -> "value"
matches arg with anything, calls it "a", and then returns "value". You can think of the match having it's own little namespace, the a only exists in the match, and the match only 'sees' the things that have been named in it.
Secondly, if you want to match to a set of predefined values, then you probably want to use discriminated unions. You can define one like this:
type Keys=
| Key1
| Key2
Then match like this:
match arg with
| Key1 -> "value1"
| Key2 -> "value2"
In this case it matches against the type Keys, not a value called Key1 or Key2.

Concisely creating an IDictionary<_,obj>

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.

Resources