mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| # An example implementation of functional, lazy
 | |
| # 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)
 | |
| 
 | |
| (defn empty-seq
 | |
|  "The empty sequence."
 | |
|  [] nil)
 | |
| 
 | |
| (defmacro cons
 | |
|  "Create a new sequence by prepending a value to the original sequence."
 | |
|  [h t]
 | |
|  (def x (tuple h t))
 | |
|  (fn [] x))
 | |
| 
 | |
| (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))
 | |
| 
 | |
| (defn range2
 | |
|  "Return a sequence of integers [start, end)."
 | |
|  [start end]
 | |
|  (if (< start end)
 | |
|   (delay (tuple start (range2 (+ 1 start) end)))
 | |
|   empty-seq))
 | |
| 
 | |
| (defn range
 | |
|  "Return a sequence of integers [0, end)."
 | |
|  [end]
 | |
|  (range2 0 end))
 | |
| 
 | |
| (defn map
 | |
|  "Return a sequence that is the result of applying f to each value in s."
 | |
|  [f s]
 | |
|  (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))))
 | |
| 
 | |
| (defn drop
 | |
|  "Ignores the first n values of the sequence and returns the rest."
 | |
|  [n s]
 | |
|  (delay
 | |
|   (def x (s))
 | |
|   (if (and x (pos? n)) ((drop (- n 1) (get x TAIL))))))
 | |
| 
 | |
| (defn take
 | |
|  "Returns at most the first n values of s."
 | |
|  [n s]
 | |
|  (delay
 | |
|   (def x (s))
 | |
|   (if (and x (pos? n))
 | |
|    (tuple (get x HEAD) (take (- n 1) (get x TAIL))))))
 | |
| 
 | |
| (defn randseq
 | |
|  "Return a sequence of random numbers."
 | |
|  []
 | |
|  (delay (tuple (random) (randseq))))
 | |
| 
 | |
| (defn take-while
 | |
|  "Returns a sequence of values until the predicate is false."
 | |
|  [pred s]
 | |
|  (delay
 | |
|   (def x (s))
 | |
|   (when x
 | |
|    (def thehead (get HEAD x))
 | |
|    (if thehead (tuple thehead (take-while pred (get TAIL x)))))))
 | |
| 
 | |
| # Iterators are a concept that looks a lot like lazy seq
 | |
| # The following functions turn iterators to lazy seq and vice versa
 | |
| 
 | |
| (defn- iter-self
 | |
|   [next more]
 | |
|   (delay 
 | |
|    (if (more) (tuple (next) (iter-self next more)))))
 | |
| 
 | |
| (defn iter2lazy
 | |
| "Create a lazy sequence from an iterator"
 | |
|   [iter]
 | |
|   (def {:more more :next next} iter)
 | |
|   (iter-self next more))
 | |
| 
 | |
| (defn lazy2iter
 | |
|   "turn a lazy-seq to an iterator"
 | |
|   [lazy-seq]
 | |
|   (var node lazy-seq)
 | |
|   {:more (fn [] (node))
 | |
|    :next (fn []
 | |
|        (when-let [n (node)]
 | |
|         (:= node (get n 1))
 | |
|         (get n 0)))})
 | |
| 
 | |
| # Now we can use the non-functional filter from boot.dst
 | |
| # to write a filter version that returns a lazy sequence
 | |
| # Be careful when creating lazy sequences from mutable
 | |
| # data structures as their values are references to this
 | |
| # data structures. Same is true for iterators
 | |
| 
 | |
| (defn filter2 [pred coll] (iter2lazy (filter pred coll)))
 | |
| 
 | |
| # be careful with the filter function. First element in (filter pos? arr) is nil
 | |
| # last element is false
 | 
