I've written this mergesort implementation, which works fine if I put the divide function outside of the mergesort function. But when I try to make divide an inner function of mergesort I encounter a syntax error.
I know, there must be some really simple explanation for this. I've looked all over the internet, yet found nothing.
Here is the code:
let mergesort list =
let rec sort lists acc = (
let rec merge sublist1 sublist2 merged_list =
match sublist1 with
|[] -> merged_list # sublist2
|hd1 :: tl1 ->
match sublist2 with
|[] -> merged_list # sublist1
|hd2 :: tl2 ->
if hd1 < hd2 then merge tl1 sublist2 (merged_list # hd1::[])
else merge sublist1 tl2 (merged_list # hd2::[])
in match lists with
|[] ->
(match acc with
|[] -> []
|hd :: [] -> hd
|_ -> sort acc [])
|hd :: tl -> sort (List.tl tl) ((merge (List.hd tl) hd [])::acc)
)
and rec divide list list_of_lists = (
match list with
[] -> list_of_lists
|hd :: tl -> divide tl ((hd :: []) :: list_of_lists)
)
in sort (divide list []) []
;;
and it results into:
Characters 567-570:
and rec divide list list_of_lists = (
^^^
Error: Syntax error
A local definition has the following syntax in OCaml:
let [rec] pattern1 = expr1 and … and patternN = exprN in expr
Thus an extra rec is not allowed after the and keyword, and is allowed only after the first let. The rec flag extends to all values defined in the local definition, thus you just need to remove this erroneous rec after and.
You need to simply remove the rec keyword from your definition there.
This is because when you use the and keyword, you’re effectively repeating the previous definition syntactically, which in this case is let rec.
So your current implementation is effectively the same as saying let rec rec
Related
I am trying to create and use a stack object (modified to have strings) from here:
let s = object
val mutable v = [""; ""]
method pop =
match v with
| hd :: tl ->
v <- tl;
Some hd
| [] -> None
method push hd =
v <- hd :: v
end ;;
let () =
s#push "first";
s#push "second";
s#push "third";
print_endline s#pop; (* error from this line *)
print_endline s#pop;
print_endline s#pop;
However, I am getting following error:
$ ocaml objects.ml
File "./objects.ml", line 19, characters 15-20:
Error: This expression has type string option
but an expression was expected of type string
I am not able to understand the error: If the expected type was string why expression of type string is not being accepted?
I am not able to understand the error: If the expected type was string why expression of type string is not being accepted?
Because the expression s#pop doesn't have type string. Its type is string option, i.e., it is either Some s or None, where s has type string.
Look at the pop method implementation, which returns Some s if there are more elements waiting in the stack, or None if the stack is empty,
method pop =
match v with
| hd :: tl ->
v <- tl;
Some hd (* returns `Some hd` *)
| [] -> None (* returns `None` *)
You can implement a helper function, that will print a value of type string option, e.g.,
let print_some s = match s with
| None -> print_endline "empty"
| Some s -> print_endline s
Here is how it is used
let () =
s#push "first";
s#push "second";
s#push "third";
print_some s#pop;
print_some s#pop;
print_some s#pop;
Here are some alternative implementations of the stack object, that use other ways to communicate to the caller that the stack is empty, e.g., a sentinel value from the stack element domain (provided by a user), an exception, or the result type, parametrized with a stringly typed error.
let stack_with_sentinel empty = object
val mutable v = []
method pop = match v with
| hd :: tl ->
v <- tl;
hd
| [] -> empty
end
let stack_with_exception = object
val mutable v = []
method pop = match v with
| hd :: tl ->
v <- tl;
hd
| [] -> raise Not_found
end
let stack_with_result = object
val mutable v = []
method pop = match v with
| hd :: tl ->
v <- tl;
Ok hd
| [] -> Error "empty stack"
end
There are many other ways to define it, but using the option type is the most common.
I want to write a tail recursive function to print elements in a string list in separate lines like this:
# printlist ["a";"b";"c"];;
a
b
c
- : unit = ()
# printlist ["hello";"thanks"];;
hello
thanks
- : unit = ()
I was able to get it to work using print_endline with no problem:
let rec printlist strlist =
match strlist with
| [] -> print_endline ""
| hd::[] -> print_endline hd
| hd :: tl -> print_endline hd ; printlist tl;;
However, as soon as I switch to printf, it doesn't work anymore. What's wrong with my printf version?
let rec printlist strlist =
match strlist with
| [] -> printf ""
| hd::[] -> printf hd
| hd :: tl -> printf "%s\n" hd ; printlist tl;;
Error: This expression has type
(unit, out_channel, unit) format =
(unit, out_channel, unit, unit, unit, unit)
CamlinternalFormatBasics.format6
but an expression was expected of type string
In essence, you're trying to use printf without a format. The first argument of printf has to be a constant string. So you should have this:
printf "%s" hd
rather than this:
printf hd
To see why this is required, imagine what would happen if some of the strings in your input contained percent characters. Things would get out of control (type-wise) quite quickly.
In addition to Jeffrey's answer, I would suggest you use the standard library more in order to write more concise code.
List.iter, for example, calls a given function on all the elements of the list:
let print_list l = List.iter (fun e -> Printf.printf "%s\n" e) l
Using partial application smartly, you can make this line even shorter and more readable:
let print_list = List.iter (Printf.printf "%s\n")
The only difference with your function is the newline after the last element.
On the other hand, instead of printing elements one after another, a more functional and idiomatic approach would be to build the whole string first, and then print it.
Lucky you, the standard library got you covered. String.concat joins the elements in a string list together in one big string. You can also specify a string to use as a separator, and you don't have to worry about the newline after the last element.
let print_list l = print_string (String.concat "\n" l)
I am trying to make a module that would allow to create a table in ocaml. It would do a query called project to limit the table's values. However on the last line of the definition of the function chooser I am getting syntax error.
module type TABLE =
sig
type database
type table
val create_table: string list * string list* (string list) list -> table
val printTable : table -> string
val listToString : string list -> string
val project : string list * table -> table
val chooser : string list * string list-> string list
end;;
module UsingTable : TABLE =
struct
type table = (string list * string list* (string list) list)
type database = table list
let create_table (a,b,c) = (a,b,c)
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
let project (conditions, aTable)= (
let rec innerProc tmp= function
n,[],v->List.rev tmp
|n,cH::cT,v-> if List.mem cH conditions
then innerProc (["True"]::tmp) (n,cT,v)
else innerProc (["False"]::tmp) (n,cT,v)
in
let trueFalseList = innerProc [] aTable
let rec finalListCreator = match aTable with
n,[],[]->n,[],[]
|n,cH::cT,[]->n,chooser cH ::finalListCreator cT,[]
|n,c,h::t -> n,c,chooser h ::finalListCreator t
)
let rec listToString aList = match aList with
[] -> ""
| h::t -> "\t"^h^"\t"^listToString t
let rec printTable aTable = match aTable with
[],[],[] -> ""
| [],[],vH::vT -> "\n"^(listToString vH)^printTable ([],[],vT)
| [],cH::cT,v -> "\t"^cH^"\t"^printTable([],cT, v)
| n, c , v-> "\n"^(List.hd n)^"\n\n"^printTable([],c, v)
end;;
let atable =UsingTable.create_table (["Student"], ["Id";"Name";"Gender";"Course"],
[["001";"Jim";"M";"AlgoDS"];
["002";"Linnea";"F";"Databases"];
["003";"Anna";"F";"C#"];
["004";"Abby";"F";"C#"];
["005";"Arthur";"M";"JavaScript"]]);;
print_string (UsingTable.printTable atable) ;;
These lines have at least two syntax problems:
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
First, the for .. done is one expression, and List.rev ans is another expression. You need a semicolon (;) between them.
Second, you should use ;; only when you want the input up to that point to be processed. But here if you process the input at the ;; you are missing a right parenthesis.
In my opinion, you should be entering ;; only at the toplevel. The best way to think of this token is as an instruction to the toplevel. It's not part of normal OCaml syntax.
These are only the first two errors. There are quite a few other errors in the code. It might be good to add one function at a time to the module so you can concentrate on a few problems at a time.
Update
The environment you're using is a little bit extra complicated because it has an Evaluate button that asks to evaluate what you've typed so far. This makes the ;; token much less useful.
It would be a good discipline to use this environment without using the ;; token at all. Just click the Evaluate button when you want an evaluation.
The main trick is if you want to evaluate a statement (a unit-valued expression in OCaml) at the outer level, like say Printf.printf "hello world\n". The usual idiom to avoid putting ;; before this is to make it into a declaration like so:
let () = Printf.printf "hello world\n"
That is the one non-obvious idiom that people use when writing source code (where the ;; almost never appears in my experience).
I'm working on a function that takes two arguments: a match value and a list of tuples. The goal is to match the first value (a string) in each tuple against the match value (also a string) and add the second value (an int) in those matching tuples to a new list, which is returned in sorted order. I started out with:
let getElems strMatch tupList =
let rec loop acc = function
| [] -> acc
| hd :: tl ->
match hd with
| (strMatch, v) -> loop (v :: acc) tl
| _ -> loop (acc) tl
List.sort (loop [] tupList)
...but came to realize that strMatch is out of scope as a pattern match so the second rule would never get matched. So I started trying to pass strMatch to the inner code blocks like so:
let getElems strMatch tupList =
let rec loop strMatch acc tupList =
match tupList with
| [] -> acc
| hd :: tl ->
match hd with
| (strMatch, v) -> loop strMatch (v :: acc) tl
| _ -> loop strMatch (acc) tl
List.sort (loop strMatch [] tupList)
...but the value is still out of scope in the match blocks. I suppose it would be possible to pass strMatch into those blocks but this seems messy and I'm wondering if there is a more elegant way.
EDIT: So here are my results...
First, I get the warning "This rule will never be matched." When I run the function as-is:
getElems "A" [("A",5);("BB",6);("AA",9);("A",0)];;
> val it : int list = [0; 5; 6; 9]
But if I hard code strMatch as "A" in the function:
getElems "A" [("A",5);("BB",6);("AA",9);("A",0)];;
> val it : int list = [0; 5]
Which is what is desired. But I'm required to take any match as an argument.
I'm trying to create a functor that makes a polynomial ring out of a ring. My underlying type, Ring_elt, has the following signature:
module type Ring_elt = sig
type t
val add : t -> t -> t
val mul : t -> t -> t
val zer : t
val one : t
val neg : t -> t
end;;
My polynomial functor looks like:
module Make_Poly2(Underlying:Ring_elt) = struct
type t = Poly of Underlying.t list
let rec create lst =
match List.rev lst with
| Underlying.zer :: tl -> create List.rev tl
| _ -> Poly of lst
end;;
(so the 'create' function should take a list, remove the leading zeros, and then return the polynomial of the result). However, I get a syntax error and utop underlines the "zer" after "Underlying."
By comparison, the following code (for making integer polynomials) works:
module Make_int_poly = struct
type t = Poly of int list
let rec create lst =
match List.rev lst with
| 0 :: tl -> create (List.rev tl)
| _ -> Poly lst
end;;
Any idea what's going on?
An OCaml pattern is built from constants, data constructors, and new names bound by the pattern match. Underlying.zer isn't any of those things. But 0 is one of them.
Seems like you can just use an if to compare against Underlying.zer.
Jeffrey's answer is good but instead of correcting it with an if construction, what you should do is the following : use algebraic data types
Instead of writing
val zer : t
val one : t
You could write
module type Ring_elt = sig
type t = Zer | One | Num of t
val add : t -> t -> t
val mul : t -> t -> t
val neg : t -> t
end
module Make_int_poly = struct
type t = Poly of int list
let rec create lst =
match List.rev lst with
| Underlying.Zer :: tl -> create (List.rev tl)
| _ -> Poly lst
end
It's a much better way of doing it since you can easily pattern match on it and even add some constants to your type t without problems.