This is what I like to call the functions that just rearrange things on the stack. (One thing I want to mention is that during a hypothetical compilation phase these "stack chatter" words effectively disappear, because we can map the logical stack locations to registers that remain static for the duration of the computation. This remains to be done but it's "off the shelf" technology.)
clear
¶1 2 3
clear
dup
dupd
¶1 2 3 dup
clear
1 2 3 dupd
clear
enstacken
disenstacken
stack
unstack
¶Replace the stack with a quote of itself.
1 2 3 enstacken
clear
Unpack a list onto the stack.
4 5 6 [3 2 1] unstack
Get the stack on the stack.
1 2 3 stack
clear
Replace the stack with the list on top. The items appear reversed but they are not, is on the top of both the list and the stack.
1 2 3 [4 5 6] disenstacken
pop
popd
popop
¶clear
1 2 3 pop
clear
1 2 3 popd
clear
1 2 3 popop
roll<
rolldown
roll>
rollup
¶The "down" and "up" refer to the movement of two of the top three items (displacing the third.)
clear
1 2 3 roll<
clear
1 2 3 roll>
swap
¶clear
1 2 3 swap
tuck
over
¶clear
1 2 3 tuck
clear
1 2 3 over
unit
quoted
unquoted
¶clear
1 2 3 unit
clear
1 2 3 quoted
clear
1 [2] 3 unquoted
Unquoting evaluates. Be aware.
clear
1 [dup] 3 unquoted
concat
swoncat
shunt
¶clear
[1 2 3] [4 5 6] concat
clear
[1 2 3] [4 5 6] swoncat
clear
[1 2 3] [4 5 6] shunt
cons
swons
uncons
¶clear
1 [2 3] cons
clear
[2 3] 1 swons
clear
[1 2 3] uncons
first
second
third
rest
¶clear
[1 2 3 4] first
clear
[1 2 3 4] second
clear
[1 2 3 4] third
clear
[1 2 3 4] rest
flatten
¶clear
[[1] [2 [3] 4] [5 6]] flatten
getitem
at
of
drop
take
¶at
and getitem
are the same function. of == swap at
clear
[10 11 12 13 14] 2 getitem
clear
[1 2 3 4] 0 at
clear
2 [1 2 3 4] of
clear
[1 2 3 4] 2 drop
clear
[1 2 3 4] 2 take
take
reverses the order.
reverse
could be defines as reverse == dup size take
remove
¶clear
[1 2 3 1 4] 1 remove
reverse
¶clear
[1 2 3 4] reverse
size
¶clear
[1 1 1 1] size
swaack
¶"Swap stack" swap the list on the top of the stack for the stack, and put the old stack on top of the new one. Think of it as a context switch. Niether of the lists/stacks change their order.
clear
1 2 3 [4 5 6] swaack
choice
select
¶clear
23 9 true choice
clear
23 9 false choice
clear
[23 9 7] 1 select
(select
is basically getitem
, should retire it?)
clear
[23 9 7] 0 select
zip
¶clear
[1 2 3] [6 5 4] zip
clear
[1 2 3] [6 5 4] zip [sum] map
+
add
¶clear
23 9 +
-
sub
¶clear
23 9 -
*
mul
¶clear
23 9 *
/
div
¶clear
23 9 /
clear
23 9 div
clear
23 -9 div
%
mod
modulus
rem
remainder
¶clear
23 9 %
neg
¶clear
23 neg -5 neg
clear
2 10 pow
sqr
¶clear
23 sqr
++
succ
--
pred
¶clear
1 ++
clear
1 --
<<
lshift
>>
rshift
¶clear
8 1 <<
clear
8 1 >>
range
range_to_zero
down_to_zero
¶clear
5 range
clear
5 range_to_zero
clear
5 down_to_zero
clear
[5 down_to_zero] run
product
¶clear
[1 2 3 5] product
sum
¶clear
[1 2 3 5] sum
min
¶clear
[1 2 3 5] min
gcd
¶clear
45 30 gcd
?
truthy
¶Get the Boolean value of the item on the top of the stack.
clear
23 bool
clear
[] bool
clear
0 bool
? == dup truthy
clear
23 ?
clear
[] ?
clear
0 ?
&
and
¶clear
true false &
!=
<>
ne
¶clear
23 9 !=
The usual suspects:
<
lt
<=
le
=
eq
>
gt
>=
ge
not
or
help
¶clear
[help] help
run
¶Evaluate a quoted Joy sequence.
clear
[1 2 dup + +] run
app1
app2
app3
¶clear
[app1] help
clear
10 4 [sqr *] app1
clear
10 3 4 [sqr *] app2
clear
[app2] help
clear
10 2 3 4 [sqr *] app3
(Wait... is that... backwards?)
It should be 40 90 160
shouldn't it?
clear
10 2 3 4 [sqr *] 3 [grabN] codi map reverse disenstacken
Ah! See? It needs reverse
in there!
clear
10 2 3 4 5 [sqr *] 4 [grabN] codi map reverse disenstacken
anamorphism
¶Given an initial value, a predicate function [P]
, and a generator function [G]
, the anamorphism
combinator creates a sequence.
n [P] [G] anamorphism
---------------------------
[...]
Example, range
:
range == [0 <=] [1 - dup] anamorphism
J('3 [0 <=] [1 - dup] anamorphism')
branch
¶J('3 4 1 [+] [*] branch')
J('3 4 0 [+] [*] branch')
cleave
¶... x [P] [Q] cleave
From the original Joy docs: "The cleave combinator expects two quotations, and below that an item x
It first executes [P]
, with x
on top, and saves the top result element.
Then it executes [Q]
, again with x
, and saves the top result.
Finally it restores the stack to what it was below x
and pushes the two
results P(X) and Q(X)."
Note that P
and Q
can use items from the stack freely, since the stack (below x
) is restored. cleave
is a kind of parallel primitive, and it would make sense to create a version that uses, e.g. Python threads or something, to actually run P
and Q
concurrently. The current implementation of cleave
is a definition in terms of app2
:
cleave == [i] app2 [popd] dip
J('10 2 [+] [-] cleave')
dip
dipd
dipdd
¶J('1 2 3 4 5 [+] dip')
J('1 2 3 4 5 [+] dipd')
J('1 2 3 4 5 [+] dipdd')
dupdip
¶Expects a quoted program [Q]
on the stack and some item under it, dup
the item and dip
the quoted program under it.
n [Q] dupdip == n Q n
V('23 [++] dupdip *') # N(N + 1)
genrec
primrec
¶J('[genrec] help')
J('3 [1 <=] [] [dup --] [i *] genrec')
i
¶V('1 2 3 [+ +] i')
ifte
¶[predicate] [then] [else] ifte
J('1 2 [1] [+] [*] ifte')
J('1 2 [0] [+] [*] ifte')
infra
¶V('1 2 3 [4 5 6] [* +] infra')
loop
¶J('[loop] help')
V('3 dup [1 - dup] loop')
map
pam
¶J('10 [1 2 3] [*] map')
J('10 5 [[*][/][+][-]] pam')
J('1 2 3 4 5 [+] nullary')
J('1 2 3 4 5 [+] unary')
J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless...
J('1 2 3 4 5 [+] ternary')
step
¶J('[step] help')
V('0 [1 2 3] [+] step')
times
¶V('3 2 1 2 [+] times')
b
¶J('[b] help')
V('1 2 [3] [4] b')
while
¶[predicate] [body] while
J('3 [0 >] [dup --] while')
x
¶J('[x] help')
V('1 [2] [i 3] x') # Kind of a pointless example.
void
¶Implements Laws of Form arithmetic over quote-only datastructures (that is, datastructures that consist soley of containers, without strings or numbers or anything else.)
J('[] void')
J('[[]] void')
J('[[][[]]] void')
J('[[[]][[][]]] void')