Firstly, apologies for the poor title - I don't understand enough F# to describe the problem better.
Consider this simple DU:
type Money =
| USD of decimal
| GBP of decimal
| EUR of decimal
static member (+) (first: Money, second: Money) =
match first, second with
| USD(x), USD(y) -> USD(x + y)
| GBP(x), GBP(y) -> GBP(x + y)
| EUR(x), EUR(y) -> EUR(x + y)
| _ -> failwith "Different currencies"
I'm representing money in different currencies, and overloading the (+) operator so that I can safely do Money + Money. However, if I have many currencies then the match statement will become tedious to write. Is there any way of expressing something like:
match first, second with
| _(x), _(y) -> _(x + y)
Or is there a different way to achieve the same result? I've considered and discarded units of measure due to the limitations described here.
Does this work for you?
type Kind = | USD | GBP | EUR
type Money =
| Money of Kind * decimal
static member (+) (first: Money, second: Money) =
match first, second with
| Money(k1,x), Money(k2,y) when k1=k2 -> Money(k1, x + y)
| _ -> failwith "Different currencies"
Related
I created a discriminated union which has three possible options:
type tool =
| Hammer
| Screwdriver
| Nail
I would like to match a single character to one tool option. I wrote this function:
let getTool (letter: char) =
match letter with
| H -> Tool.Hammer
| S -> Tool.Screwdriver
| N -> Tool.Nail
Visual Studio Code throws me now the warning that only the first character will be matched and that the other rules never will be.
Can somebody please explain this behaviour and maybe provide an alternative?
That's not how characters are denoted in F#. What you wrote are variable names, not characters.
To denote a character, use single quotes:
let getTool (letter: char) =
match letter with
| 'H' -> Tool.Hammer
| 'S' -> Tool.Screwdriver
| 'N' -> Tool.Nail
Apart from the character syntax (inside single quotes - see Fyodor's response), you should handle the case when the letter is not H, S or N, either using the option type or throwing an exception (less functional but enough for an exercise):
type Tool =
| Hammer
| Screwdriver
| Nail
module Tool =
let ofLetter (letter: char) =
match letter with
| 'H' -> Hammer
| 'S' -> Screwdriver
| 'N' -> Nail
| _ -> invalidArg (nameof letter) $"Unsupported letter '{letter}'"
Usage:
> Tool.ofLetter 'S';;
val it : Tool = Screwdriver
> Tool.ofLetter 'C';;
System.ArgumentException: Unsupported letter 'C' (Parameter 'letter')
I'm pretty new to functional programming and I've started looking at the documentation for match statements and in the example I came across here gitpages and cut and pasted to my question below:
let rec fib n =
match n with
| 0 -> 0
| 1 -> 1
| _ -> fib (n - 1) + fib (n - 2)
I understand that let is for static binding in this case for a recursive function called fib which takes a parameter n. It tries to match n with 3 cases. If it's 0, 1 or anything else.
What I don't understand is what the | symbol is called in this context or why it is used? Anything I search for pertaining to f-sharp pipe takes me to this |> which is the piping character in f sharp.
What is this | used for in this case? Is it required or optional? And when should be and shouldn't I be using |?
The | symbol is used for several things in F#, but in this case, it serves as a separator of cases of the match construct.
The match construct lets you pattern match on some input and handle different values in different ways - in your example, you have one case for 0, one for 1 and one for all other values.
Generally, the syntax of match looks like this:
match <input> with <case_1> | ... | <case_n>
Where each <case> has the following structure:
<case> = <pattern> -> <expression>
Here, the | symbol simply separates multiple cases of the pattern matching expression. Each case then has a pattern and an expression that is evaluated when the input matches the pattern.
To expand on Tomas's excellent answer, here are some more of the various uses of | in F#:
Match expressions
In match expressions, | separates the various patterns, as Tomas has pointed. While you can write the entire match expression on a single line, it's conventional to write each pattern on a separate line, lining up the | characters, so that they form a visual indicator of the scope of the match statement:
match n with
| 0 -> "zero"
| 1 -> "one"
| 2 -> "two"
| 3 -> "three"
| _ -> "something else"
Discriminated Unions
Discriminated Unions (or DUs, since that's a lot shorter to type) are very similar to match expressions in style: defining them means listing the possibilities, and | is used to separate the possibilities. As with match expressions, you can (if you want to) write DUs on a single line:
type Option<'T> = None | Some of 'T
but unless your DU has just two possibilities, it's usually better to write it on multiple lines:
type ContactInfo =
| Email of string
| PhoneNumber of areaCode : string * number : string
| Facebook of string
| Twitter of string
Here, too, the | ends up forming a vertical line that draws the eye to the possibilities of the DU, and makes it very clear where the DU definition ends.
Active patterns
Active patterns also use | to separate the possibilities, but they also are wrapped inside an opening-and-closing pair of | characters:
let (Even|Odd) n = if n % 2 = 0 then Even else Odd // <-- Wrong!
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd // <-- Right!
Active patterns are usually written in the way I just showed, with the | coming immediately inside the parentheses, which is why some people talk about "banana clips" (because the (| and |) pairs look like bananas if you use your imagination). But in fact, it's not necessary to write the (| and |) characters together: it's perfectly valid to have spaces separating the parentheses from the | characters:
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd // <-- Right!
let ( |Even|Odd| ) n = if n % 2 = 0 then Even else Odd // <-- ALSO right!
Unrelated things
The pipe operator |> and the Boolean-OR operator || are not at all the same thing as uses of the | operator. F# allows operators to be any combination of symbols, and they can have very different meanings from an operator that looks almost the same. For example, >= is a standard operator that means "greater than". And many F# programs will define a custom operator >>=. But although >>= is not defined in the F# core library, it has a standard meaning, and that standard meaning is NOT "a lot greater than". Rather, >>= is the standard way to write an operator for the bind function. I won't get into what bind does right now, as that's a concept that could take a whole answer all on its own to go through. But if you're curious about how bind works, you can read Scott Wlaschin's series on computation expressions, which explains it all very well.
I am a new programmer in general, and as well to F#. I've ran into this particular problem several times, and have yet to solve it efficiently in my opinion. Here is the problem:
I have these example types:
type Retail1 = | Fashion | Auto | Sports
type Wholesale1 = | Fashion | Auto | Sports
type Events1 = | Wedding | Birthday
type Product =
| Retail of Retail1 | Wholesale of Wholesale1 | Events of Events1
| NoProduct
I want to convert the possibility of the first three types to the Product type via a function:
let convertToProduct (retail: Retail1 option)
(wholesale: Wholesale1 option) (events: Events1 option) =
// convert to Product here
if retail.IsSome then Retail retail
elif wholesale.IsSome then Wholsale wholseale
elif events.IsSome then Events events
else NoProduct
The way that I have handled it in the pass is just to chain a long if elif statement together to check for each condition and return the final type of Product, but this does not feel correct, or at the very least idiomatic to F#. What would be the recommended approach to this problem?
How about something like this:
let convertToProduct (retail: Retail1 option) (wholesale: Wholesale1 option) (events: Events1 option) =
match (retail, wholesale, events) with
|Some rt, None, None -> Retail rt
|None, Some wh, None -> Wholesale wh
|None, None, Some ev -> Events ev
|_ -> NoProduct
This exploits the fact that if you convert all the arguments into a tuple, you can do pretty concise pattern matching on the result.
Pattern matching is actually extremely powerful, you can find more details about the types of pattern matching you can perform in the MSDN documentation.
Would I have to resort to F#'s object oriented design support to implement a method that returns void?
Specifically, what if I just wanted to print a message within a function?
Would I just have to create a member method within F# to accomplish this?
Example:
dealPlayer Hit {Face = Ace; Suit = Spades}
NOTE:
I am still learning F#. I'm apologize if this question appears ignorant.
type Suit = | Spades
| Clubs
| Diamonds
| Hearts
type Face = | Two | Three | Four | Five
| Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
type Card = {Face:Face; Suit:Suit}
type Deal = | Hand of Card * Card
| Hit of Card
let dealPlayer dealType =
match dealType with
| Hand (card1, card2) -> printfn "%A" (card1, card2)
| Hit card -> printfn "%A" card
dealPlayer Hit {Face = Ace; Suit = Spades}
As #Functional_S answers, you can use printfn, but as a general observation, one of the main benefits of functional programming is to avoid side-effects.
Ultimately, all programs have side-effects, but the functional approach is to push the side-effects to the edge of whatever system you're building. (Incidentally, this is also true for most maintainable, successful object-oriented architectures; only you get less support from languages like C# or Java for doing that.)
So instead of letting dealPlayer have side-effects, make it a pure function:
let dealPlayer dealType =
match dealType with
| Hand (card1, card2) -> sprintf "%A" (card1, card2)
| Hit card -> sprintf "%A" card
This changes the type of the function to Deal -> string. (The name of the function may now be a bit misleading, though.)
At the edge of your system, you can still print the value if you want to, by piping the string to printfn:
> dealPlayer (Hit {Face = Ace; Suit = Spades}) |> printfn "%s";;
{Face = Ace;
Suit = Spades;}
val it : unit = ()
That's much more flexible because you postpone the decision to introduce side-effects until such a time that you can no longer postpone it.
You can use this, it print pretty well for small samples
let print x = printfn "%+A" x
Or if you need a return value
let toString x = sprintf "%+A" x
I'm new to F# and not quite familiar with the whole pattern matching idea.
I tried to search for a better solution to my problem but I fear I can't even express the problem properly – I hope the question title is at least somewhat accurate.
What I want to do is extract 2 "parameters" from listMethod.
listMethod is of one of several types that have a string and an Expression "parameter" (I suspect parameter is the wrong term):
let (varDecl, listExpr) =
match listMethod with
| Select (var, expr) -> (var, expr)
| Where (var, expr) -> (var, expr)
| Sum (var, expr) -> (var, expr)
| Concat (var, expr) -> (var, expr)
Then I continue to work with varDecl and at the end have a similar match expression with the actual listMethod code that makes use of several temporary variables I created based on varDecl.
My question now is: How can I make the above code more compact?
I want to match all those types that have 2 parameters (of type string and Expression) without listing them all myself, which is kinda ugly and hard to maintain.
The ListMethod type is declared as follows (the whole thing is a FsLex/FsYacc project):
type ListMethod =
| Select of string * Expr
| Where of string * Expr
| Sum of string * Expr
| Concat of string * Expr
| ...
| somethingElse of Expr
(as of now I only have types of the form string * Expr, but that will change).
I reckon that this is a fairly dumb question for anyone with some experience, but as I've said I'm new to F# and couldn't find a solution myself.
Thanks in advance!
Edit: I'd really like to avoid listing all possible types of listMethod twice. If there's no way I can use wildcards or placeholders in the match expressions, perhaps I can modify the listMethod type to make things cleaner.
One option that comes to mind would be creating only 1 type of listMethod and to create a third parameter for the concrete type (Select, Where, Sum).
Or is there a better approach?
This is probably the standard way:
let (varDecl, listExpr) =
match listMethod with
| Select (var, expr)
| Where (var, expr)
| Sum (var, expr)
| Concat (var, expr) -> (var, expr)
The | sign means or, so if one of these match, the result will be returned. Just make sure that every case has exactly the same names (and types).
As Chuck commented, this is an even better solution:
let (Select (varDecl, expr)
| Where (varDecl, expr)
| Sum (varDecl, expr)
| Concat (varDecl, expr)) = listMethod
I reckon that this is a fairly dumb question for anyone with some experience, but as I've said I'm new to F# and couldn't find a solution myself.
On the contrary, this is a very good question and actually relatively untrodden ground because F# differs from other languages in this regard (e.g. you might solve this problem using polymorphic variants in OCaml).
As Ankur wrote, the best solution is always to change your data structure to make it easier to do what you need to do if that is possible. KVB's solution of using active patterns is not only valuable but also novel because that language feature is uncommon in other languages. Ramon's suggestion to combine your match cases using or-patterns is also good but you don't want to write incomplete pattern matches.
Perhaps the most common example of this problem arising in practice is in operators:
type expr =
| Add of expr * expr
| Sub of expr * expr
| Mul of expr * expr
| Div of expr * expr
| Pow of expr * expr
| ...
where you might restructure your type as follows:
type binOp = Add | Sub | Mul | Div | Pow
type expr =
| BinOp of binOp * expr * expr
| ...
Then tasks like extracting subexpressions:
let subExprs = function
| Add(f, g)
| Sub(f, g)
| Mul(f, g)
| Div(f, g)
| Pow(f, g) -> [f; g]
| ...
can be performed more easily:
let subExprs = function
| BinOp(_, f, g) -> [f; g]
| ...
Finally, don't forget that you can augment F# types (such as union types) with OOP constructs such as implementing shared interfaces. This can also be used to express commonality, e.g. if you have two overlapping requirements on two types then you might make them both implement the same interface in order to expose this commonality.
In case you are ok to do adjustments to your data structure then below is something that will ease out the pattern matching.
type ListOperations =
Select | Where | Sum | Concat
type ListMethod =
| ListOp of ListOperations * string * Expr
| SomethingElse of int
let test t =
match t with
| ListOp (a,b,c) -> (b,c)
| _ -> ....
A data structure should be designed by keeping in mind the operation you want to perform on it.
If there are times when you will want to treat all of your cases the same and other times where you will want to treat them differently based on whether you are processing a Select, Where, Sum, etc., then one solution would be to use an active pattern:
let (|OperatorExpression|_|) = function
| Select(var, expr) -> Some(Select, var, expr)
| Where (var, expr) -> Some(Where, var, expr)
| Sum (var, expr) -> Some(Sum, var, expr)
| Concat (var, expr) -> Some(Concat, var, expr)
| _ -> None
Now you can still match normally if you need to treat the cases individually, but you can also match using the active pattern:
let varDecl, listExp =
match listMethod with
| OperatorExpression(_, v, e) -> v, e
| _ -> // whatever you do for other cases...