In the last section, we had all our files in a “current working
directory”. We called lfec in the same directory that we
created montyhall.lfe in, and it made montyhall.beam in
the same directory. We called lfe in the same directory to run
the compiled program.
While this works for a small example, it will be convenient in
the long run to arrange
our files in a standard directory structure. First, we will
define the environment variable ERL_LIBS to point to an
umbrella directory that will contain, at whatever depth, all our
LFE files. E.g.,
export ERL_LIBS=~/erllib
Now, under $ERL_LIBS, it does not matter at what depth, create
a directory prob to contain all our code pertaining to this
text. In prob create the subdirectories src and
ebin. Put the file montyhall.lfe in prob/src.
cd to prob/src, and type
lfec -o ../ebin montyhall
This will create montyhall.beam in prob/ebin.
You may now call lfe anywhere, and any compiled file that is
in an ebin anywhere under $ERL_LIBS will be directly
visible.
% lfe
Erlang ...
LFE Shell ...
> (: montyhall run)
> 0.6713
I find it useful to have my text editor vim load the following automatically:
set acd
au bufwritepost *.lfe !lfec -o ../ebin %
This will take care to compile any .lfe file you edit to the
appropriate place. You may be able to do something similar with
Emacs.
In montyhall.lfe, the part that runs the game many times can
be extracted out into a different module, say montecarlo.lfe,
because we expect to use it unchanged for many different
problems, not just the Monty Hall game.
(defmodule montecarlo
(export (run 1) (run 2)))
(defun run (experiment num-trials)
(fletrec ((loop (i acc)
(if (=< i num-trials)
(loop (+ i 1) (+ acc (funcall experiment)))
(/ acc num-trials))))
(loop 1 0)))
(defun run (experiment)
(run experiment
;since num-trials not specified, assume
10000))
Note again, the module name matches the basename of the file.
We have defined the function run twice! In LFE, unlike Lisp
or Scheme, we can provide a function definition for the same name
multiple times, as long as they differ in arity (the number of
arguments they accept). When the function is called, it does the
right thing based on the number of arguments supplied.
The 2-ary run takes two arguments, the experiment to be
run, and num-trials, the number of times it needs to be run.
The unary run lacks the num-trials parameter, so it
assumes it to be 10000 before handing the job over to 2-ary run.
The export indicates we make available both the unary and the
2-ary procedures run.
Note also that within the 2-ary run, the argument
experiment when called, requires a funcall. This is
because LFE is a Lisp-2, and any variable containing a function
must be funcalled, otherwise the symbol-function associated
with the variable name would be called.
We also need corresponding changes in montyhall.lfe. We
replace the existing run definition with the following
wrapper to the run in montecarlo.lfe:
(defun run ()
(: montecarlo run (fun game 0)))
(fun game 0)
is how you refer, as a value, to the 0-ary procedure game.
You may also use #’game/0.
If you further wanted to specify the module that this procedure
hails from, use (fun montyhall game 0) or
#’montyhall:game/0.