View
1
Download
0
Category
Preview:
Citation preview
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibraryEPITA - Practical Programming
03 - From Code To Project
Marwan Burelle
marwan.burelle@lse.epita.frhttp://wiki-prog.infoprepa.epita.fr
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Outline
1 Multi-Files Project And Simple ModulesModulesDependencies And OrderModule Interfaces
2 OCaml Standard Library
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Multi-Files Project And Simple Modules
Multi-Files Project AndSimple Modules
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Building Real Projects
• Putting all your code in one file is stupid• Projects need organization and structures• OCaml provides a sub-language for modules:
• Modules are autonomous entity providing a set ofsymbols and definitions
• OCaml provides the basic file oriented modules• You can also have embedded modules and parametric
modules (functors.)• Modules have interfaces in order to manage visibility.• Modules’ Interface provides an opaque types
mechanism.
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Overview
1 Multi-Files Project And Simple ModulesModulesDependencies And OrderModule Interfaces
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
A Simple Example
smpl_mod.ml(* Module: Smpl_mod *)(* File: smpl_mod.ml *)
(* A type def *)type t = Yes | No
(* Some functions *)let tostr = function| Yes -> "yes"| No -> "no"
let rec fact = function| (0|1) as n -> n| n -> n * fact (n-1)
(* A constant *)let cst = 42
main.ml(* Module: Main *)(* File: main.ml *)open Printflet cst = 0
let main () =beginprintf "%s\n"(Smpl_mod.tostr Smpl_mod.Yes);printf "cst: %d\n" cst;printf "Smpl_mod.cst: %d\n"Smpl_mod.cst;printf "Smpl_mod.fact 5: %d\n"(Smpl_mod.fact 5);exit 0;endlet _ = main ()
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Compiling
Example:
File by file
> ocamlopt -c smpl_mod.ml> ocamlopt -c main.ml> ocamlopt -o main smpl_mod.cmx main.cmx> ./mainyescst: 0Smpl_mod.cst: 42Smpl_mod.fact 5: 120
Using ocamlbuild:
> ocamlbuild main.nativeFinished, 7 targets (0 cached) in 00:00:00.> ./main.native> yes <cst: 0Smpl_mod.cst: 42Smpl_mod.fact 5: 120
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Using A MakefileMakefile
# Some variablesSRC= smpl_mod.ml main.mlCMX= ${SRC:.ml=.cmx}PRG=mainOCAMLOPT=ocamlopt.optOCFLAGS= # options for modules compilingOCLDFLAG= # options for link time# Main targetall: ${PRG}${PRG}: ${CMX}
${OCAMLOPT} -o $@ ${OCLDFLAG} ${CMX}# Automatic targets.SUFFIXES: .ml .cmx.ml.cmx:
${OCAMLOPT} ${OCFLAGS} -c $<# Usefull targetsclean::
rm -f *.cm[iox] *.o *~rm -f ${PRG}
# END
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Modules
• Every .ml file is a module• Module name is built after file name: smpl_mod.ml
defines module Smpl_mod• Every definition inside a module is available using the
dot notation: Smpl_mod.fact• Tag names (record fields or sum types’ label) must
also be prefixed with module name: Smpl_mod.Yes• Names’ restrictions (uniqueness of tag names, symbol
masking . . . ) does not cross module boundaries.
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
More Modules Syntax
aa.ml(* module: Aa *)type t = {a: int;b: int;c: int;
}
module P = Printflet print x =P.printf"{a=%d;b=%d;c=%d;}\n"x.a x.b x.c
bb.ml(* Module: Bb *)
let x = {Aa.a = 0;Aa.b = 0;Aa.c = 0;
}
let y =Aa.({a = 0; b = 0; c = 0;
})
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Overview
1 Multi-Files Project And Simple ModulesModulesDependencies And OrderModule Interfaces
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Modules Organization
• Splitting code into modules requires someorganization.
• When a piece of code use symbols from anothermodule it creates a dependency.
• Dependencies induce constraints on compilationorder.
• A program with circular dependencies won’t nevercompile.
• The way you split your code is important !
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Graph And Dependencies
Data_structure File_format
Algorithm
Main is used by
A possible compilation order could be:
Data_structure File_format Algorithm Main
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Compilation Order
Given the previous example, we should compile our codehas follow:
> ocamlopt -c data_structure.ml> ocamlopt -c file_format.ml> ocamlopt -c algorithm.ml> ocamlopt -c main.ml> ocamlopt -o main data_structure.cmx file_format.cmxalgorithm.cmx main.cmx
Order is important when compiling modules but alsowhen giving .cmx files list !
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
OCaml Link And Execute Schema
• An OCaml program is basically the evaluation of asequence of phrases (most of it being definitions.)
• The old rule is still there: a symbol should definedbefore its first use.
• Unlike most language, link step in OCaml is almost aconcatenation of all modules.
mod1.ml(* Mod1 *)let _ = print_string "Mod1\n"
mod2.ml(* Mod2 *)let _ = print_string "Mod2\n"
mod3.ml(* Mod3 *)let _ = print_string "Mod3\n"
mod4.ml(* Mod4 *)let _ = print_string "Mod4\n"
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
OCaml Link And Execute Schema
Example:
> for f in mod?.ml; doocamlopt -c $fdone> ocamlopt -o v1 mod1.cmx mod2.cmx mod3.cmx mod4.cmx> ocamlopt -o v2 mod4.cmx mod3.cmx mod2.cmx mod1.cmx> ./v1Mod1Mod2Mod3Mod4> ./v2Mod4Mod3Mod2Mod1
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Good Pratices When Splitting Code
• Each data structure must belongs to its own module.• All operations attached to a data structure must be in
the module defining it.• Each algorithm should have its own module.• Functions and definitions used by only one algorithm
should reside in the module defining it.• When splitting your project you must think of:
• Nature of your data• How information will flow in your program• How modules will talk together
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Breaking Circular Dependencies ?
• Re-check previous rules: beware of orphan functions• Can you split of your module ? Yes ? Do it !• Build toolboxes: debugging facilities, pretty-printers,
file manipulation functions . . .• When all have failed, use refactoring and genericity:
• Polymorphic data structures can help to separate adata structures and its specific usages.
• First order functions can be used to loose the couplingbetween data operations and specific usages.
• Polymorphic parametric classes and functors can alsohelp.
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Overview
1 Multi-Files Project And Simple ModulesModulesDependencies And OrderModule Interfaces
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Interfaces ?
• It can be convenient to hide inner details of a module.• Some data structures are stable only if proper
operations are used on it.1
We can use interfaces for that !
• Interfaces, let you decide which symbols are exportedor not.
• Interfaces, let you define opaque types.• Interfaces can be used to define several
implementations for one API.
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
A Simple Interface
arith.ml(* Module: Arith *)(* Implementation *)
let rec aux_fact a = function| 0 | 1 -> a| n -> aux_fact (a*n) (n-1)let fact n =if n < 0 then assert falseelse aux_fact 1 n
let rec aux_pow a = function| 1 -> a| n -> (aux_pow (a*a) (n/2))* if n mod 2=0 then 1 else alet power a = function| 0 -> 1| b when b<0 -> assert false| b -> aux_pow a b
arith.mli(* Module: Arith *)(* Interface *)(* Only fact and powerare visible. *)
val fact: int -> int(* fact n : returns thefactorial of n, raiseassertion failure ifn is negative.
*)
val power: int -> int -> int(* power a b returnsa powers b, raiseassertion failure ifb is negative.
*)
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Using Modules With Interface
main.mllet main () =begin(* Working *)Printf.printf "fact 5 = %d\n" (Arith.fact 5);(* aux_fact doesn’t exit here *)Printf.printf "fact 5 = %d\n"(Arith.aux_fact 1 5);
exit 0;endlet _ = main ()
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Compiling With Interfaces
Example:> lsmymod.ml mymod.mli> ocamlopt -c mymod.mlFile "mymod.ml", line 1, characters 0-1:Error: Could not find the .cmi file for interface mymod.mli.> ocamlopt -c mymod.mli> ocamlopt -c mymod.ml
ocamlopt -c file.mli produces a compiled interface filefile.cmi
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Interfaces, Dependencies And Order
• When compiling modules, dependencies only appliedto compiled interfaces.
• When linking (program production) you need objectcode (.cmx file) for each module.
• Take the following example:• we got three modules forming a dependency string:A→ B→ Main.
• If all modules have interface we can compile theprogram that way:> ocamlopt -c a.mli> ocamlopt -c b.mli> ocamlopt -c main.mli> ocamlopt -c main.ml> ocamlopt -c b.ml> ocamlopt -c a.ml> ocamlopt -o main a.cmx b.cmx main.cmx
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Generating Interfaces
> cat mylist.mllet rec len = function| [] -> 0| _::t -> 1 + len t
let rec iter f = function| [] -> ()| h::t -> f h; iter f t
> ocamlopt -i mylist.mlval len : ’a list -> intval iter : (’a -> ’b) -> ’a list -> unit> ocamlopt -i mylist.ml > mylist.mli
Modules
Marwan Burelle
Multi-FilesModules
Dependencies And Order
Module Interfaces
OCaml StandardLibrary
Interfaces And Project Organization
• An interface describe how someone will use a module• Interfaces are the place for:
• API description• Types and operation specifications• Module documentations.
• You can have modules without comments, but notinterfaces.
• A good project organization should be:1 Analyze and divide your project2 Write interfaces3 Distribute jobs among programmers4 Test and integrate modules.
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
OCaml Standard Library
OCaml Standard Library
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Don’t rewrite code !
• Just like most modern programming languages,OCaml provides a Standard Library.
• This library contains usual tools: I/O, stringsmanipulations, formatted output, containers . . .
• Most data structures you may need are probablyavailable in a stable and efficient form.
• Like any good programmer, when you need adata-structure or a tools, the first thing you must do is:take a look at the standard library.
• The library is organized in modules.
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Pervasivesmodule
• Implicitely opens• Contains all basic functions (simple I/O, arithmetic,
types conversions . . . )• Even if the module is implicitely open, you can use
the dot notation (Pervasives.abs for example) toavoid conflicts.
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
List, Stack and Queue
• These modules provide implementation for thesethree classic data structures.
• While List is pure functional, Stack and Queue areimperative and provides in-place operations.
Most used functions:
List Stack QueueList.map Stack.create Queue.createList.iter Stack.push Queue.push
List.fold_left Stack.pop Queue.takeList.assoc Stack.is_empty Queue.is_empty
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
List, Stack and Queue
lsq.mllet l = [1;2;3;4;5;]let main () =let s = Stack.create () and q = Queue.create () inbeginList.iter (fun x -> Stack.push x s) l;while not (Stack.is_empty s) doQueue.push (Stack.pop s) q
done;Printf.printf "[";while not (Queue.is_empty q) doPrintf.printf "%d;" (Queue.take q);
done;Printf.printf "]\n";
endlet _ = main ()
> ocamlbuild lsq.nativeFinished, 4 targets (0 cached) in 00:00:00.> ./lsq.native[5;4;3;2;1;]
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Hashtbl
• Hash table are simplest kind of map (associativetables.)
• They are very efficient for searching (amortizedconstant time.)
• They’re less usefull when mapping is too dynamic.• The Hashtblmodule provides an imperative
implementation of auto-resizable hash table using ageneric hash function.
Using Hashtbllet ops =let h = Hashtbl.create 13 inList.iter (fun (k,v) -> Hashtbl.add h k v) [("+", (+));("-", (-));("*", ( * ));("/", (/));
]; hlet eval_op op v1 v2 =(Hashtbl.find ops op) v1 v2
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Set and Map
• Set provides set of values (without duplicate.)• Map provides another kind (functionnal.)• Both use a functor: a function from modules to
modules.• Functors require an input module respecting an
interface, both Set and Map have the same kind ofinput:
OrderedType(* More on module type later ... *)module type OrderedType =sigtype tval compare : t -> t -> int
end
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Using Settestset
module StrSet = Set.Make(String)
let wset = List.fold_left (fun s w -> StrSet.add w s)StrSet.empty [ "hello";"code";"work";"code";"effort" ]
module Int =structtype t = intlet compare = Pervasives.compare
endmodule IntSet = Set.Make(Int)
let iset = List.fold_left (fun s w -> IntSet.add w s)IntSet.empty [ 42; 5; 6; 2; 42; 36; ]
let main () =StrSet.iter (Printf.printf "%S\n") wset;IntSet.iter (Printf.printf "%d\n") iset;exit 0
let _ = main ()
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Using Set
> ocamlbuild testset.nativeFinished, 4 targets (0 cached) in 00:00:01.> ./testset.native"code""effort""hello""work"2563642
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Using Map
Operators with Mapmodule StrMap = Map.Make(String)
let ops =List.fold_left(fun s (k,v) -> StrMap.add k v s)[("+", (+)); ("-", (-));("*", ( * )); ("/", (/));
]
let eval_op op v1 v2 =(StrMap.find op ops) v1 v2
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Managing Command Line: Args
usingarg.mllet switch = ref falselet num = ref 0
let num_fun i = Printf.printf "Called num_fun %d\n" ilet annon s = Printf.printf "Called with: %S\n" slet usage = Sys.argv.(0) ^ " <option>: module Arg demo."
let spec = Arg.align [("-switch", Arg.Set switch, " set the switch on");("-num", Arg.Set_int num, " fix num value (default 0)");("-num_fun", Arg.Int num_fun, " call num_fun");
]
let main () =Arg.parse spec annon usage;if !switch then Printf.printf "Switch is on\n";Printf.printf "num value is: %d\n" !num
let _ = main ()
Modules
Marwan Burelle
Multi-Files
OCaml StandardLibrary
Managing Command Line: Args
> ./usingarg.native --help./usingarg.native <option>: demo for module Arg.-switch set the switch on-num fix num value (default 0)-num_fun call num_fun-help Display this list of options--help Display this list of options
> ./usingarg.native -switch -num 42 -num_fun 1 annon paramCalled num_fun 1Called with: "annon"Called with: "param"Switch is onnum value is: 42> ./usingarg.native -num_fun 1 -num_fun 2Called num_fun 1Called num_fun 2num value is: 0
Recommended