SML/NJ code works in REPL but fails to compile - sml

The code below works when typed in the REPL:
type seat = seat_type * int
val my_seat = (Window, 13)
fun aow seat =
case seat of
(Window,_) => "Window"
| (Aisle,_) => "Aisle"
fun is_window (x,_) = x = Window
aow my_seat
is_window my_seat
But if saved in a file and compiled, the expressions aow my_seat and is_window my_seat fail with the following error during compilation:
test1.sml:12.23-16.18 Error: operator is not a function [tycon mismatch]
operator: seat_type
in expression:
Window aow
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:296.17-296.20
If I comment them out, the file compiles and when I type both expressions in the REPL, they work. What may cause this error? And also, if it is relevant, comments about my datatype and type definitions is more than welcome, as I don't see myself fit on this subject.

Adding a val statement before both expressions like:
val x = aow my_seat
val y = is_window my_seat
lets the file compile. Seeing that, I also tried to replace fun before aow and is_window functions. However this results in the following very logical error:
Error: syntax error: replacing VAL with FUN
Apparently, SML does not allow footloose expressions during compilation.

Related

How does one know when try fails? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
let z = 4 in let y=5 in
try
y = z+x
with Failure msg -> msg = "Free identifier: x"
If we do this, how does OCaml know if try fails?? In real, I'm trying to "try function with fail msg" but my function has to return int value. How can you make OCaml know that try has failed by returning int value?
My real code is something like this:
try
let ast = (Prog ([], (Add (Id "x", Num 1)))) in
interp ast = NumV 5
with Failure msg -> msg = "Free identifier: x"
but function has to return int (NumV is NumV of int) and this code doesn't work. msg doesn't show at fail and it does fails.
let interp (p: Ast.prog) : int = ~
I added function interp for additional info
If your function truly has to return an int value, then you have to pick an int value to represent failure. Let's say you pick -1 as your special failure value. Then the code might look like this:
let f x = try x + 1 with Failure _ -> -1
You can't return a message in the failure case and an int in the usual case. All the returns of a function have to be the same type.
That's why there is a type named result. It's used to combine a failure type and a success type into one larger type. The failure value is constructed by Error <value> and the success value is constructed by Ok <value>. These values can be two different types because the Error and the Ok are used to tell which is which. This code would look like this:
let f x = try Ok (x + 1) with Failure _ -> Error "msg"
If what you are trying to do is exit the program with a custom error message, you need to exit the program after printing your error message:
try
let ast = (Prog ([], (Add (Id "x", Num 1)))) in
interp ast = NumV 5
with Failure msg ->
Format.eprintf "Free identifier: x";
exit 2
You might also be trying to raise a custom exception:
exception My_exception of string
try
let ast = (Prog ([], (Add (Id "x", Num 1)))) in
interp ast = NumV 5
with Failure msg ->
raise (My_exception "Free identifier: x")
If the inner equality is supposed to be a pattern matching, you might be trying to write
let ast = (Prog ([], (Add (Id "x", Num 1)))) in
match interp ast with
| NumV n -> n
| _ ->
Format.eprintf "Free identifier: x";
exit 2
(you could also raise an exception, it is unclear what to do without more context)
A value Ok x means that the computation succeeded with x, and a value Error e means that it failed.

This expression has type int list but an expression was expected of type unit

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.

Wrapping up Format.formattter

I am trying to define a function msg which will allow printing debug messages using Format library with an option to control if they displayed or not via debug flag (set from a command line). Here is my naive first attempt:
let debug = ref false
let msg =
let open Format in
(if !debug then fprintf err_formatter else ifprintf err_formatter)
Unfortunately, this does not work, giving me the following error message:
Error: The type of this expression,
('_a, Format.formatter, unit) format -> '_a,
contains type variables that cannot be generalized
What am I doing wrong? Thanks!
This is the value restriction. You can solve it by "eta expansion":
let msg x =
let open Format in
if !debug then fprintf err_formatter x
else ifprintf err_formatter x
Briefly stated, the value restriction avoids unsound behavior by prohibiting the generalization (treatment as fully polymorphic) of anything other than simple values. Your definition for msg is not a simple value. After eta expansion, the definition is a simple value (a lambda). You can read more here: Jacques Garrigue, Relaxing the Value Restriction.
The new code works for me:
# let debug = ref true
val debug : bool ref = {contents = true}
# let msg x =
let open Format in
if !debug then fprintf err_formatter x
else ifprintf err_formatter x;;
val msg : ('a, Format.formatter, unit) format -> 'a = <fun>
# let open Format in
msg "%d " 1; msg "%s" "red rose that I mean";
pp_print_flush err_formatter ();;
1 red rose that I mean- : unit = ()
#

Using length function in OCaml

I'm begining my learning of OCaml and I have been quite stuck on a simple problem.
I'm trying to count with a simple loop the number of letters that I have in a file of 6 lines.
Here's my code :
let fi = open_in "example";;
let string = "";;
let nb_carac = 0;;
for i = 0 to 6 do
string = input_line fi;
nb_carac = (nb_carac + String.length(string));
done;;
Problem is, it doesn't seem to count anything and reaches directly to EOF.
I get the following error message:
Warning 10: this expression should have type unit.
Warning 10: this expression should have type unit.
Exception: End_of_file.
I don't really get it. I have tried each line individually and they all worked. What am i doing wrong?
Thanks!
OCaml does not have mutable variables. You should use tail recursion or references. Read any basic OCaml textbook or tutorial.
Both lines:
string = input_line fi;
nb_carac = (nb_carac + String.length(string));
are understood as useless equality tests (this explains the warning you are getting).
Perhaps you want:
(* shameful *)
let string = ref "";;
let nb_carac = ref 0;;
then e.g.
(* shameful *)
string := input_line fi;
nb_carac := !nb_carac + String.length(!string);
but you should get a very bad grade if you code so imperatively in a functional language like OCaml.
As a rule of thumb, avoid mutating data when coding in OCaml. Of course there are important exceptions to this rule.
The correct solution to your exercise is to use tail recursive functions which do not mutate any data. Look at OCaml standard library stdlib/list.ml for some inspiration.
Probably a better solution to your exercise starts with
let count_lines_and_characters fil = (* incomplete code, fill the ... *)
let rec ....
in ....
;;
Of course you should fill the ....

OCaml syntax trap: multiple lets using separators

I am trying to teach myself OCaml. I've been going nuts over this one syntax trap. I'm told that you can string expressions together in sequence using ";" ie, expr1 ; expr2 executes the first expr, then the second, as expected. For some reason, I cannot get the interpreter to agree with the following input
let x = 5 ; let y = 7;;
Bizarrely if ONLY the first expr is a let, it works. So
let x = 5 ; 7;;
Passes, and evaluates to 7.
Even worse, if I attempt to use parens to compose multiple sequences of statements where the let comes first, it still does not work. I.E.:
let x = 5 ; (let y = 7 ; 9);;
Is an error, even though it consists only of sequences where lets are the first expression. Can someone explain how to get this to work?
One way to look at the problem is that let x = 5 isn't an expression. It's a top-level declaration; i.e., it declares a name x with a value 5.
The ; operator works for combining expressions, but not for declarations.
You don't need to string declarations together with ;. You can just put one after the other:
# let x = 5 let y = 7;;
val x : int = 5
val y : int = 7
#
There is a completely different use of let in OCaml that is part of an expression. In that case it's followed by in:
# (let x = 4 in x + 1);;
- : int = 5
Since this is an expression, you can string several of them together with ;:
# (let x = 4 in x + 1); (let y = 6 in y + 1);;
Warning 10: this expression should have type unit.
- : int = 7
However, as the compiler is warning you, it's not idiomatic to string together arbitrary expressions. Normally you use ; with imperative code. With functional code it doesn't make sense. So the compiler expects all but the last expression to have type unit (which is used for imperative code that does something useful but doesn't return a useful value).