JanetDocsSign in with Github

loop



    macro
    boot.janet on line 484, column 1

    (loop head & body)
    
    A general purpose loop macro. This macro is similar to the Common Lisp
    loop macro, although intentionally much smaller in scope. The head of
    the loop should be a tuple that contains a sequence of either bindings
    or conditionals. A binding is a sequence of three values that define
    something to loop over. They are formatted like:
    
      binding :verb object/expression
    
    Where binding is a binding as passed to def, :verb is one of a set of
    keywords, and object is any janet expression. The available verbs are:
    
      :iterate - repeatedly evaluate and bind to the expression while it
    is truthy.
      :range - loop over a range. The object should be two element tuple
    with a start and end value, and an optional positive step. The range is
    half open, [start, end).
      :range-to - same as :range, but the range is inclusive [start, end].
      :down - loop over a range, stepping downwards. The object should be
    two element tuple with a start and (exclusive) end value, and an
    optional (positive!) step size.
      :down-to - same :as down, but the range is inclusive [start, end].
      :keys - iterate over the keys in a data structure.
      :pairs - iterate over the keys value pairs as tuples in a data
    structure.
      :in - iterate over the values in a data structure.
      :generate - iterate over values yielded from a fiber. Can be paired
    with the generator function for the producer/consumer pattern.
    
    loop also accepts conditionals to refine the looping further.
    Conditionals are of the form:
    
      :modifier argument
    
    where :modifier is one of a set of keywords, and argument is keyword
    dependent. :modifier can be one of:
    
      :while expression - breaks from the loop if expression is falsey.
      :until expression - breaks from the loop if expression is truthy.
      :let bindings - defines bindings inside the loop as passed to the
    let macro.
      :before form - evaluates a form for a side effect before of the next
    inner loop.
      :after form - same as :before, but the side effect happens after the
    next inner loop.
      :repeat n - repeats the next inner loop n times.
      :when condition - only evaluates the loop body when condition is
    true.
    
    The loop macro always evaluates to nil.


2 examplesSign in to add an example
Loading...
(loop [x :range [1 10]
       :let [square (* x x)]
       :until (> square 9)
       :before (print "before")
       :after (print "after")
       :repeat 2]
  (print (string "square: " square)))

# before
# square: 1
# square: 1
# after
# before
# square: 4
# square: 4
# after
# before
# square: 9
# square: 9
# after

staab
# Suppose you have a fiber that yields chunks of paginated api results:
(def api-results (fiber/new (fn [] (yield [1 2 3]) (yield [4 5 6]))))

# Using :iterate, the right side of the binding is evaluated each time the loop is run,
# which allows for running a side-effecting expression that may be different each time.
(loop [_ :iterate (fiber/can-resume? api-results)] (pp (resume api-results)))

# This example can be simplified using :generate
(loop [chunk :generate api-results] (pp chunk))
staab