JanetDocsI'm feeling luckyGitHub sign in

loop



    macro
    boot.janet on line 539, 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 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 a 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 a 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 key-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 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