Iterables

An iterable is an on-demand sequence — the language's one way to talk about a collection of things. There are no arrays of creatures or objects; instead, builtins hand you iterables and you walk them.

An iterable is anything you can walk: a list, or any iterable. A bare string is not iterable — to iterate its words, convert it first with words.

Producers and consumers

A producer gives you an iterable. The collection builtins are producers: creatures / people, objects, inventory, equipment, fighting, words, list, and the filtering select / slice.

A consumer reads an iterable. Some take a block and run it per element — each, select, every, some. Others read it directly — count, first, nth, empty, ismember, choose.

after command (say) {
  each [creatures $self] { <c>
    do "smile $c"
  }
}

creatures produces an iterable over the creatures in the room; each consumes it, running the block once per creature.

Lazy sequences

Iterables can be produced on demand: an element may be computed only when a consumer asks for it. The filtering producers select and slice are especially lazy — they yield each element as it is pulled, never computing the whole result up front. That means [first [select … ]] does only as much work as it takes to find the first match.

after command (say) {
  let nums [list 1 2 3 4 5]
  let evens [select $nums { <n> [eq [% $n 2] 0] }]
  do "say first even is [first $evens]"
}

select builds a deferred iterable of the even numbers; first pulls just enough to report 2.

Iterables are never equal

Two iterables never compare equal with eq — not even an iterable to itself. To compare contents, walk them. To test membership, use ismember.

Strings are not iterable

A string is a single value, not a sequence. Walking its words takes an explicit conversion:

each [words "north east south west"] { <dir>
  do "say I could go $dir."
}

Without words, handing the bare string to each is a run-time type error.

See also