> I believe the K implementation Stevan Apter <apter@...> submitted
> earlier is more concise and much more comprehensive (neither feature was a
> goal for me at this time). On the other hand, it required the Joy
> expressions to be quoted (via 'I"'). I may have misunderstood the K code,
> but it seemed that some Joy operations were defined via 'I"' quoted Joy
> expresions, but others were defined via K code directly. I didn't see any
> mixtures, and I don't understand the implementation well enough to hazard a
> guess whether it would be possble to mix the Joy and K code in a definition.
>
hi mark
i think i can answer some of your questions.
the core of my joy interpreter is the set of functions:
E:{:[~4=4:y;(,y),x;7=4:v:. y;v x;6=4:v;(,$y),x;x _f/v]}
X:()E/
Y:()E\
O:Parse.out
I:Parse.in
R:{`0:O r:x E/y;r}
S:{`0:,/O'r:x E\y;*|r}
J:{s:();o:(R;S);while[#r:{`0:"joy>";0:`}[];:["\\"=*r;o|:;s:(*o)[s;I r]]]}
J starts the joy console. while there is input r, let the stack (s) be R
of the stack and the parse of the input. i.e. s:R[s;I r].
R is defined as the stack (x) evaluated (E) over the input (y). a side
effect of R is to print (`0:) the new stack at the console.
E is the evaluator: if the input is not a symbol (~4=4:y) then prepend
it to the stack, else if the evaluation of the input is a function (7=4:
v:. y) then apply it to the stack, else if the evaluated input is null
(6=4:v) then prepend the format of the input to the stack, else the
evaluated input must be a list of some form (i.e. a joy program), so
recursively evaluate it (x _f/v).
X and Y are two ways to recursively evaluate the stack. remember that
in my implementation, the stack is a list s. ()E/s takes any stack and
reduces it to a single evaluated item. ()E\s takes an stack, reduces
it, and returns a list each of whose items is the stack reduction up
to that point. X and Y are designed to be used directly, in k (see
below).
O and I currently point to my quick and dirty joy parser/unparser. but
you can swap in any syntax you like, merely by redefining Parse.out and
Parse.in.
my goal was to be able to implement joy primitives as k functions. for
example, the basic stack functions are:
id:(::) / identity returns the stack
false:{0,x} / put 0 on the stack
true:{1,x} / put 1 on the stack
stack:{(,x),x} / put the enlisted stack on the stack
newstack:{x;()} / return the empty stack
unstack:{x[0],1_ x} / unlist the top of the stack
pop:1_ / drop the top of the stack
dup:{x[,0],x} / prepend the enlisted top of the stack
swap:{@[x;1 0;:;2#x]} / reverse the top 2 in place
rollup:{x[1 2 0],3_ x} / etc.
rolldown:{x[2 0 1],3_ x}
choice:{(x[0 1]x 3),3_ x}
now to your question: i defined e.g. swapd as:
I"[swap]dip"
as the parse of the joy concatenation [swap]dip. the resulting
k list is
(,`swap;`dip)
a two item list, whose first item is a one-item list of the symbol
`swap and whose second item is the symbol `dip. i use I because
it allows k to define joy programs as lists more consisely than
the primitive list notation of k.
a more satisfying implementation of joy would attempt to define as
many of the joy operators as possible this way, i.e. as lists rather
than k functions.
in brief, there are three ways to use the k implementation of joy:
as an interactive interpreter via J[]
as a sublanguage within k, using I, O, and X (or Y):
X I"1 2 +"
,3
Y I"1 2 +"
(()
,1
2 1
,3)
as a set of subfunctions, each of which takes a stack, i.e.,
plus 1 2
,3
hope this helps (a revised version is included below - i still
haven't found the time to complete the implementation)
--
/ joy in k
/ joy <-> k (quick & dirty)
\d Parse
types:{:[4:x;type x;_f'x]}
type:{:[(*x)_in*Ops;Ops[1;Ops[0]?*x];&/x _lin"_.0123456789";.@[x;&x="_";:;"-"];"\""=*x;1_-1_ x;"'"=*x;x 1;`$x]}
parts:{a:ol x;b:"["=*:'a;a[&b],:;a:@[a;&~b;ob];r:(,/a)_dv"";@[r;&"["=*:'r;_f 1_-1_]}
sa:{,/@[x;&uq[x]&x=y;:[;" ",y," "]]}
ol:{(&1(~=)':ls x)_ x}
ob:{1_'(&uq[x]&x=" ")_ x:" ",x}
uq:{~(0<':b)|b:(~=)\(~(!#x)_lin,/0 1+/:x _ss"\\\"")&x="\""}
ls:{~|':~=/+\'uq[" ",x]&/:(" ",x)=/:"[]"}
nl:{@[x;&x _lin"\n\t";:;" "]}
vm:{:[4:x;x,"";1_,/" ",'x]}
in:{types parts(nl vm x)sa/"[]",*Ops}
out:{(1_,/(" ",term@)'|x),"\n"}
term:{:[-3=t:4:x;"\"",x,"\"";1>t;list@_f'x;t=3;"'",x;t=5;_f(+($!x;x[]);`dict);$(Ops[0],,x)Ops[1]?x]}
list:{"[",(1_,/" ",'$x),"]"}
Ops:("&|~+-*/%=<>";`and`or`not`plus`minus`mul`idiv`div`eq`lt`gt)
\d ^
/ eval, console, &c.
E:{:[~4=4:y;(,y),x;7=4:v:. y;v x;6=4:v;(,$y),x;x _f/v]}
X:()E/
Y:()E\
O:Parse.out
I:Parse.in
R:{`0:O r:x E/y;r}
S:{`0:,/O'r:x E\y;*|r}
J:{s:();o:(R;S);while[#r:{`0:"joy>";0:`}[];:["\\"=*r;o|:;s:(*o)[s;I r]]]}
/ utilities
Two:{(,Dot[x;2#y]),2 _ y}
One:{@[y;0;x]}
Dot:{:[-3=4:y;.($x),"[",(1_,/";",'"\"",'y,'"\""),"]";x . y]}
Num:{(_ci;::)[(b~z)&a~y]x[b:Ic z;a:Ic y]}
Ic:{:[3=4:*x;_ic x;x]}
Rel:{x[Ic z;Ic y]}
Each:{y{*(,x)E/y}\:x}
Ary:{((1_ y)E/*y),(x+1)_ y}
App:{(((x#1_ y),\:(x+1)_ y)E/\:*y),(x+1)_ y}
Dip:{(x#1_ y),((1+x)_ y)E/*y}
Type:{:[4=4:x;x;~4:x;();-3=4:x;"";*0#x]}
Leaf:{(&/@:'x)|(@x)|-3=4:x}
/ assignment
is:Two[{.[`$x;();:;y]}]
/ general operators
id:(::)
false:{0,x}
true:{1,x}
stack:{(,x),x}
newstack:{x;()}
unstack:{x[0],1_ x}
pop:1_
dup:{x[,0],x}
swap:{@[x;1 0;:;2#x]}
rollup:{x[1 2 0],3_ x}
rolldown:{x[2 0 1],3_ x}
choice:{(x[0 1]x 3),3_ x}
opcase:Two[{((1_'-1_ x),,*|x)((Type@*:)'-1_ x)?Type@*y}]
swapd:I"[swap]dip"
dupd:I"[dup]dip"
popd:I"[pop]dip"
popop:I"pop pop"
/ i/o
put:{}
get:{}
load:{(1_ x)E/I@0:x[0],".joy"}
/ atomic operators
max:or:Two[Num[|]]
min:and:Two[Num[&]]
not:One[~:]
neg:One[-:]
plus:Two[Num[+]]
minus:Two[Num[-]]
mul:Two[*]
div:Two[{y%x}]
rem:Two[{y!x}]
flr:One[_:]
idiv:I"div flr"
sign:One[{(-x<0)+0<x}]
abs:One[_abs]
pred:One[Num[+;-1]]
succ:One[Num[+;1]]
/ list operators
rand:Two[{y _draw x}]
enum:One[!:]
cut:Two[{y _ x}]
find:Two[{y?x}]
up:One[<:]
down:One[>:]
sub:Two[{y@x}]
upsort:I"up sub"
downsort:I"down sub"
cons:Two[{(,y),x}]
swons:I"swap cons"
first:One[*:]
second:One[{x 1}]
third:One[{x 2}]
last:One[*|:]
rest:One[1_]
of:Two[{x:[1=4:y;y;`$y]}]
at:I"swap of"
drop:Two[_]
take:Two[#]
size:One[#:]
reverse:One[|:]
uncons:{((1_;*:)@\:*x),1_ x}
unswons:I"uncons swap"
flatten:One[,/]
transpose:One[+:]
concat:Two[{y,x}]
swoncat:Two[,]
transpose:One[+:]
dict:One[{..[x;(;0);`$]}]
/ predicates
null:One[{:[@x;x=0;~#x]}]
small:One[{:[@x;x<2;2>#x]}]
gt:Two[Rel[>]]
lt:Two[Rel[<]]
eq:Two[Rel[=]]
le:Two[Rel[~>]]
ge:Two[Rel[~<]]
ne:Two[Rel[~=]]
equal:Two[~]
has:Two[_in]
in:Two[{y _in x}]
hasl:Two[_lin]
lin:Two[{y _lin x}]
/ general combinators
i:{(1_ x)E/*x}
x:{x E/*x}
y:{}
b:{((2_ x)E/x 1)E/*x}
nullary:Ary[0]
unary:Ary[1]
binary:Ary[2]
ternary:Ary[3]
dip:Dip[1]
dipd:Dip[2]
dipdd:Dip[3]
app1:App[1]
app2:App[2]
app3:App[3]
app4:App[4]
cleave:{((2_ x){*x E/y}/:2#x),3_ x}
construct:{}
ifte:{((3_ x)E/x@~~*(3_ x)E/x 2),4_ x}
cond:{c:*x;s:1_ x;while[1<#c;if[*s E/*c;:s E/c 1];c:2_ c]}
whiledo:{s:2_ x;while[*s:s E/x 1;s:s E/*x];s}
primrec:{:[x 2;(x[2],_f[@[x;2;-;1]])E/*x;(3_ x)E/x 1]}
linrec:{:[*(4_ x)E/x 3;(4_ x)E/x 2;(_f(4#x),(4_ x)E/x 1)E/*x]}
tailrec:{:[*(3_ x)E/x 2;(3_ x)E/x 1;_f(3#x),(3_ x)E/*x]}
binrec:{:[*(4_ x)E/x 3;(4_ x)E/x 2;((*_f@)'x{@[x;4;:;y]}/:2#(4_ x)E/x 1)E/*x]} / ?
genrec:{:[*(4_ x)E/x 3;(4_ x)E/x 2;(`genrec,(4#x),(4_ x)E/x 1)E/*x]}
condlinrec:{}
/ atomic combinators
branch:{((3_ x)E/x@~~z),4_ x}
times:{x[0]{y E/x}[x 1]/2_ x}
/ list combinators
infra:{(,x[1]E/*x),2_ x}
step:{{((,z),y)E/x}[*x]/[2_ x;x 1]}
map:{(,(1_'@[x;1;:;]'x 1){*x E/y}\:*x),2_ x}
fold:{(,{*(z;y)E/x}[*x]/[x 1;x 2]),3_ x}
filter:{1_@[x;1;@[;&*map x]]}
split:{((x[1]@&:;x[1]@&~:)@\:*map x),2_ x}
some:{@[map x;0;|/]}
all:{@[map x;0;&/]}
/ tree combinators
treestep:{:[Leaf x 1;step x;(,(*_f@)'x[1]{@[y;1;:;x]}\:x),2_ x]}
treerec:{:[Leaf x 2;(2_ x)E/x 1;((,`treerec,2#x),(2_ x))E/*x]}
treegenrec:{}
/ test routines
unitlist:I"[]cons"
shunt:I"[swons]step"
reverselist1:I"[]swap shunt"
reverselist2:I"[]swap infra"
restlist:I"[null][unitlist][dup rest][cons]linrec"
frontlist:I"[null][unitlist][uncons][[cons]map popd dup first rest swons]linrec"
subseqlist1:I"frontlist[restlist]map"
subseqlist2:I"[null][unitlist][uncons dup[frontlist[cons]map popd]dip][concat]linrec"
powerlist1:I"[null] [[] cons] [uncons][dup swapd [cons] map popd concat] linrec"
powerlist2:I"[null] [[] cons] [uncons][dup swapd [cons] map popd swoncat] linrec"
treesum:I"0 swap[+]treestep"
treesize:I"0 swap[pop succ]treestep"
treeshunt:I"[swons]treestep"
treeflatten:I"[]swap treeshunt reverse"
qsort:I"[small] [] [uncons [>] split] [swapd dip cons concat] binrec"
J[]