let rec move_robot (pos: int) (dir: string) (num_moves: int) : int =
let new_forward_position = pos + num_moves in
if (new_forward_position > 99) then failwith "cannot move beyond 99 steps"
else new_forward_position
let new_backward_position = pos - num_moves in
if (new_backward_position pos < 0) then failwith "cannot move less than 0 steps"
else new_backward_position
begin match dir with
| "forward" -> new_forward position
| "backward" -> new_backward_position
end
I keep on getting "unexpected token in" for the let new_backward_position line. What is my error?
Here is a code that compiles:
let rec move_robot pos dir num_moves =
let new_forward_position = pos + num_moves in
if new_forward_position > 99 then failwith "cannot move beyond 99 steps";
let new_backward_position = pos - num_moves in
if new_backward_position < 0 then failwith "cannot move less than 0 steps";
begin match dir with
| "forward" -> new_forward_position
| "backward" -> new_backward_position
end
I modified several things:
Important: if foo then bar else qux is an expression in OCaml, which takes either the value bar or qux. Thus bar and qux needs to have the same type.
new_backward_position instead of new_backward_position pos
you don't need type annotations : OCaml has type inference
no need for parentheses around the if clause
typo in new_forward position
Also, with your code's logic, let _ = move_robot 0 "forward" 5 fails. Shouldn't it return 5 instead? I suggest you define a sum type for pos and do a pattern matching on it first.
Your code has this basic structure if you assume the failures won't happen:
let f () =
let p = 3 in p
let q = 5 in q
...
It's not clear what you're trying to do, but this isn't well formed OCaml (as the compiler tells you). Maybe want you want is something more like this:
let f () =
let p = 3 in
let q = 5 in
match ...
If so, you need to move your ifs before your ins:
let f () =
let p = if badp then failwith "" else 3 in
let q = if badq then failwith "" else 5 in
match ...
Or maybe this is more what you want:
let f () =
let p = 3 in
let () = if badp p then failwith "" in
let q = 5 in
let () = if badq q then failwith "" in
match ...
(I hope this is helpful.)
Related
I have this error showing up when i tried to test my functions, would anyone know where this error came from ?
let () =
let t = Sys.time() in
let args_n = Array.length Sys.argv - 1 in
let args_list = Array.to_list (Array.sub Sys.argv 1 args_n) in
List.iter (fun element ->
let length_of_element = String.length element in
let text = check_if_file(List.nth args_list 1) in
let int_ls = search (to_list_ch element) text length_of_element) (check_if_file(List.nth args_list 0 )) in
if (List.length int_ls)> 1 then print_string "pattern found at characters "
else if (List.length int_ls) = 1 then print_string "Pattern found at character "
else print_string "No patterns found."
;
print_ls int_ls;
Printf.printf "Execution time: %fs\n" (Sys.time() -. t);;
Ocaml is telling that it came from the closing parenthesis after length_of_element but the things is if i remove it, the open parenthesis at the List.iter line won't have any closing parenthesis matching with him.
let int_ls = search (to_list_ch element) text length_of_element) (check_if_file(List.nth args_list 0 )) in
Before trying to make this functions iterating on a list of string it was like that :
let () =
let t = Sys.time() in
let args_n = Array.length Sys.argv - 1 in
let args_list = Array.to_list (Array.sub Sys.argv 1 args_n) in
let pattern =check_if_file(List.nth args_list 0 )in
let lpattern = String.length pattern - 1 in
let text = check_if_file(List.nth args_list 1) in
let int_ls = search (to_list_ch pattern) text lpattern in
if (List.length int_ls)> 1 then print_string "pattern found at characters "
else if (List.length int_ls) = 1 then print_string "Pattern found at character "
else print_string "No patterns found."
;
print_ls int_ls;
Printf.printf "Execution time: %fs\n" (Sys.time() -. t);;
But it was work only for one string and not multiple string, so i trie to iterate in a list to make it work not for only one string but a list of string
The let x = e1 in e2 construct evaluates e1, and then makes its result available in e2. In your case, you have no in e2, so there is not much point in having let x =.
What you have written is List.iter (fun -> ... let x = e1) in e2. But what do you expect x to mean inside e2? Should it be the result of the first evaluation of e1 in the loop? The last one? What if the body of the loop is never executed because the list you iterate over is empty? I suggest to step back and think a bit more about what you are actually trying to compute.
I wrote these function to build a sequence from a function i am having a stack overflow error while testing it
let rec from_fun f ()=
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f)
from_fun (fun () -> let x = 0 in if x<10 then Some (x+1) else None)
thanks
Your function always returns Some 1. It never returns None. So the sequence is infinitely long and the stack overflows while building it.
If you want a function to return different values when you call it, you can do two things. First, you can pass it different parameters. This isn't possible for your design of from_fun--the parameter to the function is always (). Second, your function can be impure. I.e., the function can maintain some mutable state.
Here is an example of a generator:
let range_generator from below step =
let counter = ref from
in fun () ->
if (!counter < below)
then (let result = (Some !counter) in
counter := !counter + step;
result)
else None
For example, a call to range_generator 0 10 2 returns a closure over an internal counter mutable variable which generates all natural even numbers below 10:
# let gen = range_generator 0 10 2;;
val gen : unit -> int option = <fun>
Each call to gen possibly mutates the internal counter:
# gen();;
- : int option = Some 0
# gen();;
- : int option = Some 2
# gen();;
- : int option = Some 4
# gen();;
- : int option = Some 6
# gen();;
- : int option = Some 8
# gen();;
- : int option = None
# gen();;
- : int option = None
With your function:
# from_fun (range_generator 0 5 1);;
- : int list = [0; 1; 2; 3; 4]
The variable x you are using is local to the anonymous function you are using. As a result the function always return Some 1.
What you probably wanted to do is for the function to take an argument:
let rec from_fun f n =
match f n with
| None -> Nil
| Some e -> Cons(e, from_fun f e)
let seq = from_fun (fun x -> if x<10 then Some (x+1) else None) 0
EDIT:
Here is a solution with the appropriate type signature:
let rec from_fun f () =
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f ())
let x = ref 0
let seq = from_fun
(fun () ->
let v = !x in
if v < 10
then begin
x := v + 1;
Some v
end
else None)
()
It is worth noting that because of the side effects, you would have to reinitialise x before building a new sequence. The unit argument passed in parameter to from_fun is unnecessary, you could remove it.
Can someone explain the syntax used for when you have nested functions?
For example I have a outer and an inner recursive function.
let rec func1 list = match list with
[] -> []
|(head::tail) ->
let rec func2 list2 = match list2 with
...
;;
I have spent all day trying to figure this out and I'm getting a ever tiring "Syntax error".
You don't show enough code for the error to be obvious.
Here is a working example:
# let f x =
let g y = y * 5 in
g (x + 1);;
val f : int -> int = <fun>
# f 14;;
- : int = 75
Update
Something that might help until you're used to OCaml syntax is to use lots of extra parentheses:
let rec f y x =
match x with
| h :: t -> (
let incr v = if h = y then 1 + v else v in
incr (f y t)
)
| _ -> (
0
)
It's particularly hard to nest one match inside another without doing this sort of thing. This may be your actual problem rather than nested functions.
I want to write a function that taking a string and return a list of char. Here is a function, but I think it is not do what I want ( I want to take a string and return a list of characters).
let rec string_to_char_list s =
match s with
| "" -> []
| n -> string_to_char_list n
Aside, but very important:
Your code is obviously wrong because you have a recursive call for which all the parameters are the exact same one you got in. It is going to induce an infinite sequence of calls with the same values in, thus looping forever (a stack overflow won't happen in tail-rec position).
The code that does what you want would be:
let explode s =
let rec exp i l =
if i < 0 then l else exp (i - 1) (s.[i] :: l) in
exp (String.length s - 1) []
Source:
http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#strings
Alternatively, you can choose to use a library: batteries String.to_list or extlib String.explode
Try this:
let explode s = List.init (String.length s) (String.get s)
Nice and simple:
let rec list_car ch =
match ch with
| "" -> []
| ch -> String.get ch 0 :: list_car (String.sub ch 1 (String.length ch - 1));;
How about something like this:
let string_to_list str =
let rec loop i limit =
if i = limit then []
else (String.get str i) :: (loop (i + 1) limit)
in
loop 0 (String.length str);;
let list_to_string s =
let rec loop s n =
match s with
[] -> String.make n '?'
| car :: cdr ->
let result = loop cdr (n + 1) in
String.set result n car;
result
in
loop s 0;;
As of OCaml 4.07 (released 2018), this can be straightforwardly accomplished with sequences.
let string_to_char_list s =
s |> String.to_seq |> List.of_seq
Here is an Iterative version to get a char list from a string:
let string_to_list s =
let l = ref [] in
for i = 0 to String.length s - 1 do
l := (!l) # [s.[i]]
done;
!l;;
My code, suitable for modern OCaml:
let charlist_of_string s =
let rec trav l i =
if i = l then [] else s.[i]::trav l (i+1)
in
trav (String.length s) 0;;
let rec string_of_charlist l =
match l with
[] -> ""
| h::t -> String.make 1 h ^ string_of_charlist t;;
i'm trying to learn ocaml right now and wanted to start with a little program, generating all bit-combinations:
["0","0","0"]
["0","0","1"]
["0","1","0"]
... and so on
My idea is the following code:
let rec bitstr length list =
if length = 0 then
list
else begin
bitstr (length-1)("0"::list);
bitstr (length-1)("1"::list);
end;;
But i get the following error:
Warning S: this expression should have type unit.
val bitstr : int -> string list -> string list = <fun>
# bitstr 3 [];;
- : string list = ["1"; "1"; "1"]
I did not understand what to change, can you help me?
Best regards
Philipp
begin foo; bar end executes foo and throws the result away, then it executes bar. Since this makes only sense if foo has side-effects and no meaningful return value ocaml emits a warning if foo has a return value other than unit, since everything else is likely to be a programmer error (i.e. the programmer does not actually intend for the result to be discarded) - as is the case here.
In this case it really does make no sense to calculate the list with "0" and then throw it away. Presumably you want to concatenate the two lists instead. You can do this using the # operator:
let rec bitstr length list =
if length = 0 then
[list]
else
bitstr (length-1)("0"::list) # bitstr (length-1)("1"::list);;
Note that I also made the length = 0 case return [list] instead of just list so the result is a list of lists instead of a flat list.
Although sepp2k's answer is spot on, I would like to add the following alternative (which doesn't match the signature you proposed, but actually does what you want) :
let rec bitstr = function
0 -> [[]]
| n -> let f e = List.map (fun x -> e :: x) and l = bitstr (n-1) in
(f "0" l)#(f "1" l);;
The first difference is that you do not need to pass an empty list to call the function bitsr 2 returns [["0"; "0"]; ["0"; "1"]; ["1"; "0"]; ["1"; "1"]]. Second, it returns a list of ordered binary values. But more importantly, in my opinion, it is closer to the spirit of ocaml.
I like to get other ideas!
So here it is...
let rec gen_x acc e1 e2 n = match n with
| 0 -> acc
| n -> (
let l = List.map (fun x -> e1 :: x) acc in
let r = List.map (fun x -> e2 :: x) acc in
gen_x (l # r) e1 e2 (n - 1)
);;
let rec gen_string = gen_x [[]] "0" "1"
let rec gen_int = gen_x [[]] 0 1
gen_string 2
gen_int 2
Result:
[["0"; "0"]; ["0"; "1"]; ["1"; "0"]; ["1"; "1"]]
[[0; 0]; [0; 1]; [1; 0]; [1; 1]]