Running ocaml files




















Therefore, useless results must explicitly be thrown away. This can be achieved either by using the ignore primitive or an anonymous binding. The projections are polymorphic but are defined only for a fixed arity. There is no particular syntax for projections, and pattern matching must be used.

The only exceptions are fst and snd for pairs defined in the standard library. In OCaml, records are analogous to variants and must be declared before being used. See for example the type regular used for cards Exercise 2. Mutable fields of records must be declared as such at the definition of the record type they belong to. Arguments passed on the command line are stored in the string array Sys. The standard library Arg provides an interface to extract arguments from the command line.

Assoc module, which provides utility functions for interacting with association lists , i. In particular, we use the function List. Note that List. That accumulator is initialized to the empty list. When an OCaml program is evaluated, all the statements in the implementation files are evaluated in the order in which they were linked together. These implementation files can contain arbitrary expressions, not just function definitions. But really the entire file is evaluated at startup, and so in some sense the full codebase is one big main function.

The let binding here is a pattern-match to a value of type unit , which is there to ensure that the expression on the righthand side returns unit , as is common for functions that operate primarily by side effect. We need a somewhat more complex invocation to get them linked in:.

This uses ocamlfind , a tool which itself invokes other parts of the OCaml toolchain in this case, ocamlopt with the appropriate flags to link in particular libraries and packages.

Here, -package base is asking ocamlfind to link in the Base library; -linkpkg asks ocamlfind to link in the packages as is necessary for building an executable. While this works well enough for a one-file project, more complicated projects require a tool to orchestrate the build.

One good tool for this task is dune. To invoke dune , you need to have a dune file that specifies the details of the build. We can run the resulting executable, freq. The specific invocation below will count the words that come up in the file freq. Conveniently, dune allows us to combine the building and running an executable into a single operation, which we can do using dune exec. OCaml ships with two compilers: the ocamlopt native code compiler and the ocamlc bytecode compiler.

Programs compiled with ocamlc are interpreted by a virtual machine, while programs compiled with ocamlopt are compiled to machine code to be run on a specific operating system and processor architecture.

With dune , targets ending with. Aside from performance, executables generated by the two compilers have nearly identical behavior. There are a few things to be aware of. First, the bytecode compiler can be used on more architectures, and has some tools that are not available for native code. For example, the OCaml debugger only works with bytecode although gdb , the GNU Debugger, works with some limitations on OCaml native-code applications.

The bytecode compiler is also quicker than the native-code compiler. In addition, in order to run a bytecode executable, you typically need to have OCaml installed on the system in question.

As a general matter, production executables should usually be built using the native-code compiler, but it sometimes makes sense to use bytecode for development builds. And, of course, bytecode makes sense when targeting a platform not supported by the native-code compiler.

Source files in OCaml are tied into the module system, with each file compiling down into a module whose name is derived from the name of the file. Assoc module.

At its simplest, you can think of a module as a collection of definitions that are stored within a namespace. Remember that the variable counts contains an association list representing the counts of the lines seen so far. But updating an association list takes time linear in the length of the list, meaning that the time complexity of processing a file is quadratic in the number of distinct lines in the file. We can fix this problem by replacing association lists with a more efficient data structure.

We can consider alternative and more efficient implementations once we have a clear interface to program against. The key function, called touch , bumps the frequency count of a given line by one. The file counter. The module name is capitalized even if the file is not. Indeed, module names are always capitalized. The resulting code can still be built with dune , which will discover dependencies and realize that counter.

The implementation details of a module can be hidden by attaching an interface. Note that in the context of OCaml, the terms interface , signature , and module type are all used interchangeably. A module defined by a file filename. For counter. The syntax of a val declaration is as follows:. Note that dune will detect the presence of the mli file automatically and include it in the build. A type is abstract if its name is exposed in the interface, but its definition is not.

We also used this opportunity to document the module. We started our comments with a double asterisk to cause them to be picked up by the odoc tool when generating API documentation. Now, I will be first to admit that that was a lot of work! Fortunately there are many third-party development tools to make it easy to compile an OCaml program. If you copy this single file into your project directory, then you can easily make a Makefile for your particular project; my ocolumn Makefile is just this:.

Another alternative is to install Nicolas Cannasse's ocamake application and then ocolumn can be compiled with one command:. I highly recommend that you use either OCamlMakefile or ocamake for your projects, rather than working with the compiler directly.

All the steps to generate a native-code executable instead of byte-code are the same; we simply need to use the native-code compiler, ocamlopt , instead of the byte-code compiler ocamlc , and some extensions are different:. Generating and compiling signatures is exactly the same you can use ocamlopt for both, but you don't need to. Compiling an object file is done the same way, but you need to be sure to use ocamlopt to get native-code, and the output file will be named with the.

Linking is done the same way, but again, you need to use ocamlopt and use the. But again, with OCamlMakefile , you can compile to native-code without changing the project Makefile by saying gmake nc nc for native-code and with ocamake , just give the -opt option. It's inherently slower, since you are re-parsing your program and re-compiling it to byte-code every time you invoke it this is the way things always work for many interpreted languages, like Perl and Tcl. To productionize your program, you'll need to write a shell-script wrapper hiding the invocation.

It's awkward for programs that are structured in several separate source files. It's awkward for programs that use libraries that aren't in the OCaml core.

Consider this trivial program that prints each command line argument on a separate line, structured as three one-line source-files or modules : Filename Contents a.



0コメント

  • 1000 / 1000