My colleague forwarded me some code as below. I want to understand how symbol | operates. I have a rough idea that it is looping through NutritionData Tuple and storing unique values of food into string Foods. But is there something that I am missing? I searched for | online but wasnt able to find anything.
tuple FoodNutrition
{
key string food;
key string nutrient;
float amountPerServing;
};
{FoodNutrition} NutritionData = ...;
{string} Foods = {nd.food | nd in NutritionData};
{string} Nutrients = {nd.nutrient | nd in NutritionData};
Related
I guess this is pretty basic F# question:
Types are:
type Id1 =
| Id1 of int
type Id2 =
| Id2 of string
type Id =
| Id1
| Id2
type Child = {
Id : Id;
Smth : string list
}
type Node =
| Child of Child
| Compos of Node * Node
where Node and Child should represent replacement for Composite OOP design pattern.
The problem is that I cannot instantiate types in this way:
let i1 : Child = {Id = Id1(1); Smth = []} //Id1 value is not a function and cannot be applied
let i2 : Child = {Id = Id1(1); Smth = []} //same
let i3 : Node = Compos(i1, i2) //Expression expected Node but has Child
where compiler errors are given in the comments.
Your definition of Id has the same semantics as the following:
type T = int | string
Such type, which is just a mix of two other types, is commonly referred to as "non-discriminated union". To be fair, there are languages that support non-discriminated unions (e.g. TypeScript), but F# is not one of them. F# is part of the ML family of languages, which support discriminated unions. The "discriminated" part there means that the parts of the union need to be given a distinguishing property, a "discriminator", which is more commonly called "constructor". For example:
type T = X of int | Y of string
Here, X and Y are constructors of type T. They are used when constructing values to tell which variant is being constructed:
let t = X 42
And they are used during pattern matching to tell which variant is expected:
let f t = match t with
| X n -> printfn "it's a number: %d" n
| Y s -> printfn "it's a string: %s" s
You actually have one of those in your own code - Node, - so it baffles me a bit why you made this mistake with Id, but not with Node.
If you want to construct values of Id the way you do in the definition of i1 and i2 - i.e. Id1(1), - then you need to make Id a discriminated union with one of the constructors named Id1 and taking an int as parameter. From the rest of your code I can guess that the other constructor should be Id2 and take a string:
type Id = Id1 of int | Id2 of string
Now, an interesting thing to note is that, while my example type T above wouldn't compile, your type Id compiles just fine. Why is that?
The reason is that int and string have the wrong capitalization (union case identifiers must be uppercase), but Id1 and Id2 are fine in that respect. When you define your type as type Id = Id1 | Id2, that is perfectly legal, but those Id1 and Id2 have no relation to the previously defined types Id1 and Id2. They just happen to have the same name, and having the same name as previous definitions is allowed in F#. It is called "shadowing".
Your type Id ended up having two constructors, Id1 and Id2, both of which have no parameters. This is why the compiler complains when you're trying to pass 1 as parameter to Id1 as you write Id1(1): "Id1 is not a function and cannot be applied"
I am trying to find an elegant way of assigning keys to symbols without having to do something like the following.
let [<Literal>] North = ConsoleKey.UpArrow // etc.
I'd rather do something like this, using only one attribute. Is there any way I can do that?
[<Literal>]
type Direction =
| North of ConsoleKey.UpArrow
| East of ConsoleKey.RightArrow
| South of ConsoleKey.DownArrow
| West of ConsoleKey.LeftArrow
Assuming your aim is to use these in a pattern match, here is one way to do it:
// Use a type alias to shorten the name for ConsoleKey
type Key = ConsoleKey
// Create a general purpose active pattern that simply tests for equality
let (|Is|_|) a b = if a = b then Some () else None
// This is how you would use it
let describeMovement key =
match key with
| Is Key.UpArrow -> "up"
| Is Key.RightArrow -> "right"
| Is Key.DownArrow -> "down"
| Is Key.LeftArrow -> "left"
| _ -> "invalid"
How can I enforce the creation of a Discriminated Union value through a dedicated function?
Intent:
I want to rely on Creational Patterns to produce structures having valid data only.
Therefore, I believe that I will need to restrict the use of a DU value by making it read-only. However, it's not obvious to me how to accomplish that.
module File1 =
type EmailAddress =
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
module File2 =
open File1
let validEmail = Valid "" // Shouldn't be allowed
let isValid = createEmailAddress ""
let result = match isValid with
| Valid x -> true
| _ -> false
I tried the following:
type EmailAddress =
private
| Valid of string
| Invalid of string
However, setting the DU type as private breaks the ability to perform pattern matching on the result of the creation function.
This is just what springs to mind immediately.
You could use an active pattern to determine the cases you want to expose as an API to the outside world and then keep the internal representation of the DU completely private.
This would force you to use the publically exposed API to create the discriminated union but still allow pattern matching against the result - something like this:
module File1 =
type EmailAddress =
private
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
// Exposed patterns go here
let (|Valid|Invalid|) (input : EmailAddress) : Choice<string, string> =
match input with
| Valid str -> Valid str
| Invalid str -> Invalid str
module File2 =
open File1
let validEmail = Valid "" // Compiler error
let isValid = createEmailAddress "" // works
let result = // also works
match isValid with
| Valid x -> true
| _ -> false
Note that if you use the same pattern names, you may have to add the rather nasty type annotations shown above - these would be required to prevent a compiler error if the File2 module were not present - this could be relevant if you are exposing an API in a library but not making use of it. If you use different pattern names, that's obviously not an issue.
As you've discovered, the DU value names (Valid and Invalid in your example), used in pattern matches, are also the constructors of those respective cases. It is not possible to do what you're asking for, to hide one and expose the other. A different approach is needed.
One approach might be to do what Anton Schwaighofer suggests, and embed all the possible operations on your email addresses inside a dedicated module:
module EmailAddress =
type EmailAddress =
private
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
let isValid emailAddress =
match emailAddress with
| Valid _ -> true
| Invalid _ -> false
// Deliberately incomplete match in this function
let extractEmailOrThrow (Valid address) = address
let tryExtractEmail emailAddress =
match emailAddress with
| Valid s -> Some s
| Invalid _ -> None
See Scott Wlaschin's "Designing with types" series, and in particular http://fsharpforfunandprofit.com/posts/designing-with-types-more-semantic-types/ (and the gist he references at the end of that). I'd really recommend reading from the beginning of the series, but I've linked the most relevant one.
BUT... I would suggest a different approach, which is to ask why you want to enforce the use of those constructor functions. Are you writing a library for general-purpose use by beginning programmers, who can't be trusted to follow the directions and use your constructor function? Are you writing just for yourself, but you don't trust yourself to follow your own directions? OR... are you writing a library for reasonably-competent programmers who will read the comment at the top of the code and actually use the constructor functions you've provided?
If so, then there's no particular need to enforce hiding the DU names. Just document the DU like so:
module EmailAddress =
/// Do not create these directly; use the `createEmailAddress` function
type EmailAddress =
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
Then go ahead and write the rest of your code. Worry about getting your model right first, then you can worry about whether other programmers will use your code wrong.
It really depends on what you want to do. One way would to expose the states as member functions and act on those. This works in your case but could become cumbersome with 3 or more value constructors.
type EmailAddress =
private
| Valid of string
| Invalid of string
with
member this.IsValid() =
match this with
| Valid _ -> true
| _ -> false
member this.IsInvalid() = not <| this.IsValid()
Or you add a special map function
member this.Map (success, error) =
match this with
| Valid x -> Valid (success x)
| Invalid x -> Invalid (error x)
Adding to what the accepted answer implies, and what its commenters try to refute, my impression is that there is normally no need for type annotations. If you really consider hiding the representations of discriminated unions for binary compatible APIs as per F# Component Design Guidelines, a minimalistic and generic but complete reproduction could look like this:
module Foo =
type 'a Foo =
private | Bar of 'a
| Fred of string
let mkBar a = Bar a
let mkFred<'a> s : 'a Foo = Fred s
let (|Bar|Fred|) = function
| Bar a -> Bar a
| Fred s -> Fred s
The Union case constructors Bar and Fred are inaccessible from outside module Foo, and replaced by functions doubling as hooks for validation. For consumers, we have the Active recognisers Bar and Fred instead.
let bar = Foo.mkBar 42
let fred = Foo.mkFred<int> "Fred"
[Foo.mkBar 42; Foo.mkFred "Fred"]
|> List.filter (function Foo.Bar _ -> true | _ -> false)
When using union types with quite a few constructors I almost always find myself implementing lots of logic in single function, i.e. handling all cases in one function. Sometimes I would like to extract logic for single case to separate function, but one cannot have a function accepting only one "constructor" as parameter.
Example:
Assume that we have typical "expression" type :
type Formula =
| Operator of OperatorKind * Formula * Formula
| Number of double
| Function of string * Formula list
[...]
Then, we would like to calculate expression :
let rec calculate efValues formula =
match formula with
| Number n -> [...]
| Operator (kind, lFormula, rFormula) -> [...]
| [...]
Such function would be very long and growing with every new Formula constructor.
How can I avoid that and clean up such code? Are long pattern matching constructs inevitable?
You can define the Operator case of the Formula union using an explicit tuple:
type Formula =
| Operator of (string * Formula * Formula)
| Number of double
If you do this, the compiler will let you pattern match using both Operator(name, left, right) and using a single argument Operator args, so you can write something like:
let evalOp (name, l, r) = 0.0
let eval f =
match f with
| Number n -> 0.0
| Operator args -> evalOp args
I would find this a bit confusing, so it might be better to be more explicit in the type definition and use a named tuple (which is equivalent to the above):
type OperatorInfo = string * Formula * Formula
and Formula =
| Operator of OperatorInfo
| Number of double
Or perhaps be even more explicit and use a record:
type OperatorInfo =
{ Name : string
Left : Formula
Right : Formula }
and Formula =
| Operator of OperatorInfo
| Number of double
Then you can pattern match using one of the following:
| Operator args -> (...)
| Operator { Name = n; Left = l; Right = r } -> (...)
I would say you typically want to handle all the cases in a single function. That's the main selling point of unions - they force you to handle all the cases in one way or another. That said, I can see where you're coming from.
If I had a big union and only cared about a single case, I would handle it like this, wrapping the result in an option:
let doSomethingForOneCase (form: Formula) =
match form with
| Formula (op, l, r) ->
let result = (...)
Some result
| _ -> None
And then handle None in whatever way is appropriate at the call site.
Note that this is in line with the signature required by partial active patterns, so if you decide that you need to use this function as a case in another match expression, you can easily wrap it up in an active pattern to get the nice syntax.
I'm using an active pattern to parse usage events in a csv formatted usage log. The active pattern part is listed below. Parsing the whole file in works well and the sequence that is produced is filled with all sorts of UsageEvents.
type SystemName = string
type SystemVersion = string
type MAC = string
type Category = string
type Game = string
type Setting = string
type StartupLocation = string
type UsageEvent =
| SystemStart of DateTime * SystemVersion * SystemName * MAC
| SystemEnd of DateTime
| GameStart of DateTime * Category * Game * Setting * StartupLocation
| GameEnd of DateTime * Category * Game
| Other
let (|SystemStart|SystemEnd|GameStart|GameEnd|Other|) (input : string list) =
match List.nth input 0 with
| "SystemStartedEvent" ->
SystemStart (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3, List.nth input 4)
| "SystemEndedEvent" ->
SystemEnd (DateTime.Parse (List.nth input 1))
| "GameStartedEvent" ->
GameStart (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3, List.nth input 4, List.nth input 5)
| "GameEndedEvent" ->
GameEnd (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3)
| _ ->
Other
The problem I have is that I'm probably using the ActivePattern in the wrong way. I'd like to walk the list to create a tree out of it based on some logic, but I have no way to match an entry in the sequence after parsing.
let CountSystemStart (entries : UsageEvent list) =
let rec loop sum = function
| SystemStart(_,_,_,_) -> sum + 1
| _ -> sum
loop 0 entries
This matching does not work because the loop function required a string list. In what other way could I use the data contained in the unions or should I match the input and then store it in a regular type?
To add to #Petr's answer - UsageEvent cases and your active pattern cases have the same names, so the active pattern which is defined later shadows the union type. That's where the string list thing comes from, most likely.
I would just drop the active pattern altogether, and add a Parse function (or rather a ParseParts, since you want to feed it a list of strings) to the UsageEvent.
type UsageEvent =
| SystemStart of DateTime * SystemVersion * SystemName * MAC
| (...and so on...)
static member ParseParts (input: string list) =
match input with
| ["SystemStartedEvent"; date; version; name; mac] ->
SystemStart (DateTime.Parse date, version, name, mac)
| (...and so on...)
Active patterns are cute, but you really need a good scenario for them to shine. Otherwise if you can get away with using a plain function, just use a plain function.
There are 2 problems with this code:
Discriminated union UsageEvent and active pattern choice functions have the same names
recursive loop function is not recursive as it is written - it doesn't call itself.
When you are matching on UsageEvent list try use full type name.
I would rewrite your CountSystemStart function as:
let CountSystemStart (entries : UsageEvent list) =
let rec loop sum = function
| [] -> sum
| (UsageEvent.SystemStart(_))::rest -> loop (sum + 1) rest
| _::rest -> loop sum rest
loop 0 entries