1# Getting Started with Fennel
2
3A programming language is made up of **syntax** and **semantics**. The
4semantics of Fennel vary only in small ways from Lua (all noted
5below). The syntax of Fennel comes from the lisp family of
6languages. Lisps have syntax which is very uniform and predictable,
7which makes it easier to [write code that operates on code][1] as well as
8[structured editing][2].
9
10If you know Lua and a lisp already, you'll feel right at home in Fennel. Even
11if not, Lua is one of the simplest programming languages in existence, so if
12you've programmed before you should be able to pick it up without too much
13trouble, especially if you've used another dynamic imperative language with
14closures. The [Lua reference manual][3] is a fine place to look for details,
15but Fennel's own [Lua Primer][14] is shorter and covers the highlights.
16
17## OK, so how do you do things?
18
19### Functions and lambdas
20
21Use `fn` to make functions. If you provide an optional name, the
22function will be bound to that name in local scope; otherwise it is
23simply an anonymous value.
24
25> A brief note on naming: identifiers are typically lowercase
26> separated by dashes (aka "kebab-case"). They may contain digits too, but
27> must start with a letter or underscore. You can also use the question mark
28> (typically for functions that return a true or false, ex., `at-max-velocity?`).
29> Underscores (`_`) are often used to name a variable that we don't plan
30> on using.
31
32The argument list is provided in square brackets. The final value is
33returned.
34
35(If you've never used a lisp before, the main thing to note is that
36the function or macro being called goes *inside* the parens, not
37outside.)
38
39```fennel
40(fn print-and-add [a b c]
41  (print a)
42  (+ b c))
43```
44
45Functions can take an optional docstring in the form of a string that
46immediately follows the arglist. Under normal compilation, this
47is removed from the emitted Lua, but in the REPL, or when compiling with
48metadata enabled (`fennel --metadata <tgt-files>`), the docstring and
49function usage can be viewed with the `doc` macro:
50
51*Note: Enabling metadata is only recommended for development purposes.*
52
53```fennel
54(fn print-sep [sep ...]
55  "Prints args as a string, delimited by sep"
56  (print (table.concat [...] sep)))
57,doc print-sep ; -> outputs:
58;; (print-sep sep ...)
59;;   Prints args as a string, delimited by sep
60```
61
62Like other lisps, Fennel uses semicolons for comments.
63
64Functions defined with `fn` are fast; they have no runtime overhead
65compared to Lua. However, they also have no arity checking. (That is,
66calling a function with the wrong number of arguments does not cause
67an error.) For safer code you can use `lambda` which ensures you will
68get at least as many arguments as you define, unless you signify that
69one may be omitted by beginning its name with a `?`:
70
71```fennel
72(lambda print-calculation [x ?y z] (print (- x (* (or ?y 1) z))))
73(print-calculation 5) ; -> error: Missing argument z
74```
75
76Note that the second argument `?y` is allowed to be `nil`, but `z` is not:
77
78```fennel
79(print-calculation 5 nil 3) ; -> 2
80```
81
82Like `fn`, lambdas accept an optional docstring after the arglist.
83
84### Locals and variables
85
86Locals are introduced using `let` with the names and values wrapped in
87a single set of square brackets:
88
89```fennel
90(let [x (+ 89 5.2)
91      f (fn [abc] (print (* 2 abc)))]
92  (f x))
93```
94
95Here `x` is bound to the result of adding 89 and 5.2, while `f` is
96bound to a function that prints twice its argument. These bindings are
97only valid inside the body of the `let` call.
98
99You can also introduce locals with `local`, which is nice when they'll
100be used across the whole file, but in general `let` is preferred because
101it's clearer at a glance where the value is used:
102
103```fennel
104(local tau-approx 6.28318)
105```
106
107Locals set this way cannot be given new values, but you *can*
108introduce new locals that shadow the outer names:
109
110```fennel
111(let [x 19]
112  ;; (set x 88) <- not allowed!
113  (let [x 88]
114    (print (+ x 2))) ; -> 90
115  (print x)) ; -> 19
116```
117
118If you need to change the value of a local, you can use `var` which
119works like `local` except it allows `set` to work on it. There is no
120nested `let`-like equivalent of `var`.
121
122```fennel
123(var x 19)
124(set x (+ x 8))
125(print x) ; -> 27
126```
127
128### Numbers and strings
129
130Of course, all our standard arithmetic operators like `+`, `-`, `*`, and `/`
131work here in prefix form. Note that numbers are double-precision floats in all
132Lua versions prior to 5.3, which optionally introduced integers. On 5.3 and
133up, integer division uses `//` and bitwise operations use `lshift`, `rshift`,
134`bor`, `band`, `bnot` and `xor`. Bitwise operators and integer division will
135not work if the host Lua environment is older than version 5.3.
136
137You may also use underscores to separate sections of long numbers. The
138underscores have no effect on the output.
139
140```fennel
141(let [x (+ 1 99)
142      y (- x 12)
143      z 100_000]
144  (+ z (/ y 10)))
145```
146
147Strings are essentially immutable byte arrays. UTF-8 support is
148provided in the `utf8` table in [Lua 5.3+][15] or from a
149[3rd-party library][4] in earlier versions. Strings are concatenated with `..`:
150
151```fennel
152(.. "hello" " world")
153```
154
155### Tables
156
157In Lua (and thus in Fennel), tables are the only data structure. The
158main syntax for tables uses curly braces with key/value pairs in them:
159
160```fennel
161{"key" value
162 "number" 531
163 "f" (fn [x] (+ x 2))}
164```
165
166You can use `.` to get values out of tables:
167
168```fennel
169(let [tbl (function-which-returns-a-table)
170      key "a certain key"]
171  (. tbl key))
172```
173
174And `tset` to put them in:
175
176```fennel
177(let [tbl {}
178      key1 "a long string"
179      key2 12]
180  (tset tbl key1 "the first value")
181  (tset tbl key2 "the second one")
182  tbl) ; -> {"a long string" "the first value" 12 "the second one"}
183```
184
185Immutable tables are not native to Lua, though it's possible to
186construct immutable tables using metatables with some performance overhead.
187
188### Sequential Tables
189
190Some tables are used to store data that's used sequentially; the keys
191in this case are just numbers starting with 1 and going up. Fennel
192provides alternate syntax for these tables with square brackets:
193
194```fennel
195["abc" "def" "xyz"] ; equivalent to {1 "abc" 2 "def" 3 "xyz"}
196```
197
198Lua's built-in `table.insert` function is meant to be used with sequential
199tables; all values after the inserted value are shifted up by one index:
200If you don't provide an index to `table.insert` it will append to the end
201of the table.
202
203The `table.remove` function works similarly; it takes a table and an index
204(which defaults to the end of the table) and removes the value at that
205index, returning it.
206
207```fennel
208(local ltrs ["a" "b" "c" "d"])
209
210(table.remove ltrs)       ; Removes "d"
211(table.remove ltrs 1)     ; Removes "a"
212(table.insert ltrs "d")   ; Appends "d"
213(table.insert ltrs 1 "a") ; Prepends "a"
214
215(. ltrs 2)                ; -> "b"
216;; ltrs is back to its original value ["a" "b" "c" "d"]
217```
218
219The `length` form returns the length of sequential tables and strings:
220
221```fennel
222(let [tbl ["abc" "def" "xyz"]]
223  (+ (length tbl)
224     (length (. tbl 1)))) ; -> 6
225```
226
227Note that the length of a table with gaps in it is undefined; it can
228return a number corresponding to any of the table's "boundary"
229positions between nil and non-nil values.
230
231Lua's standard library is very small, and thus several functions you
232might expect to be included, such `map`, `reduce`, and `filter` are
233absent. It's recommended to pull in a 3rd-party library like [Lume][5]
234or [luafun][9] for those.
235
236### Iteration
237
238Looping over table elements is done with `each` and an iterator like
239`pairs` (used for general tables) or `ipairs` (for sequential tables):
240
241```fennel
242(each [key value (pairs {"key1" 52 "key2" 99})]
243  (print key value))
244
245(each [index value (ipairs ["abc" "def" "xyz"])]
246  (print index value))
247```
248
249Note that whether a table is sequential or not is not an inherent
250property of the table but depends on which iterator is used with it.
251You can call `ipairs` on any table, and it will only iterate
252over numeric keys starting with 1 until it hits a `nil`.
253
254You can use any [Lua iterator][6] with `each`, but these are the most
255common. Here's an example that walks through [matches in a string][7]:
256
257```fennel
258(var sum 0)
259(each [digits (string.gmatch "244 127 163" "%d+")]
260  (set sum (+ sum (tonumber digits))))
261```
262
263If you want to get a table back, try `icollect` to get a sequential
264table or `collect` to get a key/value one. A body which returns nil
265will cause that to be omitted from the resulting table.
266
267```fennel
268(icollect [_ s (ipairs [:greetings :my :darling])]
269  (if (not= :my s)
270      (s:upper)))
271;; -> ["GREETINGS" "DARLING"]
272
273(collect [_ s (ipairs [:greetings :my :darling])]
274  s (length s))
275;; -> {:darling 7 :greetings 9 :my 2}
276```
277
278A lower-level iteration construct is `for` which iterates numerically from
279the provided start value to the inclusive finish value:
280
281```fennel
282(for [i 1 10]
283  (print i))
284```
285
286You can specify an optional step value; this loop will only print odd
287numbers under ten:
288
289```fennel
290(for [i 1 10 2]
291  (print i))
292```
293
294### Looping
295
296If you need to loop but don't know how many times, you can use `while`:
297
298```fennel
299(while (keep-looping?)
300  (do-something))
301```
302
303### Conditionals
304
305Finally we have conditionals. The `if` form in Fennel can be used the
306same way as in other lisp languages, but it can also be used as `cond`
307for multiple conditions compiling into `elseif` branches:
308
309```fennel
310(let [x (math.random 64)]
311  (if (= 0 (% x 2))
312      "even"
313      (= 0 (% x 9))
314      "multiple of nine"
315      "I dunno, something else"))
316```
317
318With an odd number of arguments, the final clause is interpreted as "else".
319
320Being a lisp, Fennel has no statements, so `if` returns a value as an
321expression. Lua programmers will be glad to know there is no need to
322construct precarious chains of `and`/`or` just to get a value!
323
324The other conditional is `when`, which is used for an arbitrary number
325of side-effects and has no else clause:
326
327```fennel
328(when (currently-raining?)
329  (wear "boots")
330  (deploy-umbrella))
331```
332
333## Back to tables just for a bit
334
335Strings that don't have spaces or reserved characters in them can use
336the `:shorthand` syntax instead, which is often used for table keys:
337
338```fennel
339{:key value :number 531}
340```
341
342If a table has string keys like this, you can pull values out of it
343easily with a dot if the keys are known up front:
344
345```fennel
346(let [tbl {:x 52 :y 91}]
347  (+ tbl.x tbl.y)) ; -> 143
348```
349
350You can also use this syntax with `set`:
351
352```fennel
353(let [tbl {}]
354  (set tbl.one 1)
355  (set tbl.two 2)
356  tbl) ; -> {:one 1 :two 2}
357```
358
359If a table key has the same name as the variable you're setting it to,
360you can omit the key name and use `:` instead:
361
362```fennel
363(let [one 1 two 2
364      tbl {: one : two}]
365  tbl) ; -> {:one 1 :two 2}
366```
367
368Finally, `let` can destructure a table into multiple locals.
369
370There is positional destructuring:
371
372```fennel
373(let [data [1 2 3]
374      [fst snd thrd] data]
375  (print fst snd thrd)) ; -> 1       2       3
376```
377
378And destructuring of tables via key:
379
380```fennel
381(let [pos {:x 23 :y 42}
382      {:x x-pos :y y-pos} pos]
383  (print x-pos y-pos)) ; -> 23      42
384```
385
386As above, if a table key has the same name as the variable you're
387destructuring it to, you can omit the key name and use `:` instead:
388
389```fennel
390(let [pos {:x 23 :y 42}
391      {: x : y} pos]
392  (print x y)) ; -> 23      42
393```
394
395This can nest and mix and match:
396
397```fennel
398(let [f (fn [] ["abc" "def" {:x "xyz" :y "abc"}])
399      [a d {:x x : y}] (f)]
400  (print a d)
401  (print x y))
402```
403
404If the size of the table doesn't match the number of binding locals,
405missing values are filled with `nil` and extra values are discarded.
406Note that unlike many languages, `nil` in Lua actually represents the
407absence of a value, and thus tables cannot contain `nil`. It is an
408error to try to use `nil` as a key, and using `nil` as a value removes
409whatever entry was at that key before.
410
411## Error handling
412
413Errors in Lua have two forms they can take. Functions in Lua can
414return any number of values, and most functions which can fail will
415indicate failure by using two return values: `nil` followed by a
416failure message string. You can interact with this style of function
417in Fennel by destructuring with parens instead of square brackets:
418
419```fennel
420(let [(f msg) (io.open "file" "rb")]
421  ;; when io.open succeeds, f will be a file, but if it fails f will be
422  ;; nil and msg will be the failure string
423  (if f
424      (do (use-file-contents (f.read f "*all"))
425          (f.close f))
426      (print (.. "Could not open file: " msg))))
427```
428
429You can write your own function which returns multiple values with `values`.
430
431```fennel
432(fn use-file [filename]
433  (if (valid-file-name? filename)
434      (open-file filename)
435      (values nil (.. "Invalid filename: " filename))))
436```
437
438**Note**: while errors are the most reason to return multiple values
439from a function, it can be used in other cases as well. This is
440the most complex thing about Lua, and a full discussion is out of
441scope for this tutorial, but it's [covered well elsewhere](https://benaiah.me/posts/everything-you-didnt-want-to-know-about-lua-multivals/).
442
443The problem with this type of error is that it does not compose well;
444the error status must be propagated all the way along the call chain
445from inner to outer. To address this, you can use `error`. This will
446terminate the whole process unless it's within a protected call,
447similar to the way in other languages where throwing an exception will
448stop the program unless it is within a try/catch. You can make a
449protected call with `pcall`:
450
451```fennel
452(let [(ok? val-or-msg) (pcall potentially-disastrous-call filename)]
453  (if ok?
454      (print "Got value" val-or-msg)
455      (print "Could not get value:" val-or-msg)))
456```
457
458The `pcall` invocation there means you are running
459`(potentially-disastrous-call filename)` in protected mode. `pcall` takes
460an arbitrary number of arguments which are passed on to the
461function. You can see that `pcall` returns a boolean (`ok?` here) to
462let you know if the call succeeded or not, and a second value
463(`val-or-msg`) which is the actual value if it succeeded or an error
464message if it didn't.
465
466**Note**: In real-world code it's better to use `match` when handling
467  errors; these snippets are intended as examples to specifically
468  illustrate how multiple values work.
469
470The `assert` function takes a value and an error message; it calls
471`error` if the value is `nil` and returns it otherwise. This can be
472used to turn multiple-value failures into errors (kind of the inverse
473of `pcall` which turns `error`s into multiple-value failures):
474
475```fennel
476(let [f (assert (io.open filename))
477      contents (f.read f "*all")]
478  (f.close f)
479  contents)
480```
481
482In this example because `io.open` returns `nil` and an error message
483upon failure, a failure will trigger an `error` and halt execution.
484
485## Variadic Functions
486
487Fennel supports variadic functions like many languages. The syntax for
488taking a variable number of arguments to a function is the `...` symbol, which
489must be the last parameter to a function. This syntax is inherited from Lua rather
490than Lisp.
491
492The `...` form is not a list or first class value, it expands to multiple values
493inline.  To access individual elements of the vararg, first wrap it in a table
494literal (`[...]`) and index like a normal table, or use the `select` function
495from Lua's core library. Often, the vararg can be passed directly to another
496function such as `print` without needing to bind it to a single table.
497
498```fennel
499(fn print-each [...]
500 (each [i v (ipairs [...])]
501  (print (.. "Argument " i " is " v))))
502
503(print-each :a :b :c)
504```
505
506```fennel
507(fn myprint [prefix ...]
508 (io.write prefix)
509 (io.write (.. (select "#" ...) " arguments given: "))
510 (print ...))
511
512(myprint ":D " :d :e :f)
513```
514
515Varargs are scoped differently than other variables as well - they are only
516accessible to the function in which they are created. This means that the
517following code wil NOT work, as the varargs in the inner function are out of
518scope.
519
520```fennel
521(fn badcode [...]
522 (fn []
523  (print ...)))
524```
525
526You can read [more detailed coverage of some of the problems with `...` and multiple values](https://benaiah.me/posts/everything-you-didnt-want-to-know-about-lua-multivals/)
527here.
528
529## Globals
530
531Globals are set with `global`. Good code doesn't use too many of
532these, but they can be nice for debugging in some contexts. Note that
533unlike most forms, with `global` there is no distinction between
534creating a new global and giving an existing global a new
535value.
536
537```fennel
538(global add (fn [x y] (+ x y)))
539(add 32 12) ; -> 44
540```
541
542Unless you are doing ahead-of-time compilation, Fennel will track all
543known globals and prevent you from referring to unknown globals, which
544prevents a common source of bugs in Lua where typos go undetected.
545
546### Strict global checking
547If you get an error that says `unknown global in strict mode` it means that
548you're trying compile code that uses a global which the Fennel compiler doesn't
549know about. Most of the time, this is due to a coding mistake. However, in some
550cases you may get this error with a legitimate global reference. If this
551happens, it may be due to an inherent limitation of Fennel's strategy. You can
552use `_G.myglobal` to refer to it in a way that works around this check.
553
554Another possible cause for this error is a modified [function environment][16].
555The solution depends on how you're using Fennel:
556* Embedded Fennel can have its searcher modified to ignore certain (or all)
557  globals via the `allowedGlobals` parameter. See the [Lua API][17] page for
558  instructions.
559* Fennel's CLI has the `--globals` parameter, which accepts a comma-separated
560  list of globals to ignore. For example, to disable strict mode for globals
561  x, y, and z:
562  ```shell
563  fennel --globals x,y,z yourfennelscript.fnl
564  ```
565
566## Gotchas
567
568There are a few surprises that might bite seasoned lispers. Most of
569these result necessarily from Fennel's insistence upon imposing zero
570runtime overhead over Lua.
571
572* The arithmetic and comparison operators are not first-class functions.
573  They can behave in surprising ways with multiple-return-valued functions,
574  because the number of arguments to them must be known at compile-time.
575
576* There is no `apply` function; instead use `table.unpack` or `unpack`
577  depending on your Lua version: `(f 1 3 (table.unpack [4 9]))`.
578
579* Tables are compared for identity, not based on the value of their
580  contents, as per [Baker][8].
581
582* Return values in the repl will get pretty-printed, but
583  calling `(print tbl)` will emit output like `table: 0x55a3a8749ef0`.
584  If you don't already have one, it's recommended for debugging to
585  define a printer function which calls `fennel.view` on its argument
586  before printing it: `(local fennel (require :fennel))
587  (global pp (fn [x] (print (fennel.view x))))`
588
589* Lua programmers should note Fennel functions cannot do early returns.
590
591## Other stuff just works
592
593Note that built-in functions in [Lua's standard library][10] like `math.random`
594above can be called with no fuss and no overhead.
595
596This includes features like coroutines, which are usually implemented
597using special syntax in other languages. Coroutines
598[let you express non-blocking operations without callbacks][11].
599
600Tables in Lua may seem a bit limited, but [metatables][12] allow a great deal
601more flexibility. All the features of metatables are accessible from Fennel
602code just the same as they would be from Lua.
603
604## Modules and multiple files
605
606You can use the `require` function to load code from other files.
607
608```fennel
609(let [lume (require :lume)
610      tbl [52 99 412 654]
611      plus (fn [x y] (+ x y))]
612  (lume.map tbl (partial plus 2))) ; -> [54 101 414 656]
613```
614
615Modules in Fennel and Lua are simply tables which contain functions
616and other values.  The last value in a Fennel file will be used as the
617value of the whole module. Technically this can be any value, not just a
618table, but using a table is most common for good reason.
619
620To require a module that's in a subdirectory, take the file name,
621replace the slashes with dots, and remove the extension, then pass
622that to `require`. For instance, a file called `lib/ui/menu.lua` would
623be read when loading the module `lib.ui.menu`.
624
625When you run your program with the `fennel` command, you can call
626`require` to load Fennel or Lua modules. But in other contexts (such
627as compiling to Lua and then using the `lua` command, or in programs
628that embed Lua) it will not know about Fennel modules. You need to add
629an entry to Lua's `package.searchers` (`package.loaders` in Lua 5.1)
630to support it:
631
632```lua
633local fennel = require "fennel"
634table.insert(package.loaders or package.searchers, fennel.searcher)
635local mylib = require("mylib") -- will compile and load code in mylib.fnl
636```
637
638Once you add this, `require` will work on Fennel files just like it
639does with Lua; for instance `(require :mylib.parser)` will look in
640"mylib/parser.fnl" on Fennel's search path (stored in `fennel.path`
641which is distinct from `package.path` used to find Lua modules). The
642path usually includes an entry to let you load things relative to the
643current directory by default.
644
645## Relative require
646
647There are several ways to write a library which uses modules.  One of
648these is to rely on something like LuaRocks, to manage library
649installation and availability of it and its modules.  Another way is
650to use the relative require style for loading nested modules.  With
651relative require, libraries don't depend on the root directory name or
652its location when resolving inner module paths.
653
654For example, here's a small `example` library, which contains an
655`init.fnl` file, and a module at the root directory:
656
657```fennel
658;; file example/init.fnl:
659(local a (require :example.module-a))
660
661{:hello-a a.hello}
662```
663
664Here, the main module requires additional `example.module-a` module,
665which holds the implementation:
666
667```fennel
668;; file example/module-a.fnl
669(fn hello [] (print "hello from a"))
670{:hello hello}
671```
672
673The main issue here is that the path to the library must be exactly
674`example`, e.g. library must be required as `(require :example)` for
675it to work, which can't be enforced on the library user.  For example,
676if the library were moved into `libs` directory of the project to
677avoid cluttering, and required as `(require :libs.example)`, there
678will be a runtime error.  This happens because library itself will try
679to require `:example.module-a` and not `:libs.example.module-a`, which
680is now the correct module path:
681
682    runtime error: module 'example.module-a' not found:
683            no field package.preload['example.module-a']
684            ...
685            no file './example/module-a.lua'
686            ...
687    stack traceback:
688      [C]: in function 'require'
689      ./libs/example/init.fnl:2: in main chunk
690
691LuaRocks addresses this problem by enforcing both the directory name
692and installation path, populating the `LUA_PATH` environment variable
693to make the library available.  This, of course, can be done manually
694by setting `LUA_PATH` per project in the build pipeline, pointing it
695to the right directory.  But this is not very transparent, and when
696requiring a project local library it's better to see the full path,
697that directly maps to the project's file structure, rather than
698looking up where the `LUA_PATH` is modified.
699
700In the Fennel ecosystem we encourage a simpler way of managing project
701dependencies.  Simply dropping a library into your project's tree or
702using git submodule is usually enough, and the require paths should be
703handled by the library itself.
704
705Here's how a relative require path can be specified in the
706`libs/example/init.fnl` to make it name/path agnostic, assuming that
707we've moved our `example` library there:
708
709```fennel
710;; file libs/example/init.fnl:
711(local a (require (.. ... :.module-a)))
712
713{:hello-a a.hello}
714```
715
716Now, it doesn't matter how library is named or where we put it - we
717can require it from anywhere.  It works because when requiring the
718library with `(require :lib.example)`, the first value in `...` will
719hold the `"lib.example"` string.  This string is then concatenated
720with the `".module-a"`, and `require` will properly find and load the
721nested module at runtime under the `"lib.example.module-a"` path.
722It's a Lua feature, and not something Fennel specific, and it will
723work the same when the library is AOT compiled to Lua.
724
725### Compile-time relative include
726
727Since Fennel v0.10.0 this also works at compile-time, when using the
728`include` special or the `--require-as-include` flag, with the
729constraint that the expression can be computed at compile time.  This
730means that the expression must be self-contained, i.e. doesn't refer
731to locals or globals, but embeds all values directly.  In other words,
732the following code will only work at runtime, but not with `include`
733or `--require-as-include` because `current-module` is not known at
734compile time:
735
736```fennel
737(local current-module ...)
738(require (.. current-module :.other-module))
739```
740
741This, on the other hand, will work both at runtime and at compile
742time:
743
744```fennel
745(require (.. ... :.other-module))
746```
747
748The `...` module args are propagated during compilation, so when the
749application, which uses this library is compiled, all library code is
750correctly included into the self-contained Lua file.
751
752Compiling a project, that uses this `example` library with the
753`--require-as-include` will include the following section in the
754resulting Lua code:
755
756```lua
757package.preload["libs.example.module-a"] = package.preload["libs.example.module-a"] or function(...)
758  local function hello()
759    return print("hello from a")
760  end
761  return {hello = hello}
762end
763```
764
765Note that `package.preload` entry contain a fully qualified path
766`"libs.example.module-a"`, which was resolved at compile time.
767
768### Requiring modules from modules other than `init.fnl`
769
770To require a module from a module other than `init` module, we must
771keep the path up to current module, but remove the module name.  For
772example, let's add `greet` module to `libs/example/utils/greet.fnl`,
773and require it from `libs/example/module-a.fnl`:
774
775```fennel
776;; file libs/example/utils/greet.fnl:
777(fn greet [who] (print (.. "hello " who)))
778```
779
780This module can be required as follows:
781
782```fennel
783;; file libs/example/module-a.fnl
784(local greet (require (: ... :gsub "(.*)%.module%-a$" "%1.utils.greet")))
785(fn hello [] (print "hello from a"))
786
787{:hello hello :greet greet}
788```
789
790The resulting module name is constructed via `gsub` call, on the
791module name string.  All other modules need to use a similar way to
792require other modules, with the only difference being their name in
793the pattern.
794
795[1]: https://stopa.io/post/265
796[2]: http://danmidwood.com/content/2014/11/21/animated-paredit.html
797[3]: https://www.lua.org/manual/5.1/
798[4]: https://github.com/Stepets/utf8.lua
799[5]: https://github.com/rxi/lume
800[6]: https://www.lua.org/pil/7.1.html
801[7]: https://www.lua.org/manual/5.1/manual.html#pdf-string.gmatch
802[8]: https://p.hagelb.org/equal-rights-for-functional-objects.html
803[9]: https://luafun.github.io/
804[10]: https://www.lua.org/manual/5.1/manual.html#5
805[11]: http://leafo.net/posts/itchio-and-coroutines.html
806[12]: http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/
807[13]: https://love2d.org
808[14]: https://fennel-lang.org/lua-primer
809[15]: https://www.lua.org/manual/5.3/manual.html#6.5
810[16]: https://www.lua.org/pil/14.3.html
811[17]: https://fennel-lang.org/api
812