I coded the following function to compute the cartesian product of two lists.
let rec descartes a = function
| _ when a = [] -> []
| [] -> []
| t::q -> (List.map (function x -> t, x) a) # (descartes q a) ;;
But when I want to simplify the function
let rec descartes a = function
| _ when a = [] | [] -> []
| t::q -> (List.map (function x -> t, x) a) # (descartes q a) ;;
I get a syntax error.
According to this the syntax of pattern matching is:
pattern-matching ::= [ | ] pattern [when expr] -> expr { | pattern [when
expr] -> expr }
And you can find the syntax of pattern here. So as you can see when is not a part of pattern, which explains the syntax error.
But in any case, your code is redundant, once you have [] -> [] you don't need _ when a = [] -> [] anymore. So you can simply write:
let rec descartes a = function
| [] -> []
| t::q -> (List.map (function x -> t, x) a) # (descartes q a) ;;
Related
I am trying to define a function that is similar to Lisp's apply. Here is my attempt:
type t =
| Str of string
| Int of int
let rec apply f args =
match args with
| (Str s)::xs -> apply (f s) xs
| (Int i)::xs -> apply (f i) xs
| [] -> f
(* Example 1 *)
let total = apply (fun x y z -> x + y + z)
[Int 1; Int 2; Int 3]
(* Example 2 *)
let () = apply (fun name age ->
Printf.printf "Name: %s\n" name;
Printf.printf "Age: %i\n" age)
[Str "Bob"; Int 99]
However, this fails to compile. The compiler gives this error message:
File "./myprog.ml", line 7, characters 25-30:
7 | | (Str s)::xs -> apply (f s) xs
^^^^^
Error: This expression has type 'a but an expression was expected of type
string -> 'a
The type variable 'a occurs inside string -> 'a
What is the meaning of this error message? How can I fix the problem and implement apply?
You cannot mix an untyped DSL for data:
type t =
| Int of int
| Float of float
and a shallow embedding (using OCaml functions as functions inside the DSL) for functions in apply
let rec apply f args =
match args with
| (Str s)::xs -> apply (f s) xs (* f is int -> 'a *)
| (Int i)::xs -> apply (f i) xs (* f is string -> 'a *)
| [] -> f (* f is 'a *)
The typechecker is complaining that if f has type 'a, f s cannot also have for type 'a since it would mean that f has simultaneously type string -> 'a and 'a (without using the recursive types flag).
And more generally, your function apply doesn't use f with a coherent type: sometimes it has type 'a, sometimes it has type int -> 'a, other times it would rather have type string -> 'a. In other words, it is not possible to write a type for apply
val apply: ??? (* (int|string) -> ... *) -> t list -> ???
You have to choose your poison.
Either go with a fully untyped DSL which contains functions, that can be applied:
type t =
| Int of int
| Float of float
| Fun of (t -> t)
exception Type_error
let rec apply f l = match f, l with
| x, [] -> f
| Fun f, a :: q -> apply (f a) q
| (Int _|Float _), _ :: _ -> raise Type_error
or use OCaml type system and define a well-typed list of arguments with a GADT:
type ('a,'b) t =
| Nil: ('a,'a) t
| Cons: 'a * ('b,'r) t -> ('a -> 'b,'r) t
let rec apply: type f r. f -> (f,r) t -> r = fun f l ->
match l with
| Nil -> f
| Cons (x,l) -> apply (f x) l
EDIT:
Using the GADT solution is quite direct since we are using usual OCaml type without much wrapping:
let three = apply (+) (Cons(1, Cons(2,Nil)))
(and we could use a heterogeneous list syntactic sugar to make this form even lighter syntactically)
The untyped DSL requires to build first a function in the DSL:
let plus = Fun(function
| Float _ | Fun _ -> raise Type_error
| Int x -> Fun(function
| Float _ | Fun _ -> raise Type_error
| Int y -> Int (x+y)
)
)
but once we have built the function, it is relatively straightforward:
let three = apply_dsl plus [Int 2; Int 1]
type t =
| Str of string
| Int of int
| Unit
let rec apply f args =
match args with
| x::xs -> apply (f x) xs
| [] -> f Unit
Let's go step by step:
line 1: apply : 'a -> 'b -> 'c (we don't know the types of f, args and apply's return type
line 2 and beginning of line 3: args : t list so apply : 'a -> t list -> 'c
rest of line 3: Since f s (s : string), f : string -> 'a but f t : f because apply (f s). This means that f contains f in its type, this is a buggy behaviour
It's actually buggy to call f on s and i because this means that f can take a string or an int, the compiler will not allow it.
And lastly, if args is empty, you return f so the return type of f is the type of f itself, another buggy part of this code.
Looking at your examples, a simple solution would be:
type t = Str of string | Int of int
let rec apply f acc args =
match args with x :: xs -> apply f (f acc x) xs | [] -> acc
(* Example 1 *)
let total =
apply
(fun acc x ->
match x with Int d -> d + acc | Str _ -> failwith "Type error")
0 [ Int 1; Int 2; Int 3 ]
(* Example 2 *)
let () =
apply
(fun () -> function
| Str name -> Printf.printf "Name: %s\n" name
| Int age -> Printf.printf "Age: %i\n" age)
() [ Str "Bob"; Int 99 ]
Since you know the type you want to work on, you don't need GADT shenanigans, just let f handle the pattern matching and work with an accumulator
Say I'm defining a recursive function on lists that looks something like:
let rec listFunc xs =
match xs with
| [] -> aThing
| h :: t -> listFunc (tailFunc t)
;;
where tailFunc is some other function from lists to lists. The compiler will give me an unused variable warning since I didn't use h, but I can't just use the wildcard since I need to be able to access the tail of the list. How do I prevent the compiler from giving me a warning?
You can prefix the h with an underscore.
let rec listFunc xs =
match xs with
| [] -> aThing
| _h :: t -> listFunc (tailFunc t)
;;
or simply:
let rec listFunc xs =
match xs with
| [] -> aThing
| _ :: t -> listFunc (tailFunc t)
;;
Any binding that starts with _ won't be in scope and won't give you unused variable warnings.
I want to make a list of summation of two lists by recursively.
let rec listadd a b
match a with
| [] -> b
| hd::tl ->
( match b with
| hd2::tl2 -> [hd + hd2]#(list_add tl tl2)
| [] -> [hd + hd2]#(list_add tl tl2)
)
However, it causes an error.
File "test.ml", line 56, characters 17-20:
Error: Unbound value hd2
Did you mean hd?
What is the problem?
The problem is that hd2 is undefined in the case [] -> [hd + hd2]#(list_add tl tl2). I guess you are trying to write something like
let rec listadd a b =
match a with
| [] -> b
| hd :: tl ->
(match b with
| hd2 :: tl2 -> [hd + hd2]#(listadd tl tl2)
| [] -> a
)
I would also recommend not to use list concatenation, instead appending an element to the head of a list directly:
let rec listadd a b =
match a with
| [] -> b
| hd :: tl ->
(match b with
| hd2 :: tl2 -> (hd + hd2) :: (listadd tl tl2)
| [] -> a
)
While that works, the code can be simplified a lot by using one match only:
let rec listadd a b =
match a, b with
| [], _ -> b
| _, [] -> a
| hd :: tl, hd2 :: tl2 -> (hd + hd2) :: (listadd tl tl2)
The name hd2 is defined by the pattern match in the line above. But the name is only defined for that one pattern match and result. So there's no definition for hd2 on the line in error. Since this erroneous line matches an empty list, it's not clear what you were intending the code to do.
As a possible hint, it seems to me that the case where the second list is empty should be handled the same as the case where the first list is empty.
And using the List.map2 function :
let listadd l l' = List.map2(fun x y -> x+y) l l';;
I am writing a ocaml project, in which I have a function that replace all '' in a char-list with 'E'. Here's my code for this propose:
let rec string_lst_change_E lst =
match lst with
[] -> let a ='E'; a::[]
|(h::t) if (h = '') -> 'E'::(string_lst_change_E t)
|(h::t) -> h::(string_lst_change_E t)
;;
It says I have a syntax error... But I cannot figure out by myself.
I tried to modify it like this:
let rec string_lst_change_E lst =
match lst with
[] -> 'E'::[]
|(h::t) ->if (h = '') then 'E'::(string_lst_change_E t) else h::(string_lst_change_E t)
;;
but still there's syntax error...(on the line |(h::t) -> .... char 18-21)
Please help me to take a look at it. Thank you!
This is where the first error lies: [] -> let a ='E'; a::[] If you want to use a after declaring it, you should instead write [] -> let a = 'E' in a ::[]. Obviously, [] -> ['E'] is simpler.
The second is the use of if in a pattern match. You should use when instead: |(h::t) when h = '' -> 'E'::(string_lst_change_E t)
But what's '' anyway? The empty character? How would you get this in a string? Typing '' is itself a syntax error. Try it in the toplevel! To make your code compile, I replaced '' by ' '.
let rec string_lst_change_E lst =
match lst with
| [] -> let a ='E' in a::[]
| (h::t) when h = ' ' -> 'E'::(string_lst_change_E t)
| (h::t) -> h::(string_lst_change_E t)
Note that you can simply use function here:
let rec string_lst_change_E = function
| [] -> let a ='E' in a::[]
| (h::t) when h = ' ' -> 'E'::(string_lst_change_E t)
| (h::t) -> h::(string_lst_change_E t)
I am working on a project with OCaml and there are some problems regarding to arrays that I am not sure with. I am not allowed to use the List module, so please give me some idea or suggestion with my works.
First, I already implemented a function 'a list -> 'a list called uniq that return a list of the uniq elements in an array, for example uniq [5;6;5;4] => [6;5;4]
Here is my implementation:
let rec uniq x =
let rec uniq_help l n =
match l with
[] -> []
| h :: t -> uniq_help t, n if (n = h) else (h :: (uniq_help(t, n)))
match x with
[] -> []
| h::t -> uniq_help t, h
;;
I mot sure this is a correct implementation, can someone give me some suggestion or correctness?
You functions are syntactically incorrect for various reasons:
uniq_help takes two elements so you have to invoke it using uniq_help t n, not uniq_help(t, n) and the like.
an if/else expression should have the form of if cond then expr1 else expr2.
to use uniq_help locally in uniq, you need an in keyword.
After fixing syntax errors, your function looks like:
let rec uniq x =
let rec uniq_help l n =
match l with
| [] -> []
| h :: t -> if n = h then uniq_help t n else h::(uniq_help t n) in
match x with
| [] -> []
| h::t -> uniq_help t h
However, to be sure that each element is unique in the list, you have to check uniqueness for all of its elements. One quick fix could be:
let rec uniq x =
(* uniq_help is the same as above *)
match x with
| [] -> []
| h::t -> h::(uniq_help (uniq t) h)