Sample Code

Well, you've already seen some! But here is the full, if minimal, module generated by the LFE rebar3 plugin:

(defmodule my-test-lib
  (export (my-fun 0)))

;;; -----------
;;; library API
;;; -----------

(defun my-fun ()
  'hello-world)

You'll note that the function we define has been exported via the export form in the module definition. The number after the function is the arity of that function (Erlang views functions of the same name but different arity as different functions, and LFE does the same).

In the REPL you will have access to this module and its one function. Try it out:

lfe> (my-test-lib:my-fun)
hello-world

Let's add to this module our new my-sum function from the REPL jam session in the previous section. In another terminal window (or text editor pane) open up the src/my-test-lib.lfe file and past the my-sum function.

When you're done, the entire file should look like this:

(defmodule my-test-lib
  (export (my-fun 0
          (my-sum 2))))

;;; -----------
;;; library API
;;; -----------

(defun my-fun ()
  'hello-world)

(defun my-sum (start stop)
  (let ((my-list (lists:seq start stop)))
    (* 2 (lists:foldl
            (lambda (n acc)
              (+ n acc))
            0 my-list))))

Then come back to the REPL sessions and compile the module with its new addition:

> (c "src/my-test-lib.lfe")
#(module my-test-lib)

And call the module functions:

> (my-test-lib:my-sum 1 6)
42
> (my-test-lib:my-sum 1 60)
3660
>

Here's something a little more involved you may enjoy, from the examples in the LFE source code:

(defun print-result ()
  (receive
    ((tuple pid msg)
      (io:format "Received message: '~s'~n" (list msg))
      (io:format "Sending message to process ~p ...~n" (list pid))
      (! pid (tuple msg))
      (print-result))))

(defun send-message (calling-pid msg)
  (let ((spawned-pid (spawn 'my-test-lib 'print-result ())))
    (! spawned-pid (tuple calling-pid msg))))

That bit of code demonstrates one of Erlang's core features in lovely Lisp syntax: message passing. When loaded into the REPL, that code can demonstrate bidirectional message passing between the LFE shell and a spawned process.

Want to give it a try? Add those two new functions to your module, and don't forget to update the export section, too! (note that one function has an arity of 0 and the other and arity of 2).

When you're done, your project module should look like this:

(defmodule my-test-lib
  (export (my-fun 0)
          (my-sum 2)
          (print-result 0)
          (send-message 2)))

;;; -----------
;;; library API
;;; -----------

(defun my-fun ()
  'hello-world)

(defun my-sum (start stop)
  (let ((my-list (lists:seq start stop)))
    (* 2 (lists:foldl
            (lambda (n acc)
              (+ n acc))
            0 my-list))))

(defun print-result ()
  (receive
    ((tuple pid msg)
      (io:format "Received message: '~s'~n" (list msg))
      (io:format "Sending message to process ~p ...~n" (list pid))
      (! pid (tuple msg))
      (print-result))))

(defun send-message (calling-pid msg)
  (let ((spawned-pid (spawn 'my-test-lib 'print-result ())))
    (! spawned-pid (tuple calling-pid msg))))