Assignment

The Arc language features a number of assignment functions to update variables and data structures. Arc also includes the concept of a "place", which specifies the position to be updated. Places are also known as "generalized variables", as they can be used as variables in many contexts.

This page describes Arc's basic assignment operators as well as the operators that use places to perform updates.

Assignment primitives

The simplest assignment operator in Arc is (set symbol value). The set form can also be used to set multiple variables in once statement: (set symbol1 value1 symbol2 value2 ...).

A list can be destructively modified with scar or scdr, which update the first element of a list or the remainder of a list, respectively. Note that these operations do not create a new copy of the list; they modify the existing list. The modifications will affect any other symbols referring to the list.

arc> (set m '(1 2 3) n m)
(1 2 3)
arc> (scar m 'a)
a
arc> n
(a 2 3)
arc> (scdr n '(b c))
(b c)
arc> m
(a b c)
Unusual list structures, including cyclic lists, can be created by splicing lists together with scar or scdr. Arc currently hangs if a cyclic list is displayed, so be forewarned.

Places and =

Generallly, assignment in Arc is performed with the = macro. It is similar to set, except it allows assignment not only to a symbol, but also to a "place". Roughly speaking, a place is a location that can be updated. The place can be a symbol, an index into a table, a character in a string, an index into a list, or a complex location in a list. The following examples illustrate how these different places can be updated.
arc> (= mytable (table) mystring "abcde" mylist '((a b) c (d 3)))
((a b) c (d 3))
arc> (= (mytable "key") 42)
42
arc> mytable
#hash(("key" . 42))
arc> (= (mystring 2) #\x)
#\x
arc> mystring
"abxde"
arc> (= (mylist 1) 'z)
z
arc> (= (car (car mylist)) 'y)
y
arc> mylist
((y b) z (d 3))
Because of its convenience, = is the operator used most often for assignment and updates in Arc. It can also be extended to support new types of places; this is considerably more complex, and will be discussed in a later article.

Operations on places

Several other macros allow assignment to places. wipe and assert allow places to be set to nil or t respectively. The name of assert may cause confusion; it is used to set a place, not to assert that something is true.
arc> (= a 1 b 2 c 3)
3
arc> (wipe a b c)
nil
arc> a
nil
arc> (assert a b c)
t
arc> b
t

(swap place1 place2) will swap the values at the two places. The places do not necessarily need to be in the same data structure and do not necessarily need to be lists.

(= x '(a b c d e))
arc>  (swap (car x) (x 3))
arc> x
(d b c a e)
arc> (= s "abc")
arc> (swap (s 0) (s 2))
arc> s
"cba"
(rotate place1 place2 ...) will rotate the places to the left. That is, the value from place2 will go in place1, the value from place3 will go in place2, and so on, and the value from place1 will go in the last place.
arc> (= x '(a b c d e))
arc> (rotate (x 0) (x 2) (x 4))
arc> x
(c b e d a)

Several macros modify the value at a place. Similar to the C operators, ++ and -- will decrement or increment a place. The place is modified by 1 by default, but the amount of increment or decrement can be specified.

arc> (= x '(0 0))
(0 0)
arc> (++ (x 0))
1
arc> (-- (x 1) 10)
-10
arc> x
(1 -10)
More general read-modify-write modifications can be done with (zap op place [args]), which gets the value at a place, applies the operation to the value and optional arguments, and puts the value back at the place.
arc> (let s "abc" (zap upcase (s 0)) s)
"Abc"
arc> (let x '(10 10) (zap mod (car x) 3) x)
(1 10)
arc>  (let tb (table) (= (tb "key") "val") (zap + (tb "key") "stuff") tb)
#hash(("key" . "valstuff"))

Places and lists

Lists can be modified with push, pushnew, pop, and pull. (push obj place) inserts the object before the place. pushnew is similar to push, except the object is pushed only if it is new: if it is not already in the list.
arc> (let x '(a b c d e) (push 'z x) (push 'b x) (push 'w x) x)
(w b z a b c d e)
arc> (let x '(a b c d e) (pushnew 'z x) (pushnew 'b x) (pushnew 'w x) x)
(w z a b c d e)
(pop place) returns the object at the place, and removes that object from the list.
arc> (= x '(a b c d e))
(a b c d e)
arc> (pop x)
a
arc> x
(b c d e)
Elements can be filtered from a list with (pull test place). Objects satisfying test are removed from the list, and the updated list is returned. Note that the values kept and returned are the values that fail the test. For example, to pull the odd elements out of a list:
arc> (= x '(1 2 3 5 8 13))
(1 2 3 5 8 13)
arc> (pull odd x)
(2 8)

Typically the place for these operations indicates a list, but the place doesn't necessarily need to be the beginning of the list. For instance, cdr can be used to access a place inside the list.

arc> (let x '(a b c d e)  (push 'z (cdr (cdr x))) x)
(a b z c d e)
arc> (let x '(a b c d e) (pop (cdr x)))
b

Summary

assign symbol expr
assign is used to assign a value to a variable. Renamed from set in arc3.
>(assign x 10)
10
scar list expr
Assigns an expression to the car of list. If applied to a string, assigns to the first character of the string, which must have length at least one.
>(do
    (= x (copy "abc"))
    (scar x #\d)
    x)
"dbc"
>(do
    (= x '(1 2 3))
    (scar x #\d)
    x)
(#\d 2 3)
scdr list exp
Assigns to cdr of a list.
>(do
    (= x '(1 2 3))
    (scdr x '(4))
    x)
(1 4)
= [place expr] ... [place]
Assigns to each place to the associated expression. If the last place has no associated expression, it is set to nil.
>(= x 1)
1
>(= x 2 y 4)
4
wipe [place ...]
Assigns nil to the places. Typically, the places are simple variables.
>(do (wipe a b c) (list a b c))
(nil nil nil)
set [place ...]
Assigns t to the places. Renamed from assert in arc3.
>(do (set a b c) (list a b c))
(t t t)
swap place1 place2
The contents of the two places are swapped. The new contents of place2 are returned.
>(with (x 'a y '(1 2))
  (swap x y)
  (prn "x:" x)
  y)
x:(1 2)

a
rotate [place1 place2 ...]
Assigns place2 to place1, assigns place3 to place2, and so on, assigning place1 to the last place.
>(let s (copy "abc") (rotate (s 0) (s 1) (s 2)) s)
"bca"
++ place [i]
Increments the value at place by i. The default increment is 1.
>(let x '(10 20) (++ (car x)) (++ (x 1) 5) x)
(11 25)
-- place [i]
Decrements the value at place by i. The default decrement is 1.
>(let x '(10 20) (-- (car x)) (-- (x 1) 5) x)
(9 15)
zap op place [args ...]
Gets the value at the place, evaluates (op value args...), and stores the result in the place.
>(let x '(0 10 20) (zap * (x 1) 5) x)
(0 50 20)
push elt place
Pushes an element at the beginning of the list referenced by place. The list is modified and returned.
>(let x '(1 2 3) (push 'a x) x)
(a 1 2 3)
pushnew elt place [test]
Pushes elt before the place if it is not present in the list. The equality test can be specified; iso is used by default.
>(let x '(1 2 3) (pushnew 'a x) x)
(a 1 2 3)
>(let x '(1 2 3) (pushnew 2 x) x)
(1 2 3)
pop place
The first element is removed from place and returned. If the value at the place is nil, then nil is returned.
>(let x '(1 2 3)
  (prn "Popped:" (pop x))
  x)
Popped:1

(2 3)
pull test place
Remove elements satisfying test from the list starting at place.
>(let x '(1 100 2 50 3) (pull [< _ 10] x) x)
(100 50)

Legend

: Foundation operation.
: Macro.
: Procedure.
: Variable.
: Destructive; arguments may be modified.
: Predicate.
: View code.

Copyright 2008 Ken Shirriff.