JanetDocsPlaygroundI'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. Bindings are written in 
    the format:

        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. Each subsequent 
    binding creates a nested loop within the loop created by the 
    previous binding.

    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 or fiber.

    `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 current loop if 
      `expression` is falsey.

    * `:until expression` -- breaks from the current loop if 
      `expression` is truthy.

    * `:let bindings` -- defines bindings inside the current 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 current loop body when 
      `condition` is true.

    The `loop` macro always evaluates to nil.


5 examplesSign in to add an example
Loading...
(loop [i :range [0 12]]
  (print i))

# => 0
# => 1
# => 2
# => 3
# => 4
# => 5
# => 6
# => 7
# => 8
# => 9
# => 10
# => 11
# => nil

jgartePlayground
# :when modifier argument example

(let [even-numbers  @[]]
    (loop [i :range [0 50] :when (even? i)]
        (array/push even-numbers i))
    even-numbers)

# => @[0 2 4 6 8 10 12 14 16 1.....]
leobmPlayground
(do
  (def coll @[])
  (loop [i :down-to [10 1]]
    (array/push coll i))
  coll)
# => @[10 9 8 7 6 5 4 3 2 1]
sogaiuPlayground
(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

staabPlayground
# 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))
staabPlayground