Haskell: parse error in pattern 3 - parsing

data Peg = Red | Green | Blue | Yellow | Orange | Purple
deriving (Show, Eq, Ord)
type Code = [Peg]
data Move = Move Code Int Int
deriving (Show, Eq)
isConsistent :: Move -> Code -> Bool
isConsistent (move1 code1 num1 num2) code2 = True --parse error here
Relatively new to Haskell. Wondering why I receive the following error message after attempting to load this.
Parse error in pattern: move1

move1 isn't a data constructor (which is what you're allowed to pattern match on) and in fact it can't be since they have to start with uppercase letters. Replace it with the constructor Move from your data declaration and the error should go away.
You will probably still get some warnings like "code1 defined but not used" you can get rid of them by changing the pattern to (Move _ _ _) if you really don't care about the contents.

Related

Pattern matching against a string property

I'm de-serializing some mappings from JSON and later on I need to pattern match based on a string field of the de-serialized types like this:
let mappings = getWorkItemMappings
let result =
workItemMappings
|> Seq.find (fun (m: WorkItemMapping) -> m.Uuid = workTime.workItemUuid)
match mapping.Name with
Even if I complete the pattern match for all cases I still get Incomplete pattern matches on this expression.. Which is obvious to me due to the string type of the Name field.
Is there a way tell the compiler which values for the Name field are available?.
I think I could create a union type for the possible mapping types and try to de-serialize the JSON to this union type but I would like to if there's another option.
If you are pattern matching on a string value, the compiler has no static guarantee that it will only have certain values, because it is always possible to construct a string of a different value. The fact that it comes from JSON does not help - you may always have an invalid JSON.
The best option is to add a default case which throws a custom descriptive exception. Either one that you handle somewhere else (to indicate that the JSON file was invalid) or (if you check the validity elsewhere) something like this:
let parseFood f =
match f with
| "burger" -> 1
| "pizza" -> 2
| _ -> raise(invalidArg "f" $"Expected burger or pizza but got {f}")
Note that the F# compiler is very cautious. It does not even let you handle enum values using pattern matching, because under the cover, there are ways of creating invalid enum values! For example:
type Foo =
| A = 1
let f (a:Foo) =
match a with
| Foo.A -> 0
warning FS0104: Enums may take values outside known cases. For example, the value 'enum (0)' may indicate a case not covered by the pattern(s).
Very hard to understand what you're asking. Maybe this snippet can be of help. It demos how literal string constants can be used in pattern matching, and reused in functions. This gives some added safety and readability when adding and removing cases. If you prefer not to serialize a DU directly, then perhaps this is useful as part of the solution.
type MyDu =
| A
| B
| C
let [<Literal>] A' = "A"
let [<Literal>] B' = "B"
let [<Literal>] C' = "C"
let strToMyDuOption (s: string) =
match s with
| A' -> Some A
| B' -> Some B
| C'-> Some C
| _ -> None
let strToMyDu (s: string) =
match s with
| A' -> A
| B' -> B
| C'-> C
| s -> failwith $"MyDu case {s} is unknown."
let myDuToStr (x: MyDu) =
match x with
| A -> A'
| B -> B'
| C -> C'
// LINQPad
let dump x = x.Dump()
strToMyDuOption A' |> dump
strToMyDuOption "x" |> dump
myDuToStr A |> dump

Parsing int or float with FParsec

I'm trying to parse a file, using FParsec, which consists of either float or int values. I'm facing two problems that I can't find a good solution for.
1
Both pint32 and pfloat will successfully parse the same string, but give different answers, e.g pint32 will return 3 when parsing the string "3.0" and pfloat will return 3.0 when parsing the same string. Is it possible to try parsing a floating point value using pint32 and have it fail if the string is "3.0"?
In other words, is there a way to make the following code work:
let parseFloatOrInt lines =
let rec loop intvalues floatvalues lines =
match lines with
| [] -> floatvalues, intvalues
| line::rest ->
match run floatWs line with
| Success (r, _, _) -> loop intvalues (r::floatvalues) rest
| Failure _ ->
match run intWs line with
| Success (r, _, _) -> loop (r::intvalues) floatvalues rest
| Failure _ -> loop intvalues floatvalues rest
loop [] [] lines
This piece of code will correctly place all floating point values in the floatvalues list, but because pfloat returns "3.0" when parsing the string "3", all integer values will also be placed in the floatvalues list.
2
The above code example seems a bit clumsy to me, so I'm guessing there must be a better way to do it. I considered combining them using choice, however both parsers must return the same type for that to work. I guess I could make a discriminated union with one option for float and one for int and convert the output from pint32 and pfloat using the |>> operator. However, I'm wondering if there is a better solution?
You're on the right path thinking about defining domain data and separating definition of parsers and their usage on source data. This seems to be a good approach, because as your real-life project grows further, you would probably need more data types.
Here's how I would write it:
/// The resulting type, or DSL
type MyData =
| IntValue of int
| FloatValue of float
| Error // special case for all parse failures
// Then, let's define individual parsers:
let pMyInt =
pint32
|>> IntValue
// this is an alternative version of float parser.
// it ensures that the value has non-zero fractional part.
// caveat: the naive approach would treat values like 42.0 as integer
let pMyFloat =
pfloat
>>= (fun x -> if x % 1 = 0 then fail "Not a float" else preturn (FloatValue x))
let pError =
// this parser must consume some input,
// otherwise combined with `many` it would hang in a dead loop
skipAnyChar
>>. preturn Error
// Now, the combined parser:
let pCombined =
[ pMyFloat; pMyInt; pError ] // note, future parsers will be added here;
// mind the order as float supersedes the int,
// and Error must be the last
|> List.map (fun p -> p .>> ws) // I'm too lazy to add whitespase skipping
// into each individual parser
|> List.map attempt // each parser is optional
|> choice // on each iteration, one of the parsers must succeed
|> many // a loop
Note, the code above is capable working with any sources: strings, streams, or whatever. Your real app may need to work with files, but unit testing can be simplified by using just string list.
// Now, applying the parser somewhere in the code:
let maybeParseResult =
match run pCombined myStringData with
| Success(result, _, _) -> Some result
| Failure(_, _, _) -> None // or anything that indicates general parse failure
UPD. I have edited the code according to comments. pMyFloat was updated to ensure that the parsed value has non-zero fractional part.
FParsec has the numberLiteral parser that can be used to solve the problem.
As a start you can use the example available at the link above:
open FParsec
open FParsec.Primitives
open FParsec.CharParsers
type Number = Int of int64
| Float of float
// -?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?
let numberFormat = NumberLiteralOptions.AllowMinusSign
||| NumberLiteralOptions.AllowFraction
||| NumberLiteralOptions.AllowExponent
let pnumber : Parser<Number, unit> =
numberLiteral numberFormat "number"
|>> fun nl ->
if nl.IsInteger then Int (int64 nl.String)
else Float (float nl.String)```

How to avoid long pattern match based functions?

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.

Tracking locations in Genlex

I'm writing a parser for a language that is sufficiently simple for Genlex + camlp4 stream parsers to take care of it. However, I'd still be interested in having a more or less precise location (i.e. at least a line number) in case of parsing error.
My idea is to use an intermediate stream between the original char Stream and the token Stream of Genlex, that takes care of line counts, like in the code below, but I'm wondering whether there's a simpler solution?
let parse_file s =
let num_lines = ref 1 in
let bol = ref 0 in
let print_pos fmt i =
(* Emacs-friendly location *)
Printf.fprintf fmt "File %S, line %d, characters %d-%d:"
s !num_lines (i - !bol) (i - !bol)
in
(* Normal stream *)
let chan =
try open_in s
with
Sys_error e -> Printf.eprintf "Cannot open %s: %s\n%!" s e; exit 1
in
let chrs = Stream.of_channel chan in
(* Capture newlines and move num_lines and bol accordingly *)
let next i =
try
match Stream.next chrs with
| '\n' -> bol := i; incr num_lines; Some '\n'
| c -> Some c
with Stream.Failure -> None
in
let chrs = Stream.from next in
(* Pass that to the Genlex's lexer *)
let toks = lexer chrs in
let error s =
Printf.eprintf "%a\n%s %a\n%!"
print_pos (Stream.count chrs) s print_top toks;
exit 1
in
try
parse toks
with
| Stream.Failure -> error "Failure"
| Stream.Error e -> error ("Error " ^ e)
| Parsing.Parse_error -> error "Unexpected symbol"
A much simpler solution is to use Camlp4 grammars.
Parsers built this way allow one to get decent error messages "for free", unlike the case with stream parsers (which are a low level tool).
It could be that there is no need to define your own lexer, because OCaml's lexer suits your needs already. But if you really need your own lexer, then you can easily plug in a custom one:
module Camlp4Loc = Camlp4.Struct.Loc
module Lexer = MyLexer.Make(Camlp4Loc)
module Gram = Camlp4.Struct.Grammar.Static.Make(Lexer)
open Lexer
let entry = Gram.Entry.mk "entry"
EXTEND Gram
entry: [ [ ... ] ];
END
let parse str =
Gram.parse rule (Loc.mk file) (Stream.of_string str)
If you are new to OCaml, then all this module system trickery might seem at first like black voodoo magic :-) The fact that Camlp4 is a severely underdocumented beast might also contribute to the surreality of experience.
So never hesitate to ask a question (even a stupid one) on the mailing list.

How do I use Some/None Options in this F# example?

I am new to F# and I have this code:
if s.Contains("-") then
let x,y =
match s.Split [|'-'|] with
| [|a;b|] -> int a, int b
| _ -> 0,0
Notice that we validate that there is a '-' in the string before we split the string, so the match is really unnecessary. Can I rewrite this with Options?
I changed this code, it was originally this (but I was getting a warning):
if s.Contains("-") then
let [|a;b|] = s.Split [|'-'|]
let x,y = int a, int b
NOTE: I am splitting a range of numbers (range is expressed in a string) and then creating the integer values that represent the range's minimum and maximum.
The match is not unnecessary, the string might be "1-2-3" and you'll get a three-element array.
Quit trying to get rid of the match, it is your friend, not your enemy. :) Your enemy is the mistaken attempt at pre-validation (the "if contains" logic, which was wrong).
I think you may enjoy this two-part blog series.
http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!180.entry
http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!181.entry
EDIT
Regarding Some/None comment, yes, you can do
let parseRange (s:string) =
match s.Split [|'-'|] with
| [|a;b|] -> Some(int a, int b)
| _ -> None
let Example s =
match parseRange s with
| Some(lo,hi) -> printfn "%d - %d" lo hi
| None -> printfn "range was bad"
Example "1-2"
Example "1-2-3"
Example "1"
where parseRange return value is a Some (success) or None (failure) and rest of program can make a decision later based on that.

Resources