JanetDocsPlaygroundI'm feeling luckyGitHub sign in

loop



    macro
    boot.janet on line 528, 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 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 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. lets try 
      putting a loop item on multiple lines.
    * `:when condition` - only evaluates the 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