I am trying to understand Ocaml and running following code from here:
let rec fib n =
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () =
let arg = int_of_string Sys.argv.(1) in
print_int (fib arg);
print_newline ();
exit 0;;
main ();;
However, I cannot understand why () and in are needed and why following code (which is much cleaner) does not work:
let rec fib n =
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main =
let arg = int_of_string Sys.argv.(1);
print_int (fib arg);
print_newline;
exit 0;; (* Line 7. Error is coming from here.*)
main;;
Above code gives following error:
File "fib_simpler.ml", line 7, characters 8-10:
Error: Syntax error
I notice that removing () only give warning, while removing in gives error and program execution stops.
Keeping in and () after print_newline removes all warnings and errors. So () is not really needed with main keywords.
Above is shown in comments below:
let rec fib n = (*(n) also works here*)
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () = (*removing () here does not matter*)
let arg = int_of_string Sys.argv.(1) in (* in keyword is essential here*)
print_int (fib arg);
print_newline (); (*removing () causes warning *)
exit 0;;
main ();; (*removing () here does not matter*)
Any explanation will be appreciated.
OCaml is an expression-based language. It does not have statements, and therefore ; is not a statement terminator, but a sequence operator (similar to the comma operator of C). <expr1>; <expr2> is approximately just a short-hand for let () = <expr1> in <expr2>. It evaluates expr1, discards its value, then evaluates expr2 and returns that value.
let <pattern> = <expr1> in <expr2> is an expressions which binds the result of expr1 according to <pattern>, which may just be a simple identifier or a more complex record pattern for example, in the context of expr2. The bindings created by <pattern> will not exist outside expr2.
Using (), called "unit" in a binding defines a function. If you omit the argument, you're not defining a function, just a value. The difference is that a value is evaluated immediately, and just once, while a function will be evaluated when it is "called" by applying arguments to it. A function that expects () as an argument must be given () as the argument to execute it, otherwise you're just passing the function itself around. And if you're just discarding it, as you do above, that is almost always an error. Hence the warning.
In short:
let arg = int_of_string Sys.argv.(1); ... without an in separating two expressions is a syntax error. The compiler just doesn't realize it until it gets to the end of the current expression and discovers there is no in to be found there.
let main () =... defines a function
let main = ... defines a value
print_newline (); ... applies the argument () to print_newline, thereby executing it, then discards the return value
print_newline; ... doesn't really do anything
Finally, if you're just going to execute main once, you can reduce
let main () = ...;;
main;;
to
let () = ...;;
You don't need a named function unless you're going to use it multiple times.
Related
I tried this in utop but since I am not familar with a dune project, it failed and report the error
This expression has type int list but an expression was expected of type unit.
This is for the line filter greaterthanfive list1
open Base
let rec filter p inputList = match inputList with
[] -> []
| x::xs -> if p x then x::filter p xs else filter p xs
;;
let greaterthanfive num =
if num>5 then true else false;;
let () =
let list1 = [1;6;8;3] in
filter greaterthanfive list1
;;
let () = <expr> means <expr> is expected to evaluate to ()
More generally, this construct has the form let <pattern> = <expr>, where <pattern> is anything you can put in the branch of a match expression. And () is a literal pattern that will only match this value, which is also the only value of the type unit.
In program code it is good practice to use let () = <expr> for the main part of the program to make sure it evaluates to () and indicates it will only have side-effects, such as printing to the terminal or writing to a file.
In utop however, you usually want the value of an expression to be sent to utop to be printed, and in that case let () = <expr> prevents that. Instead you should just evaluate the expression directly.
I have been trying to create a cycle to call an changing function i-times , but for some reason the cycle itself always spits out an error. I have also tried an recursive function to call itself but didn't work either.
Is it even possible to make it work with for`s.
r is a list of lists.
a and b are two immutable variables.
(List.nth (r) (i)) gives an list.
let rec changing (lista: 'a zlista) (a:int) (b:int) =
match lista with
| Vazio -> failwith "NO"
| Nodo (n, l, r) ->
if a <= n && n <= b then n
else if a < n && b < n then changing l a b
else changing r a b
let rec call_changing (a: int) (b: int) =
for i=0 to ort do
changing (List.nth (r) (i)) (a) (b)
done;;
Changing returns an int, in order to call it in a for loop you have to ignore the result of the function :
for i = 0 to ort do
let _ = changing .... in ()
done
(* Or *)
for i = 0 to ort do
ignore (changing ....)
done
EDIT :
If you want to print the result you can do :
for i = 0 to ort do
Printf.printf "Result for %d iteration : %d\n" i (changing ....)
done
See the Printf documentation for more information
To perhaps generalize on Butanium's answer, OCaml is not a pure functional programming language. It does contain imperative features. Imperative features are all about side-effects. Functions which exist for the purpose of their side-effects on the system (like Printf.printf) by convention return () (the literal for the unit type).
A for loop is an imperative feature. As such, it expects that any expression (or expessions chained with ;) contained within will return unit. If they do not, you will receive warnings.
The for loop expression itself (for ... = ... to ... do ... done) returns unit so the warning can clue you in that any code in the loop which does not have side-effects is inconsequential, and while your code will compile and run, it may not do what you expect.
As a side note, I believe you may be a little overzealous with the parentheses, likely making your code harder to read.
let rec call_changing (a: int) (b: int) =
for i=0 to ort do
changing (List.nth (r) (i)) (a) (b)
done;;
Properly indented and with extraneous parens removed:
let rec call_changing (a: int) (b: int) =
for i=0 to ort do
changing (List.nth r i) a b
done;;
I just recently started to learn OCaml, and I have a small issue
I'm trying to generate a series of numbers with the following function
let new_num =
let cpt = ref (-1) in
fun () -> incr cpt; Printf.sprintf "__number_%i" !cpt
When I run ocaml in a terminal I can get a number with something like:
let n = new_num()
But when I add the above function to an existing file (that works, just provided to me) and try to call it like this, I get an error on the line containing with the call to the new_num function
let matching_function i = match i with
| case1 -> ... (* a code that works fine*)
| C(e,s1,s2)->
let n1 = new_num() in
n1
let n2 = new_num() in
n2
let code_e = trl e in (* trl is a working function somewhere else in my code)
code_e
(* rest of code and print n1,n2*)
if I remove the following part and run the file everything works perfectly.
let n1 = new_num() in
n1
let n2 = new_num() in
n2
I don't understand why this works in terminal interpreter but not when I run it in a .ml file? Can someone please explain it to me and help call it correctly? (sorry for the novice question)
The code in the file is not syntactically valid, that's all that's going on.
You can't have this:
let n1 = new_num () in n1
let ...
The second let isn't syntactically valid at that point.
You almost certainly want something like this:
let n1 = new_num () in
let n2 = new_num () in
...
This defines n1 and n2 for later use in the code.
The reason it works in the interpreter is that you're not typing in this same code.
Here's what you actually see if you type the erroneous lines into the toplevel (the interpreter):
# let n1 = new_num () in n1
let n2 = new_num () in n2;;
Error: Syntax error
If you add ;; between the two lines it is accepted (though it doesn't actually define top-level values named n1 and n2). But this isn't the same code. The ;; has a syntactic effect.
As a side comment, this expression:
let n1 = new_num () in n1
is exactly equivalent to this expression:
new_num ()
In particular, it doesn't define a value n1 that you can use later. The scope of the definition of v in let v = e1 in e2 is just e2.
fun count_wcs p =
let
val count = 0
in
g (fn () => count + 1) (fn y => 1) p
end
I'm doing homework and we're not supposed to use mutations, this doesn't reassign the value to anything but it doesn't feel right. Please, don't say what is the right way to do this, because I'm supposed to figure this out.
datatype pattern = Wildcard
| Variable of string
| UnitP
| ConstP of int
| TupleP of pattern list
| ConstructorP of string * pattern
fun g f1 f2 p =
let
val r = g f1 f2
in
case p of
Wildcard => f1 ()
| Variable x => f2 x
| TupleP ps => List.foldl (fn (p,i) => (r p) + i) 0 ps
| ConstructorP(_,p) => r p
| _ => 0
end
This function g has to receive a type unit -> int function as the first argument. I checked the count after I called the function and got 0, so it is ok to write it like this, right? But still, it does feel sloppy.
Added the context (function g and the datatype used). The function count_wcs is supposed to count the number a Wildcard pattern appears in a pattern.
This does not count as a mutation, but it does resemble what you might do if you had them and is probably not going to work, depending on what it is you're doing. Mutations require references and they're made with ref and are de-referenced with !. So just stick away from those. :-)
You're doing something that will be of little benefit:
let
val count = 0
in
...
end
will bind count to 0, but will never cause count to have any other value; I presume that you want to eventually have that count increases. If it had been a reference, val count = ref 0, you could increment it by doing count := !count + 1, but since it's not, you have to make count a variable of some function for it to change.
For example:
fun count_4s ([], count) = count
| count_4s (x::xs, count) = count_4s (xs, if x = 4 then count + 1 else count)
In each call count is constant, but in each subsequent, recursive call it is possibly incremented.
This function g has to receive a type unit -> int function as first argument.
...
g (fn () => count + 1) (fn y => 1) p
...
[...] But still it does feel sloppy.
Assuming that g's first arguments have no side-effects and do not throw exceptions and do not loop forever, all they can do is return the same thing on every call. This makes them rather boring. Typically functions that either take as input or return () : unit do something else, like read or write from a source external to the program.
I wouldn't call it sloppy. Just a bit weird, without knowing the context.
It's very easy to identify mutation in standard ML - if you don't use ref variables and assign them new values with :=, it's not mutation.
And you don't, so you aren't mutating anything.
Also, your function can be simplified to
fun count_wildcards p = g (fn () => 1) (fn _ => 1) p
which makes it even clearer that nothing gets mutated.
(It's not at all clear what it's supposed to accomplish, so it's impossible to tell whether your solution is correct.)
I have a function save that take standard input, which is used individually like this:
./try < input.txt (* save function is in try file *)
input.txt
2
3
10 29 23
22 14 9
and now i put the function into another file called path.ml which is a part of my interpreter. Now I have a problem in defining the type of Save function and this is because save function has type in_channel, but when i write
type term = Save of in_channel
ocamlc complain about the parameter in the command function.
How can i fix this error? This is the reason why in my last question posted on stackoverflow, I asked for the way to express a variable that accept any type. I understand the answers but actually it doesn't help much in make the code running.
This is my code:
(* Data types *)
open Printf
type term = Print_line_in_file of int*string
| Print of string
| Save of in_channel (* error here *)
;;
let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i = n then begin
close_in ic;
(line)
end else aux (succ i)
| None ->
close_in ic;
failwith "end of file reached"
in
aux 1
(* get all lines *)
let k = ref 1
let first = ref ""
let second = ref ""
let sequence = ref []
let append_item lst a = lst # [a]
let save () =
try
while true do
let line = input_line stdin in
if k = ref 1
then
begin
first := line;
incr k;
end else
if k = ref 2
then
begin
second := line;
incr k;
end else
begin
sequence := append_item !sequence line;
incr k;
end
done;
None
with
End_of_file -> None;;
let rec command term = match term with
| Print (n) -> print_endline n
| Print_line_in_file (n, f) -> print_endline (nth_line n f)
| Save () -> save ()
;;
EDIT
Error in code:
Save of in_channel:
Error: This pattern matches values of type unit
but a pattern was expected which matches values of type in_channel
Save of unit:
Error: This expression has type 'a option
but an expression was expected of type unit
There are many errors in this code, so it's hard to know where to start.
One problem is this: your save function has type unit -> 'a option. So it's not the same type as the other branches of your final match. The fix is straightforward: save should return (), not None. In OCaml these are completely different things.
The immediate problem seems to be that you have Save () in your match, but have declared Save as taking an input channel. Your current code doesn't have any way to pass the input channel to the save function, but if it did, you would want something more like this in your match:
| Save ch -> save ch
Errors like this suggest (to me) that you're not so familiar with OCaml's type system. It would probably save you a lot of trouble if you went through a tutorial of some kind before writing much more code. You can find tutorials at http://ocaml.org.