1   Introduction

This article discusses the following module that supports functional programming in Lua: luafun -- https://luafun.github.io/index.html

The luafun library enable us to chain functions together, feeding the result of the previous function into the following function. And, they each support lazy evaluation, which means that, when we process items in a collection, the chain of processing for one item completes before the chain of evaluation for the next item starts. In effect, we do not have to wait for all the items in the collection to be processed before completing the chain of evaluation. The examples given below and the order of the messages that they print out makes this clear.

2   luafun -- Lua Functional Library

The latest version of the script discussed below is here: luafun_example.zip

Here is a Lua script that uses several of the features of luafun:

#!/usr/bin/env lua

-- Various tests for module `fun`.
-- Tests for laziness.
-- Test for `fun.chain`, `fun.map`, `fun.enumerate`, `fun.each`,
--   `fun.reduce`, `fun.cycle`, `fun.take`, etc.

M = {}

local fun = require('fun')

function M.test01(count, quiet)
  quiet = quiet == true or false
  local verbose = true
  local a = { 11, 22, 33, 44,  }
  local b = { "aa", "bb", "cc",  }
  local c = fun.range(1, 3)
  local calc_fn = function(x, n)
    local val
    if type(x) == 'number' then
      val = x * n
    elseif type(x) == 'string' then
      val = x .. '|' .. x
      val = 'unknown'
    return val
  local make_map_fun = function(msg, n, func)
    local inner_fn = function(x)
      if not quiet then
        print(msg, x)
      val = calc_fn(x, n)
      return val
    return inner_fn
  local f1 = make_map_fun('(f1) x:', 5)
  local f2 = make_map_fun('(f2) x:', 10)
  local f3 = make_map_fun('(f3) x:', 100)
  local f4 = make_map_fun('(f4) x:', 1000)
  local show = function(i, v)
    if verbose then
      print(string.format('result -- i: %d  v: %s', i, v))
  local acc_fn = function(acc, val)
    if type(val) == 'number' then
      acc = acc + val
    elseif type(val) == 'string' then
      acc = acc + #val
    return acc
  fun.chain(a, b, c)

function M.main()
  quiet = false
  if arg[1] == '-h' or arg[1] == '--help' then
    print('usage: lua test21.lua [-q | --quiet] [n]')
  elseif arg[1] == '-q' or arg[1] == '--quiet' then
    quiet = true
    table.remove(arg, 1)
  local count = 1
  if #arg == 1 then
    count = tonumber(arg[1])
  print('test 08')
  M.test01(count, quiet)

if os.getenv('LUACLI') == nil then
  return M


  • In order to run this script from the command line, use something like this:

    $ LUACLI=1 lua test21.lua 10
    $ LUACLI=1 lua test21.lua --quiet 10

    Using an environment variable (in this case LUACLI) enables us to use this script from either the command line for from within another Lua module.

  • In order to run this test at the Lua interactive prompt, do this:

    >  module = require('test21')
    >  module.test01(20)
    >  module.test01(20, true)
  • We can modify a snippet in the above code so that it accumulates a sum of some of the values that we iterate over. We us fun.reduce (alias fun.foldl) to do the accumulation:

    local sum = fun.chain(a, b, c)
      :reduce(acc_fn, 0)
    print('sum:', sum)

    See functions task1 and task2 in the sample code for functions that do these two tasks.

  • Lazy evaluation -- After running this script, if you inspect that messages that are printed out, you will notice that functions f1, f2, f3, and f4 all complete for the first item in the collection, before processing is begun for the next item. That will enable us to process large collections and to incrementally obtain results for some items in the collection without waiting for all the items in the collection.