On this page:
sequence
sequence
sequence
8.12
7.13.4 Sequence Macros🔗ℹ

class clause

sequence 'pattern':

  body

  ...

 

interface clause

sequence 'pattern':

  body

  ...

 

veneer clause

sequence 'pattern':

  body

  ...

Forms for class, interface, or veneer to supply an optimizing conversion in an each clause of for. The conversion applies whenever the right-hand side of each has static information for the class or interface containing the sequence declaration. Normally, sequence should be used in a class that implements Sequenceable as the non-optimizing implementation.

The input pattern is matched to each_id ...: each_expr where each_expr is a parsed expression for the right-hand side of each, and the number of each_ids reflects the number of expected result values. The result of the body sequence must be either #false, in which case the implementation falls back to dynamic mode, or a syntax object of the form

'(~outer_binds:

    outer_bind: outer_body; ... // `=` allowed instead of `:`

    ...,

  ~outer_check:

    outer_check_body

    ...,

  ~recur_binds:

    recur_id = recur_init_expr

    ...,

  ~head_guard:

    head_guard_body

    ...,

  ~inner_binds:

    inner_bind: inner_body; ... // `=` allowed instead of `:`

    ...,

  ~pre_guard:

    pre_guard_body

    ...,

  ~post_guard:

    post_guard_body

    ...,

  ~recur_args:

    (recur_arg_expr, ...))'

The keywords in this shape must appear in the shown order, but each is optional and defaults to either an empty binding sequence or a body sequence that produces #true.

These pieces are integrated into a larger expression of roughly the following form, where loop_body is an iteration body, and done_expr is the reducer-generated result.

// bind and/or unpack the sequence

def outer_bind: outer_body; ...

...

// maybe check that sequence is valid

block:

  outer_check_body

  ...

// bind loop arguments, especially as the iteration position

let recur_id = recur_init_expr

...

fun loop(recur_id = recur_id, ...):

  if (block: head_guard_body; ...) // check continues at this position

  | def inner_bind: inner_body; ... // bind variables for element

    ...

    if (block: pre_guard_body; ...) // check continues for this element

    | loop_body

      ...

      if (block: post_guard_body; ...) // check continues *after* this

      | loop(recur_arg_expr, ...) // update the position for next iteration

      | done_expr

    | done_expr

  | done_expr

loop()

Typically, the inner_binds include the the each_ids supplied to the match for pattern, so they can be referenced in loop_body. However, the each_ids are not the same as the identifiers used in the triggerring each form. Static information for identifier bounds by each comes from statinfo_meta.index_result_key static information for the enclosing class or interface.

class Posn(x :: Int, y :: Int):

  implements Sequenceable

  override method to_sequence():

    Sequence.make(

      ~initial_position: 0,

      ~continue_at_position: fun (i): i < 2,

      ~position_to_next: fun (i): i + 1,

      ~position_to_element: fun (i): if i == 0 | y | x

    )

  sequence '$lhs: $rhs':

    '(~outer_binds:

        p = $rhs,

      ~recur_binds:

        pos = 0,

      ~head_guard:

        pos < 2,

      ~inner_binds:

        $lhs = if pos == 0 | Posn.y(p) | Posn.x(p),

      ~recur_args:

        (pos + 1))'

  static_info:

    '(($statinfo_meta.index_result_key,

       $(annot_meta.parse_to_packed_statinfo('Int'))))'

> for List (j: dynamic(Posn(1, 2))): j // uses `to_sequence`

[2, 1]

> for List (j: Posn(1, 2)): j // uses `sequence` expansion

[2, 1]