Converting Discriminated Union case to string - f#

I am working on a FAKE project using F# - I am not fluent in F# or functional first programming, and am mostly doing front-end formatting. I am trying to set the color of an item based off of a class variable assigned to it. I am having issues converting this into string or using it in an if statement. I know its a long-shot, but are there any F# developers out there who might have experience in this area?
the class:
type State =
| New
| Open
| Closed
| Archived
the item to be recolored:
td [ ClassName "text-center" ] [ statusTag appt.state ]
I am primarily a C# developer, so the way that F# does things is very foreign. Normally i would just create an if statement and plug the state into it with a .ToString(), then use that to restyle but I am stumped as to how to go about it using F#. Any help would be greatly appreciated.

The usual way is to examine your value with a match expression:
let stateToColor state =
match state with
| New -> "red"
| Open -> "green"
| Closed -> "blue"
| Archived -> "yellow"
But of course you can also use an if expression, almost like in C#:
let stateToColor state =
if state = New then "red"
elif state = Open then "green"
elif state = Closed then "blue"
else "yellow"
The latter is a bit less safe though: if you later add another State and forget to also add it to stateToColor, the compiler will catch you if you use the match expression, but not for if/then/else.

Related

F# - Cleanest way to Extract/Unwrap an Expected Case's Typed Value from Discriminated Union?

The overall type structure and utilization in my current F# is working very well. However, I want to get some perspective if I am doing something incorrectly or following some kind of anti-pattern. I do find myself very often essentially expecting a particular type in particular logic that is pulling from a more general type that is a Discriminated Union unifying a bunch of distinct types that all follow layers of common processing.
Essentially I need particular versions of this function:
'GeneralDiscriminatedUnionType -> 'SpecificCaseType
I find myself repeating many statements like the following:
let checkPromptUpdated (PromptUpdated prompt) = prompt
This is the simplest way that I've found to this; however, every one of these has a valid compiler warning that makes sense that there could be a problem if the function is called with a different type than the expected. This is fair, but I so far have like 40 to 50 of these.
So I started trying the following out, which is actually better, because it would raise a valid exception with incorrect usage (both are the same):
let checkPromptUpdated input = match input with | PromptUpdated prompt -> prompt | _ -> invalidOp "Expecting Prompt"
let checkPromptUpdated = function | PromptUpdated prompt -> prompt | _ -> invalidOp "Expecting Prompt"
However, this looks a lot messier and I'm trying to find out if anyone has any suggestions prior to me doing this messiness all over.
Is there some way to apply this wider logic to a more general function that could then allow me to write this 50 to 100x in a cleaner and more direct and readable way?
This question is just a matter of trying to write cleaner code.
This is an example of a DU that I'm trying to write functions for to be able to pull the particular typed values from the cases:
type StateEvent =
| PromptUpdated of Prompt
| CorrectAnswerUpdated of CorrectAnswer
| DifficultyUpdated of Difficulty
| TagsUpdated of Tag list
| NotesUpdated of Notes
| AuthorUpdated of Author
If the checkPromptUpdated function only works on events that are of the PromptUpdated case, then I think the best design is that the function should be taking just a value of type Prompt (instead of a value of type StateEvent) as an argument:
let checkPromptUpdated prompt =
// do whatever checks you need using 'prompt'
Of course, this means that the pattern matching will get moved from this function to a function that calls it - or further - to a place where you actually receive StateEvent and need to handle all the other cases too. But that is exactly what you want - once you pattern match on the event, you can work with the more specific types like Prompt.
This works for me
let (TypeUWantToExtractFrom unwrappedValue) = wrappedValue

Difference between discriminated Union types in F#

I'm reading about F# and looking at people's source code and I sometimes see
Type test =
| typeone
| typetwo
And sometimes i see
type test = typeone | typetwo
One of them has a pipe before and the one doesn't. At first I thought one was an enum vs discriminated Union but I THINK they are the same. Can someone explain the difference if there is any?
There is no difference. These notations are completely equivalent. The leading pipe character is optional.
Having this first pipe optional helps make the code look nicer in different circumstances. In particular, if my type has many cases, and each case has a lot of data, it makes sense to put them on separate lines. In this case, the leading pipe makes them look visually aligned, so that the reader perceives them as a single logical unit:
type Large =
| Case1 of int * string
| Case2 of bool
| SomeOtherCase
| FinalCase of SomeOtherType
On the other hand, if I only need two-three cases, I can put them on one line. In that case, the leading pipe only gets in the way, creating a feeling of clutter:
type QuickNSmall = One | Two | Three
There is no difference.
In the spec, the first | is optional.
The relevant bit of the spec is this:
union-type-cases:= '|'opt union-type-case '|' ... '|'
union-type-case
An enum would needs to give explicit values to the cases like
Type test =
| typeone = 1
| typetwo = 2
As already mentioned, the leading | is optional.
The examples in the other answers do not show this, so it is worth adding that you can omit it even for a multi-line discriminated union (and include it when defining a single line union):
type Large =
Case1 of int * string
| Case2 of bool
| SomeOtherCase
| FinalCase of SomeOtherType
type QuickNSmall = | One | Two | Three
I think most people just find these ugly (myself included!) and so they are usually written the way you see in the other answers.

What's with "Uppercase variable identifiers should not generally be used in patterns..."?

This compiler like:
let test Xf Yf = Xf + Yf
This compiler no like:
let test Xfd Yfd = Xfd + Yfd
Warning:
Uppercase variable identifiers should not generally be used in patterns, and may indicate a misspelt pattern name.
Maybe I'm not googling properly, but I haven't managed to track down anything which explains why this is the case for function parameters...
I agree that this error message looks a bit mysterious, but there is a good motivation for it. According to the F# naming guidelines, cases of discriminated unions should be named using PascalCase and the compiler is trying to make sure that you don't accidentally misspell name of a case in pattern matching.
For example, if you have the following union:
type Side =
| Left
| Right
You could write the following function that prints "ok" when the argument is Left and "wrong!" otherwise:
let foo a =
match a with
| Lef -> printfn "ok"
| _ -> printfn "wrong!"
There is a typo in the code - I wrote just Lef - but the code is still valid, because Lef can be interpreted as a new variable and so the matching assigns whatever side to Lef and always runs the first case. The warning about uppercase identifiers helps to avoid this.
F# tries to enforce case rules for active patterns - consider what does this code do
let f X =
match X with
|X -> 1
|_ -> 2
This is quite confusing. Also, function parameters are similar to patterns, you can do
let f (a,b,_) = a,b
for example. Not quite sure why the third letter triggers the warning though

F#: combining together discriminated unions and class hierarchies?

Let's say I have a significant class hierarchy:
Tag
ControlFlowTag
IfTag
ForTag
JumpTag
HTMLTag
DivTag
and I want to make a list interspersed with these and strings.
let MyList = [tagA, tagB, "some text", tagC]
and I thought I could discriminated union it
type Node =
| Tag of Tag
| String of String
let MyList: list<Node> = [tagA, tagB, "some text", tagC]
but alas, it doesn't work without
let MyList: list<Node> = [Tag tagA, Tag tagB, String "some text", Tag tagC]
Obviously the Tag and String described in Node are orthogonal and separate from the existing Tag/String classes. Mousing over gives me the types as Node.Tag and Node.String, which isn't what I want.
What I have now is a function t which creates a StringTag which inherits from Tag, giving me
let MyList : list<Tag> = [tagA, tagB, t"some text", tagC]
which is pretty nice, but the extra t adds to the visual noise. What I actually want is a strongly typed "list of two different types" which I could work with using match statements. I thought that was the point of Discriminated Unions, but their inability to use existing type hierarchies is a problem, since the existing hierarchy (in this case Tag) is complex enough I think a full OO-inheritence approach to that subset of types is clearer than a pure Discriminated Union approach
One option is to just make it a list of obj and cast everything before/during the match, but that's not really very nice. Are there any other approaches?
If you had two different DUs, say
type Node =
| Tag of Tag
| String of String
and
type Foo =
| Bar of Tag
| Name of String
how would the compiler know of which type the following list is?
[tagA; tagB; "some text"; tagC]
As svick said, the discriminator is necessary. If you use classes instead you'll need to upcast to the base type, so I'm not sure you save on keystrokes.
If you're working with dictionaries, here is a nice option to reduce the syntactic noise of boxing. Maybe you can do something similar for lists.
I don't know how helpful this is, but you can use Active Patterns to match a class hierarchy in a DU-like fashion if appropriate.
[<AbstractClass>]
type Animal() =
abstract Talk : string
type Cat() =
inherit Animal()
override this.Talk = "Meow"
type Dog() =
inherit Animal()
override this.Talk = "Woof"
type SuperCat(s) =
inherit Cat()
override this.Talk = s
let animals : list<Animal> =
[Dog(); Cat(); SuperCat("MEOW")]
let (|SCSaid|_|) (a:Animal) = // Active Pattern
match a with
| :? SuperCat as sc -> Some sc.Talk
| _ -> None
for a in animals do
match a with
| :? Dog -> printfn "dog"
| SCSaid s -> printfn "SuperCat said %s" s // looks like DU
| _ -> printfn "other"
//dog
//other
//SuperCat said MEOW
Discriminated unions are just that – discriminated (unlike e.g. C unions). That means you have to always add the discriminator.
If this were C#, I would think about having an implicit conversion from string to StringTag. But since F# doesn't support implicit conversions, I think the second approach is your best bet. Although I would make the function's name more descriptive, not just t. Most of the time, it's better to write code that's easy to read, not code that's easy to write.

Simple type test in F#

I've been googling for a while now... Ok, I'm sorry, this one is pathetically easy but is there an operator in F# to compare class types, like the 'is' keyword in C#? I don't want to use a full blown match statement or start casting things. Cheers
You can use the :? construct both as a pattern (inside match) or as an operator:
let foo = bar :? System.Random
This behaves slightly differently than in C#, because the compiler still tries to do some checks at compile-time. For example, it is an error to use this if the result would be surely false:
let bar = 42
let foo = bar :? System.Random // Error
I don't think this could lead to confusion, but you can always add box to convert the argument to obj, which can be tested against any type:
let foo = box bar :? System.Random
If you want a general C#-to-F# quick-reference, see
http://lorgonblog.wordpress.com/2008/11/28/what-does-this-c-code-look-like-in-f-part-one-expressions-and-statements/
which answers this question and many others.

Resources