Match within a match? - f#

Is there a way to do a match within a match in F#? I've noticed that you can do one tailed on another like so...
match L.Head with
| null -> []
| _ -> match N with
| 1 -> [L.Head]
| _ -> []
But is there a way to do it so that a match, ending with a _ can be placed in the MIDDLE of another match? This seems to give a bug... is there a better way to do this, should you need it for your logic? EX:
match A with
| 0 -> match B with
| 1 -> 1
| _ -> 0
| _ -> 2

Why not use match on a tuple -
match (A,B) with
|0,1 -> 1
|0,_ -> 0
|_, -> 2

Not sure whether it was possible 7 years ago, but now you can use struct to reduce allocations:
match struct (A, B) with
| 0, 1 -> 1
| 0, _ -> 0
| _ -> 2
Old answer creates instance of System.Tuple`2, while this creates instance of System.ValueTuple`2
Decompilation

Related

Can one set default values for Discriminated Union types?

I implemented a Discriminated Union type that would be used to select a function:
type BooleanCombinator =
| All
| Some
| None
| AtLeast of int
| MoreThan of int
| NotMoreThan of int
| LessThan of int
| ExactlyOne
| ExactlyTwo
| AllButOne
| AllButTwo
let boolToInt (b: bool) : int = if b then 1 else 0
let combineBooleans (combinator : BooleanCombinator)
(bools : bool list)
: bool =
let n = List.sumBy boolToInt bools
match combinator with
| BooleanCombinator.All -> List.forall id bools
| BooleanCombinator.Some -> bools |> List.exists id
| BooleanCombinator.None -> bools |> List.exists id |> not
| BooleanCombinator.AtLeast i -> n >= i
| BooleanCombinator.MoreThan i -> n > i
| BooleanCombinator.NotMoreThan i -> n <= i
| BooleanCombinator.LessThan i -> n < i
| BooleanCombinator.ExactlyOne -> n = 1
| BooleanCombinator.ExactlyTwo -> n = 2
| BooleanCombinator.AllButOne -> n = bools.Length - 1
| BooleanCombinator.AllButTwo -> n = bools.Length - 2
This looked Ok to me but the compiler started to look at all instances of Some and None as belonging to this DU, instead of the Option DU.
I do not want to go through all of my code replacing Some with Option.Some and None with Option.None.
Is there a way to tell the compiler that unqualified Some and None are actually Option.Some and Option.None?
Or should I just give different names to these DU cases, like AtLeastOne and ExactlyZero
The general rule for resolving name collisions in F# is "last declaration wins". Because your custom DU is declared after Option, its constructors Some and None win over those of Option.
But this rule offers a way to fix the problem: you just need to "reassert" the declarations after your custom DU:
type Bogus = Some of int | None
let g = function Some _ -> 42 | None -> 5
let x = Some 42
let inline Some a = Option.Some a
let inline None<'a> = Option.None : 'a option
let (|Some|None|) = function | Option.Some a -> Some a | Option.None -> None
let f = function Some _ -> 42 | None -> 5
let y = Some 42
If you inspect the types of g, x, f, and y in the above code:
> g
g : Bogus -> int
> f
f : 'a option -> int
> x
Bogus
> y
int option
The function g and value x were inferred to have type Bogus -> int and Bogus respectively, because Some and None in their bodies refer to Bogus.Some and Bogus.None.
The function f and value y were inferred to have Option-related types, because Some and None in their bodies refer to the Some function and the (|Some|None|) active pattern that I defined just above.
Of course, this is a rather hacky way to restore status quo. This will convince the compiler, but humans will still have a hard time reading your code. I suggest you rename the cases of your DU instead.
You can mark your DU with [<RequireQualifiedAccess>] attribute.
This means that you will be required to qualify the case name with the type whenever you use it in the code - which is something you do now anyway in your match expression.
That way an unqualified Some would still be resolved to mean Option.Some, despite the fact that you reuse the name.
It's a useful technique to know when you want to use a snappy name for a DU case - like None, Yes, Failure etc. - that by itself would be ambiguous or confusing to the reader (or the compiler, for that matter).

F# function calling isn't working properly

I'm having a problem with a piece of code in F# that I wrote. I made a stack structure in F#, also made push and pop function, and all seems working fine. I also made some instruction (ADD, MULT, PUSH, ABS) that work with integer items inside the stack.
I made a function which serves as interpreter for the instructions; it gets in input a stack and an instruction, and the output is the stack with the result of the instruction in it. When I try to use push function inside the interpreter, it dosen't work any more, it completely ignores the command.
type stack =
| Stck of int list
type instr =
| ADD
| MULT
| PUSH of int
| ABS
let stackPush stck num =
match stck with
| Stck(someList) ->
match someList with
| [] -> Stck[num]
| _ -> Stck(num::someList)
let stackPop stck =
match stck with
| Stck(someList) ->
match someList with
| [] -> Stck[]
| _::xEnd -> Stck(xEnd)
let getFirstItem stck =
match stck with
| Stck(someList) ->
match someList with
| [] -> 0
| [xOnly] -> xOnly
| xStart::_ -> xStart
let exec stck instr =
match stck with
| Stck(someList) ->
match someList with
| [] -> Stck[]
| [xOnly] -> Stck[xOnly]
| xStart::xMid::xEnd ->
let tempStack = stackPop(stackPop(stck))
match instr with
| ADD ->
match tempStack with
| _ -> Stck((xStart + xMid)::xEnd)
| MULT ->
match tempStack with
| _ -> Stck((xStart * xMid)::xEnd)
| PUSH x -> stackPush stck x
| ABS -> Stck(abs( xStart)::xEnd)
The problems comes when I run them
let mutable stackProva = Stck[]
stackProva <- exec stackProva (PUSH 5) //not working
When I run the exec stackProva (PUSH 5) , the result I get is an empty stack
stackProva <- stackPush stackProva -3 //working
When I run stackPush stackProva -3 , it actually put the integer -3 inside the stack. They are doing the same stuff for what I think, but in one way it works, in the other (the one I really want) it is not working.
What I expect after running both these command I having stackProva containing [-3;5], but it just contains [-3].
Thanks for any help you could give me.
The problem lies in your implementation of exec. In case it takes empty stack it returns immediately with empty stack.
Here is working version:
type Stack = Stack of int list
type Instruction =
| ADD
| MULT
| ABS
| PUSH of int
let push num (Stack stack) = Stack (num::stack)
let pop (Stack stack) =
match stack with
| [] -> []
| _::tail -> tail
let tryGetFirstItem (Stack stack) = List.tryHead stack
let exec instr (Stack stack) =
match stack, instr with
| s1::s2::tail, ADD -> Stack (s1+s2::tail)
| s1::s2::tail, MULT -> Stack (s1*s2::tail)
| s1::tail, ABS -> Stack (abs(s1)::tail)
| _, PUSH x -> push x (Stack stack)
| x, _ -> Stack x
Stack []
|> exec (PUSH 1)
|> exec (PUSH 2)
|> exec ADD
|> tryGetFirstItem
|> printfn "%A" //prints "Some 3"

How to Return Specific Discriminated Union from Function

I have a hierarchy of discriminated unions.
type SpecificNoun =
| Noun
| NounPhrase
| Pronoun
| PosesivePronoun
type SpecificModifier =
| Adverb //slowly, quickly, verb + ly (90% of the time)
| Preposition //off, on, together, behind, before, between, above, with, below
type SpecificVerb =
| ActionVerb
| BeingVerb
| PossesiveVerb
| TransitiveVerb
type PartsOfSpeech =
| Noun of SpecificNoun
| Verb of SpecificVerb
| Adjective
| Punctuation
| Modifier of SpecificModifier
I need to translate a string into one of them, but it has to be a PartOfSpeech so I can use it in my match cases. The below code does not compile.
let StringToPartOfSpeech (part:string) =
match part with
| "Noun" -> SpecificNoun.Noun
| "NounPhrase" -> SpecificNoun.NounPhrase
| "Pronoun" -> SpecificNoun.Pronoun
| "PossessivePronoun" -> SpecificNoun.PosesivePronoun
| "Adverb" -> SpecificModifier.Adverb
This is a related question to this: F# - Can I return a discriminated union from a function however, in my case, everything is just straight discriminated unions
You need to return a consistent type from all branches. In your case the PartsOfSpeech type is ideal.
So that means you need to take a type like SpecificNoun.Noun and wrap it in the appropriate case from PartsOfSpeech.
Also, what if the input string doesn't match any of the cases?
In the code below I decided to return a PartsOfSpeech option, but you could raise an exception,
or return a more detailed Success/Failure type, etc.
let StringToPartOfSpeech (part:string) =
match part with
| "Noun" ->
SpecificNoun.Noun |> PartsOfSpeech.Noun |> Some
| "NounPhrase" ->
SpecificNoun.NounPhrase |> PartsOfSpeech.Noun |> Some
| "Pronoun" ->
SpecificNoun.Pronoun |> PartsOfSpeech.Noun |> Some
| "PossessivePronoun" ->
SpecificNoun.PosesivePronoun |> PartsOfSpeech.Noun |> Some
| "Adverb" ->
SpecificModifier.Adverb |> PartsOfSpeech.Modifier |> Some
| _ -> None
Your code doesn't compile because you are returning two values with different types :
let StringToPartOfSpeech (part:string) =
match part with
| "Noun" -> Noun // type of SpecificNoun
| "NounPhrase" ->NounPhrase // type of SpecificNoun
| "Pronoun" -> Pronoun // type of SpecificNoun
| "PossessivePronoun" ->PosesivePronoun // type of SpecificNoun
| "Adverb" -> Adverb // type of SpecificModifier
Why you didn't use your type PartsOfSpeech ?
Try the following code :
type PartsOfSpeech =
| PNoun of SpecificNoun
| PVerb of SpecificVerb
| PAdjective
| PPunctuation
| PModifier of SpecificModifier
| PUnknown
let StringToPartOfSpeech (part:string) =
match part with
| "Noun" -> PNoun (Noun)
| "Adverb" -> PModifier (Adverb)
| _ -> PUnknown
Plus, to avoid compiler warnings, I add a case for a Unknown String.

F#: Nested discriminated unions and matching

I have 2 nested discriminated unions:
type ServiceTypes =
| Contexts
| Context of int
| Producers
type ServiceActions =
| Get of ServiceTypes
| Update of ServiceTypes
And a nested match statement:
let s_action = match action with
| Get(stype) -> sprintf "Get%s" (match stype with
| Contexts -> sprintf "Contexts"
| Context(id) -> (sprintf "Context/%d" id))
| _ -> raise (RequestException("get"))
| Update(stype) -> sprintf "Update%s" (match stype with
| Producers -> (sprintf "Producers")
| _ -> raise (RequestException("update")))
The goal is to build a request string with a call looking like that req.Send(Update Producers).
Anyway for a reason that I do not understand, the compiler gives me 2 warnings:
on the Update(stype) I get a This rule will never be matched
on the the first match stype I get a Incomplete pattern matches on this expression. For example, the value 'Producers' may indicate a case not covered by the pattern(s).
So the question is why do I get these 2 warnings? Did I miss something on the way matching works?
While nested match expressions are sometimes warranted, in this particular case I would write a more readable single-level match, if I were you:
let s_action =
match action with
| Get Contexts -> "GetContexts"
| Get (Context id) -> sprintf "GetContext/%d" id
| Update Producers -> "UpdateProducers"
| Get _ -> raise (RequestException "get")
| Update _ -> raise (RequestException "update")
which achieves exactly the same effect as your code.
Your closing parenthesis is in the wrong place.
| Context(id) -> (sprintf "Context/%d" id))
| _ -> raise (RequestException("get"))
should be
| Context(id) -> (sprintf "Context/%d" id)
| _ -> raise (RequestException("get")))
Indeed, for the sake of clarity I would get rid of all extraneous parentheses (which in this case is actually every parenthesis):
let s_action =
match action with
| Get stype -> match stype with
| Contexts -> "Contexts"
| Context id -> sprintf "Context/%d" id
| _ -> RequestException "get" |> raise
|> sprintf "Get%s"
| Update stype -> match stype with
| Producers -> "Producers"
| _ -> RequestException "update" |> raise
|> sprintf "Update%s"
Personally I find this more readable, but of course that's subjective so YMMV.
Since you closed the paratheses in the wrong point, your code actually becomes:
let s_action =
match action with
| Get(stype) -> sprintf "Get%s" (match stype with
| Contexts -> sprintf "Contexts"
| Context(id) -> (sprintf "Context/%d" id))
| _ -> raise (RequestException("get")) (* Closing parenthesis should be here *)
| Update(stype) -> sprintf "Update%s" (match stype with
| Producers -> (sprintf "Producers")
| _ -> raise (RequestException("update")))
Obviously you can see the first match stype with doesn't cover Producers and the last pattern Update(stype) never matches due to the previous pattern of _. Therefore, all compiler warnings are justified.
You seem to overuse paratheses; here is a cleaned up version:
let s_action =
match action with
| Get stype -> sprintf "Get%s" <| match stype with
| Contexts -> sprintf "Contexts"
| Context id -> sprintf "Context/%d" id
| _ -> raise <| RequestException "get"
| Update stype -> sprintf "Update%s" <| match stype with
| Producers -> sprintf "Producers"
| _ -> raise <| RequestException "update"

pattern matching and returning new object based on pattern

Say I've got some code like this
match exp with
| Addition(lhs,rhs,_) -> Addition(fix lhs,fix rhs)
| Subtraction(lhs,rhs,_) -> Subtraction(fix lhs,fix rhs)
is there any way that would allow me to do something like
match exp with
| Addition(lhs,rhs,_)
| Subtraction(lhs,rhs,_) -> X(fix lhs,fix rhs)
where X be based on the actual pattern being matched
I like #kvb's answer.
This does suggest that you may want to redefine the DU, though:
type Op = | Add | Sub
type Expr = | Binary of Op * Expr * Expr
You can use an active pattern:
let (|Binary|_|) = function
| Addition(e1,e2) -> Some(Addition, e1, e2)
| Subtraction(e1,e2) -> Some(Subtraction, e1, e2)
| _ -> None
let rec fix = function
| Binary(con,lhs,rhs) -> con(fix lhs, fix rhs)
| _ -> ...

Resources