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"
Related
I have built a toy spreadsheet to help learn F#. When I process the text for a new cell I store it as a discriminated type. To parse it I feel I should be able to do something like:
let cv =
match t with
| _ when t.Length=0 -> Empty
| x when t.[0]='=' -> Expr(x)
| x when t.[0]='\"' -> Str(x)
| (true,i) when Int32.TryParse t -> IntValue(i) // nope!
| _ -> Str(t)
I have tried quite a few combinations but I cannot get TryParse in the guard. I have written a helper:
let isInt (s:string) =
let mutable m:Int64 = 0L
let (b,m) = Int64.TryParse s
b
I can now write:
| _ when Utils.isInt t -> IntValue((int)t)
This seems like a poor solution as it discards the converted result. What the correct syntax to get TryParse into the guard?
I think an active pattern will do what you want:
let (|Integer|_|) (str: string) =
let flag, i = Int32.TryParse(str)
if flag then Some i
else None
let cv =
match t with
| _ when t.Length=0 -> Empty
| x when t.[0]='=' -> Expr(x)
| x when t.[0]='\"' -> Str(x)
| Integer i -> IntValue(i)
| _ -> Str(t)
But if you really want TryParse in the guard condition (and you don't mind parsing twice), you could do this:
| x when fst (Int32.TryParse(t)) -> IntValue (Int32.Parse(x))
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.
I've written a typical evaluator for simple math expressions (arithmetic with some custom functions) in F#. While it seems to be working correctly, some expressions don't evaluate as expected, for example, these work fine:
eval "5+2" --> 7
eval "sqrt(25)^2" --> 25
eval "1/(sqrt(4))" --> 0.5
eval "1/(2^2+2)" --> 1/6 ~ 0.1666...
but these don't:
eval "1/(sqrt(4)+2)" --> evaluates to 1/sqrt(6) ~ 0.408...
eval "1/(sqrt 4 + 2)" --> will also evaluate to 1/sqrt(6)
eval "1/(-1+3)" --> evaluates to 1/(-4) ~ -0.25
the code works as follows, tokenization (string as input) -> to rev-polish-notation (RPN) -> evalRpn
I thought that the problem seems to occur somewhere with the unary functions (functions accepting one operator), these are the sqrt function and the negation (-) function. I don't really see what's going wrong in my code. Can someone maybe point out what I am missing here?
this is my implementation in F#
open System.Collections
open System.Collections.Generic
open System.Text.RegularExpressions
type Token =
| Num of float
| Plus
| Minus
| Star
| Hat
| Sqrt
| Slash
| Negative
| RParen
| LParen
let hasAny (list: Stack<'T>) =
list.Count <> 0
let tokenize (input:string) =
let tokens = new Stack<Token>()
let push tok = tokens.Push tok
let regex = new Regex(#"[0-9]+(\.+\d*)?|\+|\-|\*|\/|\^|\)|\(|pi|e|sqrt")
for x in regex.Matches(input.ToLower()) do
match x.Value with
| "+" -> push Plus
| "*" -> push Star
| "/" -> push Slash
| ")" -> push LParen
| "(" -> push RParen
| "^" -> push Hat
| "sqrt" -> push Sqrt
| "pi" -> push (Num System.Math.PI)
| "e" -> push (Num System.Math.E)
| "-" ->
if tokens |> hasAny then
match tokens.Peek() with
| LParen -> push Minus
| Num v -> push Minus
| _ -> push Negative
else
push Negative
| value -> push (Num (float value))
tokens.ToArray() |> Array.rev |> Array.toList
let isUnary = function
| Negative | Sqrt -> true
| _ -> false
let prec = function
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
let toRPN src =
let output = new ResizeArray<Token>()
let stack = new Stack<Token>()
let rec loop = function
| Num v::tokens ->
output.Add(Num v)
loop tokens
| RParen::tokens ->
stack.Push RParen
loop tokens
| LParen::tokens ->
while stack.Peek() <> RParen do
output.Add(stack.Pop())
stack.Pop() |> ignore // pop the "("
loop tokens
| op::tokens when op |> isUnary ->
stack.Push op
loop tokens
| op::tokens ->
if stack |> hasAny then
if prec(stack.Peek()) >= prec op then
output.Add(stack.Pop())
stack.Push op
loop tokens
| [] ->
output.AddRange(stack.ToArray())
output
(loop src).ToArray()
let (#) op tok =
match tok with
| Num v ->
match op with
| Sqrt -> Num (sqrt v)
| Negative -> Num (v * -1.0)
| _ -> failwith "input error"
| _ -> failwith "input error"
let (##) op toks =
match toks with
| Num v,Num u ->
match op with
| Plus -> Num(v + u)
| Minus -> Num(v - u)
| Star -> Num(v * u)
| Slash -> Num(u / v)
| Hat -> Num(u ** v)
| _ -> failwith "input error"
| _ -> failwith "inpur error"
let evalRPN src =
let stack = new Stack<Token>()
let rec loop = function
| Num v::tokens ->
stack.Push(Num v)
loop tokens
| op::tokens when op |> isUnary ->
let result = op # stack.Pop()
stack.Push result
loop tokens
| op::tokens ->
let result = op ## (stack.Pop(),stack.Pop())
stack.Push result
loop tokens
| [] -> stack
if loop src |> hasAny then
match stack.Pop() with
| Num v -> v
| _ -> failwith "input error"
else failwith "input error"
let eval input =
input |> (tokenize >> toRPN >> Array.toList >> evalRPN)
Before answering your specific question, did you notice you have another bug? Try eval "2-4" you get 2.0 instead of -2.0.
That's probably because along these lines:
match op with
| Plus -> Num(v + u)
| Minus -> Num(v - u)
| Star -> Num(v * u)
| Slash -> Num(u / v)
| Hat -> Num(u ** v)
u and v are swapped, in commutative operations you don't notice the difference, so just revert them to u -v.
Now regarding the bug you mentioned, the cause seems obvious to me, by looking at your code you missed the precedence of those unary operations:
let prec = function
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
I tried adding them this way:
let prec = function
| Negative -> 5
| Sqrt -> 4
| Hat -> 3
| Star | Slash -> 2
| Plus | Minus -> 1
| _ -> 0
And now it seems to be fine.
Edit: meh, seems I was late, Gustavo posted the answer while I was wondering about the parentheses. Oh well.
Unary operators have the wrong precedence. Add the primary case | a when isUnary a -> 4 to prec.
The names of LParen and RParen are consistently swapped throughout the code. ( maps to RParen and ) to LParen!
It runs all tests from the question properly for me, given the appropriate precedence, but I haven't checked the code for correctness.
Is it possible in F# to automatically generate predicates and accessors for an arbitrary algebraic data type in type-safe manner?
For example, if we have user defined type:
type A =
B of string
| C of int * sting
should be generated something like this:
type A =
B of string
| C of int * sting
with
member __.isB = match __ with B -> true | _ -> false
member __.isC = match __ with C -> true | _ -> false
member __._1 = match __ with B(x) -> Some(x) | _ -> None
member __._2 = match __ with C(x,_) -> Some(x) | _ -> None
member __._3 = match __ with C(_,x) -> Some(x) | _ -> None
It will be better if can specify names for accessors may be with annotation like this:
[<GenerateAccessors(["BName", "CName", "Value"])>]
May be it can not be done or I should use records instead discriminated unions (DU) if I want to siplify access to inner data. But it's more simply to use patten matching with DUs and I want both of this profits - simply pattern matching and simply "direct data access" - in the same time.
You can reflect over a discriminated union using FSharpType.GetUnionCases and generate code using the F# CodeDOM available in the F# PowerPack or simply by writing text.
open Microsoft.FSharp.Reflection
type A = B of string | C of int * string
let generate t =
let cases = FSharpType.GetUnionCases(t)
printfn "type %s with" t.Name
for case in cases do
printfn "\tmember value.is%s = " case.Name
let fields =
match [for field in case.GetFields() -> "_"] with
| [] -> ""
| fields -> " (" + (fields |> String.concat ",") + ")"
printfn "\t\tmatch value with %s%s -> true | _ -> false" case.Name fields
generate typeof<A>
Generates an F# type extension:
type A with
member value.isB =
match value with B (_) -> true | _ -> false
member value.isC =
match value with C (_,_) -> true | _ -> false
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)
| _ -> ...