Ocaml- syntax error during a pattern-matching - ocaml

Here is my code :
type mass = Inf | P of int
let som = fun
|Inf _ | _ Inf -> Inf
| (P a) (P b) -> P (a+b)
I get the following error :
line 5, characters 0-1:
Error: Syntax error
I don't understand at all how I can get a syntax error here. I tried to replace the fun by : match a b with yet I still get the same syntax.
I also tried to put some : ";" yet it still doesn't work.

These patterns:
Inf _
_ Inf
don't make sense in OCaml. Both of them consist of one pattern followed directly by another. (The Inf pattern matches the Inf constuctor, and _ is a wild-card that matches anything.)
But there is no pattern in OCaml that consists of one pattern followed by another.
The same is true of this pattern:
(P a) (P b)
If these patterns did have a meaning, they would seem to match function applications. But a pattern can't pull apart a function application, it can only pull apart data constructors (lists, tuples, etc.).
What is an example OCaml value that you would expect this pattern to match?
Update
You seem to be saying that the value P 2, P 3 should match this second pattern. The value P 2, P 3 in OCaml is a tuple. It will match this pattern:
(P a), (P b)
Note that the comma is required. The comma is the constructor that creates a tuple.
Update 2
Well, the other mistake is that the fun keyword allows only a single pattern. For multiple patterns you need to use the function keyword. Here is a correct version of your function (assuming that you want it to handle pairs of values of type mass).
type mass = Inf | P of int
let som = function
|Inf, _ | _, Inf -> Inf
| (P a), (P b) -> P (a+b)
Update 3
It's more idiomatic in OCaml to have curried functions. It strikes me that this could be the reason you wanted to have adjacent patterns. To get a curried version of som you need to use an explicit match. Neither fun nor function is quite flexible enough.
It would look like this:
let som x y =
match x, y with
| Inf, _ | _, Inf -> Inf
| P a, P b -> P (a + b)

Related

Pattern Matching with Varying types of Tuples

I'm trying to figure out how to pattern match with user defined types. For example I have this type.
Type custom_type = B of bool | I of int | S of string | C of custom_type * custom_type
I want to pattern match these types, and say for example count the number of ints in a value. Example value:
C(C(B true, I 5), C(S "example", B false))
I think I'm very close to figuring it out, I know I need to use wildcards but I can't write out every instance there could be, because there are numerous varying values I need to check.
Thanks!
Edit: Code that isn't working:
let num = 0
let rec count_ints (c: custom_type):int =
match c with
| C (I(_), _) -> num + 1
| C (_, I(_)) -> num + 1
| C (C(_), _) -> count_ints c
| C (_, C(_)) -> count_ints c
You should be thinking of having 4 cases in your function, one for each constructor. You don't need to match what's inside these constructors because you can call yourself recursively to handle that.
Your code calls count_chars, but there's no function of that name. If it's supposed to be count_ints, then this is not a good recursive call. You must call recursively on a smaller problem. If you just pass c along to yourself recursively you'll get infinite recursion.
let rec count_ints (c: custom_type):int =
match c with
| I _ -> 1
| C (c1,c2) -> count_ints c1 + count_ints c2
| _ -> 0

Can I unpack an F# list with no warnings?

F# makes it easy to unpack tuples. Unpacking lists is also feasible, but the compiler issues a warning:
let m = [1; 2; 3]
let [a; b; c] = m
// Incomplete pattern matches on this expression. For example, the value '[_;_;_;_]' may indicate a case not covered by the pattern(s)
Is there a way to avoid this warning?
You can disable warnings per file by using the #nowarn directive (in your case #nowarn "25") or you can disable warnings on the command line with --nowarn.
Check out the F# Compiler Directives for details.
There is currently no way to re-enable warnings again, when first disabled.
Your match may (unexpectedly) result in a runtime error if the number of elements cannot be unpacked to [a;b;c], so instead you can use a complete match that is explicit about the risc:
let m = [1;2;3]
let (a,b,c) =
match m with
| [a;b;c] -> (a,b,c)
| _ -> failwith "Expected exactly three items in m"
What would happen if your list m has 2 or 4 elements?
There is obviously a way, plain old pattern matching:
let a, b, c =
match m with
| [a;b;c] -> a,b,c
| _ -> ... // handle the length!=3 case
F# allows you to deconstruct the right-hand side objects that way when there's clear that you only have a single case you need to cover. This is the case with tuples, since there's only one tuple type that would match both the left and the right hand side. Something like this obviously would not compile, because the types won't match:
let m = 1, 2
let a, b, c = m
Yet in your case there's no guarantee that you're not in fact in this scenario:
let m = [ 1; 2 ]
let [1;2;3] = m
You're in fact asking the compiler to allow non-exhaustive pattern matching. You can disable the warning as noted in the other answer, but you're inviting runtime errors that way.
One obvious, but hardly elegant, way is:
let m = [1; 2; 3]
let a = List.item 0 m
let b = List.item 1 m
let c = List.item 2 m
You can write a helper function to make it neater:
let unpack3 x = (List.item 0 x, List.item 1 x, List.item 2 x)
let (a, b, c) = unpack3 m
Basically a list is not a great fit if you know you are always going to have a fixed number of items.

match case unused in OCaml

I want to build a list of type (char, 'a list) list where each char is an upper case letter of the alphabet. I'am getting a warning Warning 11: this match case is unused. for the second match case on get_list. I did some prints on the first case and found out len get's there with value 0, so it never uses the second case. What's happening?
let rec get_list abc i len =
match i with
| len -> []
| _ -> ((String.get abc i), [])::get_list abc (i + 1) len
in
let rec print_list l =
match l with
| [] -> ()
| h::t -> print_char(fst h);print_list t
in
let abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" in
let abc_l = get_list abc 0 (String.length abc) in
print_list abc_l;;
The reason it doesn't work
When you write
match i with
| len -> []
| _ -> ["..."]
len is a generic pattern, which hasn't anything to do with the len define above. In a pattern matching you define only how the variable should look like, you describe it's general "structure", the variable names are used to name the differents parts of the pattern matching, and are new variables. For example with lists you can do:
match my_list with
| [x,y,z] -> x+y+z
| x :: r -> x + (List.length r)
| anything_else -> List.length anything_else
When you put '_' it's only a convention to say "I don't mind which value it is, I don't need it". Here is another example with tuples:
match my_tuple with
| (a,b) -> a+b
A solution : conditionnal pattern matching
If you want to put condition in a pattern matching you can use the when keyword :
match i with
| n when n = len -> []
| _ -> ["..."]
Another example that "sort" a tuple:
match my_tuple with
| (a,b) when a>b -> (a,b)
| (a,b) -> (b,a)
Or just use conditions with integers :
if i = len then []
else ["..."]
You can also note that you can do pattern matching within functions :
let f (a,b) = a+b
The len in your pattern is a new variable introduced by the pattern. As a pattern, its meaning is that it will match anything at all. Thus, the next pattern _ will never match.
As #AlexanderRevyakin says, this new variable len is hiding the parameter that's also named len.
It is not the case that the len in your pattern represents the value of the parameter len. OCaml patterns contain only new variables (to which pieces of the matched value are bound) and constants. They don't contain expressions that are evaluated at run time. For that you want to use if/then/else (as #AntonTrunov points out).

OCaml function parameter pattern matching for strings

I tried to pass a string in to get a reversed string. Why can't I do this:
let rec reverse x =
match x with
| "" -> ""
| e ^ s -> (reverse s) ^ e;;
The compiler says it's a syntax error. Can't I use ^ to destructure parameters?
The reason for this is that strings are not represented as a datatype in the same way as lists are. Therefore, while cons (::) is a constructor, ^ is not. Instead, strings are represented as a lower level type without a recursive definition (as lists are). There is a way to match strings as a list of characters, using a function from SML (which you can write in OCaml) called explode and implode which -- respectively -- take a string to a char list and vice versa. Here's an example implementation of them.
As Kristopher Micinski explained, you can't decompose strings using pattern matching as you do with lists.
But you can convert them to lists, using explode. Here's your reverse function with pattern matching using explode and its counterpart implode:
let rec reverse str =
match explode str with
[] -> ""
| h::t -> reverse (implode t) ^ string_of_char h
Use it like this:
let () =
let text = "Stack Overflow ♥ OCaml" in
Printf.printf "Regular: %s\n" text;
Printf.printf "Reversed: %s\n" (reverse text)
Which shows that it works for single-byte characters but not for multi-byte ones.
And here are explode and implode along with a helper method:
let string_of_char c = String.make 1 c
(* Converts a string to a list of chars *)
let explode str =
let rec explode_inner cur_index chars =
if cur_index < String.length str then
let new_char = str.[cur_index] in
explode_inner (cur_index + 1) (chars # [new_char])
else chars in
explode_inner 0 []
(* Converts a list of chars to a string *)
let rec implode chars =
match chars with
[] -> ""
| h::t -> string_of_char h ^ (implode t)
When you write a pattern matching expression, you cannot use arbitrary functions in your patterns. You can only use constructors, which look like unevaluated functions. For example, the function "+" is defined on integers. So the expression 1+2 is evaluated and gives 3; the function "+" is evaluated, so you cannot match on x+y. Here is an attempt to define a function on natural numbers that checks whether the number is zero:
let f x = match x with
| 0 -> false
| a+1 -> true
;;
This cannot work! For the same reason, your example with strings cannot work. The function "^" is evaluated on strings, it is not a constructor.
The matching on x+1 would work only if numbers were unevaluated symbolic expressions made out of the unevaluated operator + and a symbolic constant 1. This is not the case in OCAML. Integers are implemented directly through machine numbers.
When you match a variant type, you match on constructors, which are unevaluated expressions. For example:
# let f x = match x with
| Some x -> x+1
| None -> 0
;;
val f : int option -> int = <fun>
This works because the 'a option type is made out of a symbolic expression, such as Some x. Here, Some is not a function that is evaluated and gives some other value, but rather a "constructor", which you can think of as a function that is never evaluated. The expression Some 3 is not evaluated any further; it remains as it is. It is only on such functions that you can pattern-match.
Lists are also symbolic, unevaluated expressions built out of constructors; the constructor is ::. The result of x :: y :: [] is an unevaluated expression, which is represented by the list [x;y] only for cosmetic convenience. For this reason, you can pattern-match on lists.

Haskell - parse error/ using multiple where clauses

when trying to define a function that would remove the largest subset of set m that is also a subset of set a from set a, I encountered the following error:
filename.hs:7:33:parse error (possibly incorrect indentation)
for the following code:
exclude :: Integral t => [t] -> [t] -> [t]
a `exclude` m
| m == [] = a
| a == (b ++ c) = b
| otherwise = []
where b /= []
where c = [z | z <- m]
how do I implement multiple conditions/definitions (using where or otherwise), or correct the function to properly work in a different way?
One part of your question is easily answerable. You can have multiple definitions in one where clause, as in
foo n
| even r = bar
| s < 12 = baz
| otherwise = quux
where
r = n `mod` 1357
h = a + b
where
(a,b) = r `divMod` 53 -- nested where-clause
s = r - 3*h
and you can have nested where-clauses. But in a where-clause, you can only have definitions. Conditions would go into the guards (or if then else expressions on the right hand side) and can be combined with the boolean operators, (&&), (||), not ...
As for your code, so far I haven't figured out what you intended it to do.
Saying "the largest subset of set m that is also a subset of set a"
is the same as saying "all elements of m that are also elements of a".
Then the solution to your problem is stated simply as:
exclude a = filter (`notElem` a)
which when applied to m will give you a subset of m modulo any elements
that are also members of a. That is, it will "remove the largest subset of
m that is also a subset of a".
In fact,there is a function in Data.List and Data.Set called '\'. I'll show '\' function of Data.List .
import Data.List
exclude :: Integral t => [t] -> [t] -> [t]
a `exclude` m = a\\m