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