1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-03 21:39:54 +00:00
janet/examples/lazyseqs.dst

132 lines
3.0 KiB
Plaintext
Raw Normal View History

# An example implementation of functional, lazy
2018-03-18 13:13:21 +00:00
# sequences, as in clojure. The lazy seq is essentially
# A lazy linked list, where the next value is a function
# that must be called (realizing it), and the memoized.
# Use with (import "./path/to/this/file" :prefix "seq.")
(defmacro delay [& forms]
"Lazily evaluate a series of expressions. Returns a function that
returns the result of the last expression. Will only evaluate the
body once, and then memoizes the result."
(def $state (gensym))
(def $loaded (gensym))
(tuple 'do
(tuple 'var $state nil)
(tuple 'var $loaded nil)
(tuple 'fn (array)
(tuple 'if $loaded
$state
(tuple 'do
(tuple ':= $loaded true)
(tuple ':= $state (tuple.prepend forms 'do)))))))
# Use tuples instead of structs to save memory
(def HEAD :private 0)
(def TAIL :private 1)
2018-03-22 08:31:04 +00:00
(defn empty-seq
"The empty sequence."
[] nil)
2018-03-22 08:31:04 +00:00
(defmacro cons
"Create a new sequence by prepending a value to the original sequence."
[h t]
2018-03-18 13:18:53 +00:00
(def x (tuple h t))
(fn [] x))
2018-03-22 08:31:04 +00:00
(defn empty?
"Check if a sequence is empty."
[s]
(not (s)))
(defn head
"Get the next value of the sequence."
[s]
(get (s) HEAD))
(defn tail
"Get the rest of a sequence"
[s]
(get (s) TAIL))
2018-03-22 08:31:04 +00:00
(defn range2
"Return a sequence of integers [start, end)."
[start end]
(if (< start end)
2018-03-18 14:18:41 +00:00
(delay (tuple start (range2 (+ 1 start) end)))
empty-seq))
2018-03-16 17:40:10 +00:00
(defn range
"Return a sequence of integers [0, end)."
[end]
(range2 0 end))
(defn map
2018-03-22 08:31:04 +00:00
"Return a sequence that is the result of applying f to each value in s."
[f s]
2018-03-16 17:40:10 +00:00
(delay
(def x (s))
(if x (tuple (f (get x HEAD)) (map f (get x TAIL))))))
(defn realize
"Force evaluation of a lazy sequence."
[s]
(when (s) (realize (tail s))))
(defn realize-map [f s]
"Evaluate f on each member of the sequence. Forces evaluation."
(when (s) (f (head s)) (realize-map f (tail s))))
2018-03-22 08:31:04 +00:00
(defn drop
"Ignores the first n values of the sequence and returns the rest."
[n s]
2018-03-16 17:40:10 +00:00
(delay
(def x (s))
2018-03-18 14:18:41 +00:00
(if (and x (pos? n)) ((drop (- n 1) (get x TAIL))))))
(defn take
"Returns at most the first n values of s."
[n s]
2018-03-22 08:31:04 +00:00
(delay
2018-03-18 14:18:41 +00:00
(def x (s))
(if (and x (pos? n))
(tuple (get x HEAD) (take (- n 1) (get x TAIL))))))
2018-03-18 13:13:21 +00:00
(defn randseq
"Return a sequence of random numbers."
[]
(delay (tuple (random) (randseq))))
2018-03-16 17:40:10 +00:00
(defn take-while
"Returns a sequence of values until the predicate is false."
[pred s]
2018-03-22 08:31:04 +00:00
(delay
(def x (s))
(when x
(def thehead (get HEAD x))
(if thehead (tuple thehead (take-while pred (get TAIL x)))))))
2018-03-22 08:31:04 +00:00
2018-03-26 00:39:38 +00:00
# Iterators are a concept that looks a lot like lazy seq
# The following functions turn iterators to lazy seq and vice versa
2018-03-22 08:31:04 +00:00
(defn- iter-self
2018-03-26 00:39:38 +00:00
[next more]
(delay
(if (more) (tuple (next) (iter-self next more)))))
2018-03-22 08:31:04 +00:00
(defn iter2lazy
2018-03-26 00:39:38 +00:00
"Create a lazy sequence from an iterator"
2018-03-22 08:31:04 +00:00
[iter]
2018-03-26 00:39:38 +00:00
(def {:more more :next next} iter)
(iter-self next more))
2018-03-22 08:31:04 +00:00
(defn lazy2iter
2018-03-22 09:38:55 +00:00
"turn a lazy-seq to an iterator"
2018-03-22 08:31:04 +00:00
[lazy-seq]
2018-03-26 00:39:38 +00:00
(var node lazy-seq)
{:more (fn [] (node))
:next (fn []
(when-let [n (node)]
(:= node (get n 1))
(get n 0)))})