I tried:
let x = 1; let y = 2;;
but is a syntax error. Why is that?
Note I know you can do
let x = 1 let y = 3;;
though thats not my question.
I tried:
let x = 1; let y = 2;;
but is a syntax error. Why is that?
Note I know you can do
let x = 1 let y = 3;;
though thats not my question.
let
is for expressions ā something which will resolve to a result. Sequencing is for statements, with no used value but generally having some side-effect (eg. screen output, or modifying a memory cell).
If let x = 1;
was accepted, it wouldnāt do anything. The scope of x
only exists within that statement.
What you want instead is let x = 1 and y = 2 in
ā¦ followed by use of x
and y
. Or let x = 1 in let y = 2 in
ā¦
Think of building an expression rather than a sequence of statements.
Because itās read as:
let x =
1; (* this should have type unit but only gives a warning *)
let y = 2
;;
Your expression doesnāt have any value.
Because sometimes you want to write things like:
let x =
print_endline "hello";
1
I guess I still donāt get it and I donāt know what it is. I will try to ask something to perhaps figure out whats confusing me. I guess I donāt understand what the difference is between statements and expressions in OCAML. I am also confused when ;
vs ;;
is usedā¦thnx for the help.
I think this sequencing, statements and expression things is still not clear to me at all. Perhaps going through this example would help?
let result =
let test x = ( p 650; fun y -> ( p x ) + ( p y ) ) in test ( p 4 ) ( test ( p 5 ) ( p 6 ) );;
what on earth is going on there!
I thought @zapashcanonās answer was pretty good, but given your confusion, maybe have a look at https://ocaml.org/learn/tutorials/structure_of_ocaml_programs.html#The-sequence-operator , which explains it in further detail.
oh, Iāve read that before of course! Though, perhaps I can clarify what confuses me about that document. What does this mean:
The semi-colon
;
may be seen as having typeunit -> 'b -> 'b
ā it takes two values and simply returns the second one, the first expression is guaranteed to be evaluated before the second.
What confuses me a lot is that ;
ātakes the unit typeā. I thought to take the unit type one has to pass itā¦ like:
let f () = 2;;
f ();; (* returns 2 afaik*)
what do you mean it only gives a warning? To me it gives me a syntax error:
# let x =
1; (* this should have type unit but only gives a warning *)
let y = 2
;;
Error: Syntax error
The ()
value is the only literal value of type unit
, but itās not the only expression of type unit
For example, the function ignore
takes a value and returns a result of type unit
: ignore 5 (* has type unit *)
Its implementation is: let ignore _anything = ()
As you can imagine, many different functions can return ()
and therefore so can many different expressions. So saying that the semicolon āoperatorā takes two expressions, one of type unit
, and the other of polymorphic type 'b
, means that it looks like this:
expr1 ; expr2
ā¦ where expr1 : unit
and expr2 : 'b
.
The exampleās incomplete; you need to complete it with an expression; e.g.
let x =
1;
let y = 2 in y + 3
;;
results in
Line 2, characters 2-3:
Warning 10: this expression should have type unit.
val x : int = 5
I guess your explanation makes sense, after, to my surprise the following code gave me a warning:
# let do_this x = ( add2 5; fun y -> y + 4 );;
Warning 10: this expression should have type unit.
val do_this : 'a -> int -> int = <fun>
although, I guess the code DID work since:
# do_this 2 4;;
- : int = 8
worked.
This are making a lot more sense. But I still donāt understand the difference between expressions and statements.
what [quote=āatavener, post:2, topic:4507ā]
Think of building an expression rather than a sequence of statements.
[/quote]
what is the difference between a statement and an expression?
Statements donāt āreturnā a value. E.g. in a language like say Python:
if x == 1: print("One")
This is a statement. It doesnāt āresult inā a final value. In OCaml:
if x = 1 then print_endline "One"
This is an expression. It āresults inā a value. In this case ()
of type unit
. OCaml is designed so that almost all syntax is an expression. The standard if ... else ...
, the try ... with ...
, even for ... in ... do
. This is useful because itās more expressive. Different parts of the syntax compose together because everything results in values after all. While other languages had to add special syntax for this (e.g. Pythonās X if COND else Y
and C/C++/etc.'s ternary syntax), ML (and Lisp) languages get it from day one.
IMO, a good way to start is to stop using the top level, to write all your code in a file and to wrap all your code in a single āmainā function (let _ = ...
). Then, you can stop completely using ;;
youāre only left with let ... in
and statements.
let _ =
let rec fib x =
if x < 0 then failwith "fib";
if x < 2 then x else fib (x - 1) + fib (x - 2)
in
let print_res x =
Printf.printf "fib %d = %d" x (fib x)
in
let x1 = 5 in
print_res x1;
let x2 = 6 in
print_res x2;
()
Once youāre at ease with this, itāll be easier to understand. You would just rewrite it like that:
let rec fib x =
if x < 0 then failwith "fib";
if x < 2 then x else fib (x - 1) + fib (x - 2)
let print_res x =
Printf.printf "fib %d = %d" x (fib x)
let _ =
let x1 = 5 in
print_res x1;
let x2 = 6 in
print_res x2;
()
Not sure if you are familiar with Python, but I will try translating your questions to that.
let x = 1 ; let y = 2
(* this fails because let .. = .. must be followed by `in`.
In the top level / outer scope of a module (such as your file.ml)
you don't need the "in," but for all the nested let .. you do.
*)
is essentially equivalent to:
x = ( 1; y = 2
and
let x = 1 let y = 3;;
(* with less misleading formatting: *)
let x = 1
let y = 3
;;
is
x = 1 ; y = 2
# aka
x = 1
y = 2
basically ;
in ocaml is a very strong binding operator, as opposed to being a statement/expression separator in most other languages.
When you see a ;
in OCaml you should read it at "put () around the previous expression, and this one, and make sure that the previous expression returned type unit
".
so revisiting your original:
let x = 1; let y = 2
;;
first we need to close the let ..
scope:
let x = 1; let y = 2 in y
;;
(* with the implicit grouping/binding order spelled out: *)
let x = ( 1; (let y = 2 in y) )
(* x is now 2 *)
OCaml will still complain, because the type of 1
is int
, and youāre using ;
to denote you want a side-effect and donāt care about the value of the expression (since nothing is recording it).
Thereās a function in the standard library called ignore
which has signature 'a -> unit
, it is basically implemented like this:
let ignore _whatever = ()
We can use it like this to satisfy the type checker:
let x = ignore 1; let y = 2 in y
(* more readable formatting: *)
let x =
ignore 1;
let y = 2 in
y
Hope that helps
What does this mean? I think Iām starting to understand better that everything in OCAML results in a value (even though the distinction between expressions and statements is still not clear to me). I guess what I am confused is that I ONLY know python really. So Iām having a hard time understand what OCAML does. I thought python always returned values too. The way I thought about python is I have a bunch of statements (pretty much one per line usually) and they get executed and return a value. So for me everything is a statement in the programming I am used to. So what I am trying to understand is how do things work in OCAML. It seems once the distinction btw statements and expressions is clear everything would make sense to me.
me asking for clarification on the precise difference between statements and expressions: What is the difference between statements and expressions in OCAML?
I donāt think this is right. Correct me if Iām wrong. Check this:
Python 3.7.3 (default, Mar 27 2019, 16:54:48)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print("One")
One
>>> x = print("One")
One
>>> x
>>> print(x)
None
>>> y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
it seems that x DOES have a value. The print statement is a function and it returns None afaik. I tried printing y to emphasize that x had to be assigned.
print("One")
is an expression. if x == 1: print("One")
doesnāt.
>>> x = 1
>>> y = (if x == 1: print("One"))
File "<stdin>", line 1
y = (if x == 1: print("One"))
^
SyntaxError: invalid syntax
Iām confused about this. I can easily do:
# let x = 3;;
val x : int = 3
not only in top level but in my .ml
file to. I can define a variable and then use it later if I need to. My question makes me feel there is something fundamental about OCAML or perhaps fp programming I donāt understand.