lazy-seq
lazy-seq copied to clipboard
Lazy sequences for Fennel and Lua (mirror)
lazy-seq
Lazy sequences for Lua runtime, and functions to operate on those.
Installation
Clone this library to your project:
git clone https://gitlab.com/andreyorst/lazy-seq.git
Requires Fennel 1.1.0 or higher.
Rationale
Iterators in Lua can be considered lazy, however these are not really a data type. You shouldn't pass iterators around, as these can be stateful. Lazy sequences solve this problem by being immutable.
Design
A lazy sequence is implemented in terms of closures, and works similarly to the linked list. Each element of a sequence is a cons cell, and there are three cons cell types:
-
cons
- an ordinary cons cell, containing a value, and the next cons cell, -
empty-cons
- an empty cons cell, which containsnil
as a value, and itself as the next cons cell, -
lazy-cons
- a lazy variant of a cons cell, which will not get realized until accessed.
This library provides a set of functions for creating and manipulating (lazy) sequences.
For example, consider map
function:
(local lazy (require :lazy-seq))
(lazy.map print [1 2 3])
;; prints: 1, 2, 3 on separate lines
;; returns: @seq(nil nil nil)
Each element of the vector [1 2 3]
was printed and we got back a sequence of results: @seq(nil nil nil)
.
However, if the result of lazy.map
call is put into the variable, there are no prints happening until this variable is realized:
(local {: map : first : doall} (require :lazy-seq))
(local s (map print [1 2 3]))
(first s)
;; only prints 1, returns nil
(doall s)
;; only prints 2, 3, and returns @seq(nil nil nil)
Sequences can be constructed with the seq
function, which accepts tables and strings, and via the lazy-seq
macro to produce a lazy variant:
(local {: seq} (require :lazy-seq))
(import-macros {: lazy-seq} :lazy-seq)
(seq [1 2 3 4 5])
;; @seq(1 2 3 4 5)
(seq {:a 1 :b 2 :c 3})
;; @seq([:b 2] [:c 3] [:a 1])
(seq "foobar")
;; @sseq("f" "o" "o" "b" "a" "r")
(lazy-seq (do (print "I'm lazy!") [1 2 3 4 5]))
;; prints "I'm lazy!" upon access
;; @seq(1 2 3 4 5)
Lazy sequences can be self-referencing:
(local bc (require :bc)) ; lbc library for arbitrary precision math
(tset (getmetatable (bc.new 1)) :__fennelview tostring) ; render arbitrary precision numbers
(local {: map : rest : take : drop} (require :lazy-seq))
(import-macros {: lazy-cat} :lazy-seq)
(global fib (lazy-cat [(bc.new 0) (bc.new 1)] (map #(+ $1 $2) (rest fib) fib)))
(take 20 fib)
;; @seq(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
fib
here is an infinite sequence of Fibonacci numbers.
Documentation
The documentation is auto-generated with Fenneldoc and can be found here.
Contributing
Please do. You can report issues or feature request at project's GitLab repository. Consider reading contribution guidelines beforehand.