LING 4424: Getting Started

By now, you should be able to invoke ocaml and run code interactively. If you want to install OCaml on your own computer, follow the instructions here.

Invoking Caml

To review, you can start the OCaml "interpreter" (or toplevel) by running the ocaml command in the Linux shell. Simply type ocaml at the prompt and then press return.

$ ocaml

In the above example, the dollar sign ($) simply represents the command prompt. You do not need to type this. It indicates that the system is ready to accept your command.

When you run the OCaml interpreter, you will enter an interactive mode similar to the Linux terminal. If everything is set up correclty, you should see something like the following:

OCaml version 4.04.0

Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

/usr/local/lib/ocaml/dynlink.cma: loaded
/usr/local/lib/ocaml/camlp4: added to search path
/usr/local/lib/ocaml/camlp4/camlp4o.cma: loaded
/usr/local/lib/ocaml/unix.cma: loaded
/usr/local/lib/ocaml/nums.cma: loaded
/usr/local/lib/ocaml/site-lib/num-top: added to search path
/usr/local/lib/ocaml/site-lib/num-top/num_top.cma: loaded
	Camlp4 Parsing version 4.04.0

/usr/local/lib/ocaml/site-lib/num: added to search path
/usr/local/lib/ocaml/bigarray.cma: loaded
/usr/local/lib/ocaml/str.cma: loaded
/usr/local/lib/ocaml/site-lib/bytes: added to search path
/usr/local/lib/ocaml/site-lib/batteries: added to search path
/usr/local/lib/ocaml/site-lib/batteries/batteries.cma: loaded
/usr/local/lib/ocaml/site-lib/batteries/batteriesConfig.cmo: loaded
/usr/local/lib/ocaml/site-lib/batteries/batteriesHelp.cmo: loaded
/usr/local/lib/ocaml/site-lib/batteries/batteriesPrint.cmo: loaded
/usr/local/lib/ocaml/site-lib/pa_comprehension: added to search path
/usr/local/lib/ocaml/site-lib/pa_comprehension/pa_comprehension.cma: loaded

So long as you get the pound sign (#) at the end, you should be good to go for now. The rest is information about packages installed for this course that we will be using later.

Again, the pound sign (#) simply indicates that the system is ready for your command. Here, however, you will enter OCaml commands rather than Linux commands. For example, you can enter 3 + 3;; and then hit return to evaluate the mathematical expression 3 + 3.

# 3 + 3;;
- : int = 6

When you hit return, you the toplevel gives you some information about the expression it just evaluated. In this case, it gives you a hyphen, a colon, the word "int", an equal sign, and the number six. What does this mean? In general, the toplevel's response is of the form <status> : <type> = <value>. The status is simply an indication of whether the expression was valid or not. The hyphen indicates that we're good to go. The type of an expression is a fixed category to which the expression belongs. In this case, it's an integer. The value is what we're really looking for - the expression you entered is equivalent to (evaluates to) the integer 6.

If we enter something invalid, we get an error or an exception. For example, try evaluating the expression 7 / 0.

# 7 / 0;;
Exception: Division_by_zero.

In OCaml, an exception is different from an error. An exception indicates an anomalous condition in the values that you entered. Exceptions, unlike errors, can be handled (that is, they are not necessarily fatal). They generally relate to issues caused by specific values. In this case, the problem was that you used 0 - and 0 is the only value that would produce this exception.

An error is slightly different, and probably more common in OCaml. Errors are compilation or type-checking errors. Let's try out a few pieces of problematic code.

# (6 + 3;;
Error:Parse error: ";" or ":" or ":>" or ")" expected after [expr] (in [expr])
# 5 + 'a';;
Error: This expression has type char but an expression was expected of type 

An error, as you may have guessed, is something which is more fundamentally wrong with your program. Errors relate to generalities - things that are problems no matter what the specific values are. In the first example, the problem is a syntax error - OCaml has no idea how to read what you just told it to evaluate. In the second example, the problem is a type error. The problem is that you can never add a character to an integer, no matter what the value of the integer or the character is.

Related to this is the notion that OCaml is strictly typed. Nothing really changes its type over the course of a program, and everything has exactly one type. Thus, 3 is always an integer, 'a' is always a character, and so on. This will be more important when we talk about functions and names.

To exit the OCaml toplevel, enter #quit (this time, you do have to type the pound sign) or CTRL-D.

Basic Unix

Basic Unix Commands
Command Description
ls Show files in folders in current working directory
pwd Print the current working directory
cd Change your current directory
mkdir Create a new directory
rm Permanently delete a file
rm -r Permanently delete a directory and everything in it
cp Copy a file
mv Move a file or directory

The OCaml toplevel is quite useful for quick, interactive experiments. You may want to know something's type or evaluate a simple expression. But you can't save your work in the toplevel - once you quit, the program is gone. As such, we usually work with files.

In the Linux shell, you are really working in a filesystem. The command pwd (for "print working directory") will show you your current "location" within that filesystem. Many of the commands that you run in the command line are run with respect to your current working directory. For example, you can view the contents of your current directory using the command ls.

# pwd
# ls
code  example.txt

To move around in this system, rather than clicking on folder icons like you might with a graphical interface, you issue commands to change the directory. This is done with the cd (change directory) command.

For example, I might want to go into my code directory. To do this, enter cd code at the terminal. Now, if I type pwd, the result will be /home/jacob/code

# cd code
# pwd

cd also assumed that you wanted to enter a directory from your current working directory. The code directory, in this example, was located directly inside my current directory. You can go deeper all at once by using relative paths. For example, if there is a directory inside of code called ocaml, then I could have entered cd code/ocaml. These can be used to formulate "addresses" for directories or files. There are also absolute paths which alaways begin with a forward slash (/), indicating the "root" directory.

If I wanted to get back to my home directory (/home/jacob), then I could enter cd /home/jacob - that would work fine. There's a shortcut to going up a directory though, which is the .. directory. This pair of dots indicates the parent directory of wherever the dots are seen. A single dot (.) indicates the current directory.

# cd code
# pwd
# cd ..
# pwd

You may want to make a new directory for your work in this course. This can be done using the mkdir (make directory) command. Again, you can use either relative or absolute paths, but this time the last name in the path will be the name of the directory that your create.

# pwd
# mkdir ling4424
# ls
code ling4424 example.txt
# mkdir ling4424/gettingstarted
# ls ling4424

You can also copy files and directories. This is done using the cp command. Again, you can use relative or absolute paths, but this command takes two arguments: the location of the file you want to copy, and the location you want to copy it to. For example, let's say I want to copy code/ocaml/ to my current working directory.

# pwd
# ls code/ocaml
# cp code/ocaml/
# ls

The cp command provides a shortcut for keeping the original name of the file, so I don't have to type out both times. In the target location, I can use . as a stand-in for the original filename.

# pwd
# ls code/ocaml
# cp code/ocaml/ .
# ls

To copy a directory, use cp -r instead.

There are a lot of other commands in Unix, but this should be a reasonable starting spot. If you come across a new command, you can use the man (manual) command to learn more about it (for example, enter man man now).

Opening Files

To actually open and edit a file, you need a text editor. In this course, we recommend using Emacs (more information here). Invoke Emacs using emacs -nw where is the path to the file you want to open (Emacs will create it if it doesn't exist).

Once you've opened a file, you can enter OCaml code and save the file (C-x C-s) for later. Let's write a simple program to show how this works.
3 + 3

To send code to the toplevel, select the region that you want to send and then enter C-c C-r. The code will be evaluated as if you had typed it into the toplevel. To start setting a region, type C-space. The cursor then becomes the end of your region.

More Basic OCaml

Almost everything in OCaml is an expression which can be evaluated. This includes if expressions, which have the syntax if <bool> then <consequent> else <alternative>. Note that the consequent and the alternative must have the same type, because in OCaml, every expression has only a single type.

# if 6 > 3 then "hello" else "goodbye";;
- : string = "hello"
# if 6 > 3 then "yes" else 'n';;
Error: This expression has type char but an expression was expected of type

This becomes useful when handling identifiers in OCaml. It is possible to assign a value to a name in OCaml using let expressions. Just like every other expression, let expressions have a value. The syntax of a let expression is let <name> = <expression> in <expression>. The value of a let expression is the value of the expression after the in keyword, with all instances of <name> replaced with the expression after the equal sign.

# let x = if 6 then "hello" else "goodbye" in x;;
- : string = "hello"

This kind of expression can also be used to define functions. With let expressions defined in the toplevel (or defined outside outside of any other expression), it is not necessary to include in. The identifier will be bound globally in the current file.

# let greeting time = 
    if time < 12 then "good morning"
    else if time < 18 then "good afternoon
    else "good evening";;
val greeting : int -> string = <fun>
# let current_time = 8;;
val current_time : int = 8
# greeting current_time;;
- : string = "good morning"

It should be clear how the above function works. The function takes as input a time (an integer using the 24-hour system) and returns either "good morning", "good afternoon" or "good evening", depending on the time entered.