syntax-errorocamlocaml-toplevel

Why syntax error in this very simple print command


I am trying to run following very simple code:

open Str
print (Str.first_chars "testing" 0)

However, it is giving following error:

$ ocaml testing2.ml 
File "testing2.ml", line 2, characters 0-5:
Error: Syntax error

There are no further details in the error message.

Same error with print_endline also; or even if no print command is there. Hence, the error is in part: Str.first_chars "testing" 0

Documentation about above function from here is as follows:

val first_chars : string -> int -> string

first_chars s n returns the first n characters of s. This is the same function as Str.string_before.

Adding ; or ;; at end of second statement does not make any difference.

What is the correct syntax for above code.

Edit: With following code as suggested by @EvgeniiLepikhin:

open Str
let () =
    print_endline (Str.first_chars "testing" 0)

Error is:

File "testing2.ml", line 1:
Error: Reference to undefined global `Str'

And with this code:

open Str;;
print_endline (Str.first_chars "testing" 0)

Error is:

File "testing2.ml", line 1:
Error: Reference to undefined global `Str'

With just print command (instead of print_endline) in above code, the error is:

File "testing2.ml", line 2, characters 0-5:
Error: Unbound value print

Note, my Ocaml version is:

$ ocaml -version
The OCaml toplevel, version 4.02.3

I think Str should be built-in, since opam is not finding it:

$ opam install Str
[ERROR] No package named Str found.

I also tried following code as suggested in comments by @glennsl:

#use "topfind"
#require "str"
print (Str.first_chars "testing" 0)

But this also give same simple syntax error.


Solution

  • An OCaml program is a list of definitions, which are evaluated in order. You can define values, modules, classes, exceptions, as well as types, module types, class types. But let's focus on values so far.

    In OCaml, there are no statements, commands, or instructions. It is a functional programming language, where everything is an expression, and when an expression is evaluated it produces a value. The value could be bound to a variable so that it could be referenced later.

    The print_endline function takes a value of type string, outputs it to the standard output channel and returns a value of type unit. Type unit has only one value called unit, which could be constructed using the () expression. For example, print_endline "hello, world" is an expression that produces this value. We can't just throw an expression in a file and hope that it will be compiled, as an expression is not a definition. The definition syntax is simple,

    let <pattern> = <expr>
    

    where is either a variable or a data constructor, which will match with the structure of the value that is produced by <expr> and possibly bind variable, that are occurring in the pattern, e.g., the following are definitions

    let x = 7 * 8
    let 4 = 2 * 2 
    let [x; y; z] = [1; 2; 3]
    let (hello, world) = "hello", "world"
    let () = print_endline "hello, world"
    

    You may notice, that the result of the print_endline "hello, world" expression is not bound to any variable, but instead is matched with the unit value (), which could be seen (and indeed looks like) an empty tuple. You can write also

    let x = print_endline "hello, world"
    

    or even

    let _ = print_endline "hello, world"
    

    But it is always better to be explicit on the left-hand side of a definition in what you're expecting.

    So, now the well-formed program of ours should look like this

     open Str
    
     let () = 
        print_endline (Str.first_chars "testing" 0)
    

    We will use ocamlbuild to compile and run our program. The str module is not a part of the standard library so we have to tell ocamlbuild that we're going to use it. We need to create a new folder and put our program into a file named example.ml, then we can compile it using the following command

     ocamlbuild -pkg str example.native --
    

    The ocamlbuild tool will infer from the suffix native what is your goal (in this case it is to build a native code application). The -- means run the built application as soon as it is compiled. The above program will print nothing, of course, here is an example of a program that will print some greeting message, before printing the first zero characters of the testing string,

    open Str
    
    let () =
      print_endline "The first 0 chars of 'testing' are:";
      print_endline (Str.first_chars "testing" 0)
    

    and here is how it works

    $ ocamlbuild -package str example.native --
    Finished, 4 targets (4 cached) in 00:00:00.
    The first 0 chars of 'testing' are:
    

    Also, instead of compiling your program and running the resulting application, you can interpret your the example.ml file directly, using the ocaml toplevel tool, which provides an interactive interpreter. You still need to load the str library into the toplevel, as it is not a part of the standard library which is pre-linked in it, here is the correct invocation

    ocaml str.cma example.ml