问题
I was trying to write a piece of code that checks if a sentence is a palindrome (if we don't consider spaces and case) but my code won't compile. I get the following error :
File "main.ml", line 12, characters 0-2:
Error: Syntax error
This error corresponds to the second program, line 12 being where the ;; are at.
Entire program
let scan_word () = Scanf.scanf " %s" (fun x -> x)
in
let scan_int () = Scanf.scanf " %d" (fun x -> x)
in
let scan_float () = Scanf.scanf " %f" (fun x -> x)
in
let scan_char () = Scanf.scanf " %c" (fun x -> x)
in
let maj_to_min = function
| c when (c >= 'a' && c <= 'z') -> c
| c -> (char_of_int ( (int_of_char c) - (int_of_char 'A') + (int_of_char 'a')))
in
let convert_string s =
let n = String.length s in
let cur = ref 0 in
let arr = Array.make n ' ';
for i = 0 to (n-1)
do
if s.[i] <> ' '
then begin
arr.(!cur) <- maj_to_min s.[i];
incr cur;
end;
done;
(Array.sub arr 0 cur)
in
let is_palindrome arr =
let n = Array.length arr in
let ans = ref true in
for i = 0 to (n-1)
do
ans := (!ans) && (arr.(i) = arr.(n-1-i));
done;
!ans
in
let n = read_int () in
for i = 1 to n
do
let s = read_line () in
if (is_palindrome (convert_string s)) = true then print_endline s
done;;
Minimal program which doesn't compile :
let scan_word () = Scanf.scanf " %s" (fun x -> x)
in
let scan_int () = Scanf.scanf " %d" (fun x -> x)
in
let scan_float () = Scanf.scanf " %f" (fun x -> x)
in
let scan_char () = Scanf.scanf " %c" (fun x -> x)
in
let maj_to_min = function
| c when (c >= 'a' && c <= 'z') -> c
| c -> (char_of_int ( (int_of_char c) - (int_of_char 'A') + (int_of_char 'a')))
;;
The maj_to_min converts upper case letts to lower-case letters.
I'd like to understand where did I make a mistake when writing code ! Thanks in advance.
回答1:
It doesn't compile because your code is not a syntactically valid OCaml.
An OCaml program is a sequence of value, type, module, and other definitions. Your particular example is trying to define several values. A value definition in OCaml is having the following syntax
let <name> = <value>
Note, that there is no in
part. So the correct (syntactically at least) program would look like this
let scan_word () = Scanf.scanf " %s" (fun x -> x)
let scan_int () = Scanf.scanf " %d" (fun x -> x)
let scan_float () = Scanf.scanf " %f" (fun x -> x)
let scan_char () = Scanf.scanf " %c" (fun x -> x)
let maj_to_min = function
| c when (c >= 'a' && c <= 'z') -> c
| c -> (char_of_int ( (int_of_char c) - (int_of_char 'A') + (int_of_char 'a')))
This program will define 5 functions. Neither will be called, so you would probably like to add a definition that will call it.
The main difference between let <name> = <expr-1> in <expr-2>
and let <name> = <expr>
is that the latter is the value definition which occurs on the program/module top-level. It is the closest to the what is named statement in other languages. The former, I mean the let <name> = <expr-1> in <expr-2>
is an expression, which can occur in any place where an expression is expected. And usually it is used to build complex expressions. e.g.,
let input_user () =
let name = scan_word () in
let age = scan_int () in
let weight = scan_float () in
let gender = scan_char () in
printf "%s is %d years old, weights %g pounds, and has gender %c\n"
name age weight gender
and now to make your binary do something you can call this function, add the following value definition to the top-level of your program, e.g.,
let () = input_user ()
This will serve as an entry point of your program.
To elaborate a little more, this is a general structure of an OCaml program:
(* this is the top-level of your file, each file defines a module
which has the name equal to the file name (but capitalized),
let's imagine that our file is named example.ml therefore it
defines a module named Example
*)
(* this is a top-level constant that is visible to all code that is below
it. You can also access it from other files as `Example.version`.
*)
let version = "0.0.1"
(* this is a mutable reference, the closest to the mutable and global
variable in C *)
let calls = ref 0
(* this is a simple function with two imperative expressions, which uses
values defined above *)
let make_a_call () =
incr calls;
Printf.printf "we made %d calls so far in version %s\n" !calls version
(* this is a function, that defines local variables `d` and `e` and
uses them. These variables are seen only in the body of this
function. More generally `let <v> = <e> in <body>` evaluates `<e>`
binds it to `<v>` and makes `<v>` visible in the scope of `<body>` *)
let complex_function x y =
let d = x + y - 1 in
let e = x * y + 2 in
(d + e) / (x + y)
(* we can even define function inside other functions, the
same as with `d` and `e` above, the `inner_function` is only
visible inside the `complex_function_with_functions` *)
let complex_function_with_functions x =
let inner_function y =
x + y in
inner_function 5 + inner_function 6
(* this is the main function. The name doesn't matter at all, well at
least to OCaml. But it is usually a good idea to have one at least
to cherish others who will be reading your code. This function
demonstrates how you can interleave imperative expressions with
`let` bindings` *)
let main () =
make_a_call ();
let r = complex_function_with_functions 12 in
make_a_call ();
let p = complex_function r 16 in
make_a_call ();
Printf.printf "wow: we get %d and %d, don't know what it means\n" r p
(* finally, let's call the main function to actually run our program *)
let () = main ()
A pro tip, you don't really need to compile this file to run it, as OCaml has an interpreter, so if you put this code in the file named example.ml
then it is as easy as,
$ ocaml example.ml
we made 1 calls so far in version 0.0.1
we made 2 calls so far in version 0.0.1
we made 3 calls so far in version 0.0.1
wow: we get 35 and 12, don't know what it means
来源:https://stackoverflow.com/questions/57416477/basic-ocaml-program-not-compiling