Particles

Particle  Object

Ah, particles - an Atomo programmer's best friend. Although their primary purpose is to represent "partial messages" like @sqrt or @(foo: 2 bar: _), their use gracefully extends far beyond that. The fact that they can be pattern-matched makes their use as error values and success indicators very handy.

For example, lookup: uses them to indicate whether it was able to find a given key in a list of Associations. If it finds the association, it returns the associated value wrapped in @ok:. If it doesn't find it, it returns @none. It is the dispatcher's job to decide what they want to do from there.

Example:

> [1 -> $a, 2 -> $b] lookup: 1
@(ok: $a)
> [1 -> $a, 2 -> $b] lookup: 3
@none

Many errors are also encoded as simple "structured error messages" using particles. For example, when indexing a list out of bounds:

> [1, 2, 3] at: 1
2
> [1, 2, 3] at: 3
ERROR: <error @(out-of-bounds: 3 for-list: [1, 2, 3])>

This value can be caught and pattern-matched, with the keywords in the particle clearly explaining the importance and meaning of every value involved:

{ [1, 2, 3] at: 3 } handle: {
  @(out-of-bounds: idx for-list: _) ->
    "out of bounds: " (.. idx show) print
}

And, since they respond to call:, they can be used most places where you would otherwise have a block that takes certain arguments:

> [1, 2, 3] map: { n | n + 2 }
[3, 4, 5]
> [1, 2, 3] map: @(+ 2)
[3, 4, 5]
> [1, 4, 9] map: @sqrt
[1.0, 2.0, 3.0]

In this case, the values fill up the empty slots in the particle (in order), and the "completed" message is dispatched, yielding its result.

There are two kinds of particles: single particles and keyword particles, which reflects the two types of messages.

Single particles are simple names, like @sqrt, or if the target is filled, @(1 sqrt).

Keyword particles may contain more "filled-in" values, such as @(+ 2) or @foo: or even @(1 + 1). Single particles only have one unfilled value; keyword particles can have any number of them, but they are keyword-delimited.

Keyword particles have varying forms of syntax. @+ is equivalent to @(_ + _). @foo:bar: is equivalent to @(_ foo: _ bar: _). @(foo: 2) is equivalent to @(_ foo: 2).

p complete: (... targets)  Message
  | p is-a?: Particle

Complete the particle p by filling it in with values from values, in order. If there are not enough values in the list to complete the particle, @particle-needed:given: is thrown.

Example:

> @sqrt complete: 10
<message 10 sqrt>
> @+ complete: (1, 2)
<message 1 + 2>
> @+ complete: 1
ERROR: <error @(particle-needed: 2 given: 1)>
p call: (... values)  any
  | p is-a?: Particle

Complete the particle p by filling it in with values from values, in order, and dispatch the completed message.

Example:

> @sqrt call: 10
3.1622776601683795
> @+ call: (1, 2)
3
> @+ call: 2
ERROR: <error @(particle-needed: 2 given: 1)>
p name  String
  | p is-a?: Particle

Returns the name of the single particle p.

Example:

> @sqrt name
"sqrt"
p names  String
  | p is-a?: Particle

Returns the names in the keyword particle p.

Example:

> @+ names
["+"]
> @foo:bar: names
["foo", "bar"]
p target  any
  | p is-a?: Particle

Returns the single particle p's target wrapped in @ok:, or none if it does not exist.

Example:

> @foo target
@none
> @(1 sqrt) target
@(ok: 1)
p targets  List
  | p is-a?: Particle

Returns a list of the keyword particle p's targets, indicating the absense of a value with @none and wrapping existing values in @ok:.

Example:

> @+ targets
[@none, @none]
> @(+ 2) targets
[@none, @(ok: 2)]
> @(foo: _ bar: $a) targets
[@none, @none, @(ok: $a)]
> @(1 + 2) targets
[@(ok: 1), @(ok: 2)]
p type  in?: [@single, @keyword]
  | p is-a?: Particle

Yields the type of the keyword - single or keyword.

Example:

> @sqrt type
@single
> @+ type
@keyword
> @foo:bar: type
@keyword