Another imperative example in Joy

Nick Forde — 2002-03-26 17:14:50

Inspired by the examples in "Imperative thinking for Joy programs"
(http://www.latrobe.edu.au/www/philosophy/phimvt/joy/jp-imper.html)
and wishing to get more familiar with the language I translated the
following C code into Joy:

int main(int argc, char *argv[])
{
int x, y, k;
char *p = " .:,;!/>)|&IH%*#";
double z1, z2, t, c1, c2;

for (y = 30; y >= 0; y--) {
c2 = ( y * 0.1) - 1.5;
for (x = 0; x < 75; x++) {
c1 = (x * 0.04) - 2;
z1 = z2 = 0;
for (k = 0; k < 112; k++) {
t = (z1 * z1) - (z2 * z2) + c1;
z2 = (2 * z1 * z2) + c2;
z1 = t;
if ((z1 * z1) + (z2 * z2) > 10) break;
}
printf("%c", p[k%16]);
}
printf("\n");
}
}

It is a very simple Mandelbrot generator that I translated from Basic
in the early '80s. Since then I've lost count of the number of times
I've used this to try out new languages. Anyway, the best I've come up
with to date is the following:

(******************************************************************************
* fraclib.joy - a simple fractal generator example.
* Nick Forde <nickf@...> (March 2002)
* The main definition is 'mandel' which may be run without arguments.
* This implementation uses a single loop through all x & y coordinates and
* maintains state by manipulating the aggregate [I:z1 I:z2 F:c1 F:c2].
* $Id: fraclib.joy,v 1.3 2002/03/26 16:17:06 nickf Exp nickf $
******************************************************************************)

"seqlib" libload.

LIBRA

nrows == 30; ncols == 75; (* size of output display *)
mandel == -1 nrows ncols * (* one loop for rows & cols. *)
[ succ dup dup [col] dip row (* calc. column & row indices *)
get_c1 swap get_c2 (* calc. coefficients 1 & 2 *)
get_k putpt (* calc. k and then print *)
[eol] ['\n putch] [] ifte (* put newline if appropriate *)
] times; (* loop for each cell *)
row == ncols /; (* I:i -> I:row *)
col == ncols rem; (* I:i -> I:col *)
eol == col ncols pred =; (* I:i -> B *)
putpt == 16 rem " .:,;!/>)|&IH%*#" of putch; (* we've a palette of 16 *)
get_k == pairlist [0 0] swoncat (* F:c1 F:c2 -> A *)
0 [112 <= [eoloop] dip and] (* condition *)
[succ [inc_zs] dip] while (* if true *)
popd 1 -; (* cleanup -> I *)
get_c1 == 0.10 * 1.5 -; (* outer loop coeff. I:i -> F *)
get_c2 == 0.04 * 2.0 -; (* inner loop coeff. I:i -> F *)
sqr_z1 == first dup *; (* A -> I *)
sqr_z2 == 1 at dup *; (* A -> I *)
inc_z1 == dup [sqr_z1] [sqr_z2] cleave - (* (z1*z1)-(z2*z2)+c2 *)
[3 at] dip +; (* A -> I *)
inc_z2 == 3 take reverse uncons uncons (* (2*z1*z2)+c1 *)
uncons pop (* *)
2 * * + ; (* A -> I *)
eoloop == dup sqr_z1 swap sqr_z2 + 10 <=; (* (z1*z1)+(z2*z2)<=10 A -> B *)
inc_zs == dup [inc_z1] [inc_z2] cleave (* *)
pairlist swap rest rest concat; (* A -> A *)

FRACLIB == "fraclib.joy - fractal library\n".
"fraclib is loaded\n" putchars.

(******************************************************************************
* END fraclib.joy
******************************************************************************)

Could those of you who've been thinking in Joy for some time please
point out where this may be improved. Perhaps this algorithm could be
modified to make it more suitable for implementing in Joy? Am I
missing some more appropriate operators or combinators?

Any help would be most appreciated. As I'm a novice when it comes to
both Joy and functional programming I can't help but feel that this
could be made much more elegant and/or efficient.

Regards,

Nick.

Louis Madon — 2002-03-27 22:21:00

Hi Nick,

Interesting program! I tried creating my own version of it in Joy,
though I'm not quite happy with the solution I got (but here it is
anyway!).

It is a bit smaller but also a lot slower than your version - I think
because using aggregates (pair) and ops on them (mapr2, infra) within
the inner k loop is imposing a lot of overhead. (Ideally it shouldn't,
but the current Joy implementation seems to penalize you for using
those).

Anyway, here it is:

mandel ==
0 30 from-to-list [-0.10 * 1.5 +] map
0 74 from-to-list [-0.04 * 1.0 +] map 'n swons
cartproduct [putpt] step;

putpt ==
unpair
[pop2 newline]
[pair get_k 16 rem " .:,;!/>)|&IH%*#" of putch]
ifchar;

get_k ==
[-1 [0 0]] dip [[+] mapr2 inczs [succ] dip] cons
[null not swap 112 < and] repeat pop;
inczs ==
[[* 2 *] nullary rollup [dup *] unary2
[+ 10 >] [pop2 pop] [- swap] ifte] infra;

Louis.

Nick Forde — 2002-03-28 13:12:33

Hi Louis,

Nice!

I prefer your approach with the main loop(s). I tried a few variants
on this theme but didn't know "from-to-list". The "mapr" combinator
was also new to me. I really need to take a closer look at agglib.

Joy truly is a beautiful little language!

Many thanks,

Nick.

P.S. I notice "pair" is no longer in Manfred's latest libraries.

Louis Madon writes:
...
> mandel ==
> 0 30 from-to-list [-0.10 * 1.5 +] map
> 0 74 from-to-list [-0.04 * 1.0 +] map 'n swons
> cartproduct [putpt] step;
>
> putpt ==
> unpair
> [pop2 newline]
> [pair get_k 16 rem " .:,;!/>)|&IH%*#" of putch]
> ifchar;
>
> get_k ==
> [-1 [0 0]] dip [[+] mapr2 inczs [succ] dip] cons
> [null not swap 112 < and] repeat pop;
> inczs ==
> [[* 2 *] nullary rollup [dup *] unary2
> [+ 10 >] [pop2 pop] [- swap] ifte] infra;
...

Louis Madon — 2002-03-28 20:45:53

On Thursday, March 28, 2002, at 11:12 PM, Nick Forde wrote:
>
> I prefer your approach with the main loop(s). I tried a few variants
> on this theme but didn't know "from-to-list". The "mapr" combinator
> was also new to me. I really need to take a closer look at agglib.
>

For the main loop I had wanted to write:

mandel ==
0 30 from-to-list [-0.10 * 1.5 +] map
0 74 from-to-list [-0.04 * 1.0 +] map
cartproduct 31 slices
[[putput] step newline] step;

putpt == ... just call get_k and output a char

Unfortunately there was nothing like a "slices" function that I could
find - ie. take a list and slice it up into that number of equi-sized
sublists. So I ended up deciding the 'n hack would be quicker than
writing up 'slices' myself. But the slices solution would have been more
elegant ...


> Joy truly is a beautiful little language!

Agreed !

Louis.

>
>
> P.S. I notice "pair" is no longer in Manfred's latest libraries.
>

Ah interesting, you were missing that too - I just thought I had a dud
version but obviously not...


[Non-text portions of this message have been removed]

e1_t — 2002-03-29 05:21:59

--- In concatenative@y..., Louis Madon <madonl@b...> wrote:
> Hi Nick,
>
> Interesting program! I tried creating my own version of it in Joy,
> though I'm not quite happy with the solution I got (but here it is
> anyway!).
>
> It is a bit smaller but also a lot slower than your version - I
think
> because using aggregates (pair) and ops on them (mapr2, infra)
within
> the inner k loop is imposing a lot of overhead. (Ideally it
shouldn't,
> but the current Joy implementation seems to penalize you for using
> those).
>
> Anyway, here it is:
>
> mandel ==
> 0 30 from-to-list [-0.10 * 1.5 +] map
> 0 74 from-to-list [-0.04 * 1.0 +] map 'n swons
> cartproduct [putpt] step;
>
> putpt ==
> unpair
> [pop2 newline]
> [pair get_k 16 rem " .:,;!/>)|&IH%*#" of putch]
> ifchar;
>
> get_k ==
> [-1 [0 0]] dip [[+] mapr2 inczs [succ] dip] cons
> [null not swap 112 < and] repeat pop;
> inczs ==
> [[* 2 *] nullary rollup [dup *] unary2
> [+ 10 >] [pop2 pop] [- swap] ifte] infra;
>

I couldn't get the program to work - Joy keeps complaining how it
can't find the definition for pair. I did a grep on the libs hoping
to find the definition but I only found unpair, pairset and pairlist.
I assumed pair and pairlist were the same so I just added pair ==
pairlist but then the program produced some weird output.

The program does however look impressive. When I first saw Nick's
post I started writing my own version of the program but after I saw
your program there wasn't much point to it as it's much cleaner and
more readable then what I had.

Ivan

Louis Madon — 2002-03-29 05:26:27

On Friday, March 29, 2002, at 03:21 PM, e1_t wrote:

> >      mandel ==
> >         0 30 from-to-list [-0.10 * 1.5 +] map
> >         0 74 from-to-list [-0.04 * 1.0 +] map 'n swons
> >         cartproduct [putpt] step;
> >
> >      putpt ==
> >        unpair
> >          [pop2 newline]
> >          [pair get_k 16 rem " .:,;!/>)|&IH%*#" of putch]
> >        ifchar;
> >
> >      get_k ==
> >        [-1 [0 0]] dip [[+] mapr2 inczs [succ] dip] cons
> >          [null not swap 112 < and] repeat pop;
> >      inczs ==
> >        [[* 2 *] nullary rollup [dup *] unary2
> >          [+ 10 >] [pop2 pop] [- swap] ifte] infra;
> >
>
> I couldn't get the program to work - Joy keeps complaining how it
> can't find the definition for pair. I did a grep on the libs hoping
> to find the definition but I only found unpair, pairset and pairlist.
> I assumed pair and pairlist were the same so I just added pair ==
> pairlist but then the program produced some weird output.

pair was definitely in the earlier definitions of joy - the fact that
it's not there now is a bug. Anyway, you can define it as:

pair == unitlist cons;


> The program does however look impressive. When I first saw Nick's
> post I started writing my own version of the program but after I saw
> your program there wasn't much point to it as it's much cleaner and
> more readable then what I had.

Thanks. However, I'm not too happy with get_k and inczs - I think they
look too much like jibberish. I would prefer code that is more
self-evident. (Maybe a cross between what I did and what Nick did would
be the best solution ...)

Louis.


[Non-text portions of this message have been removed]

e1_t — 2002-03-29 06:40:39

> >
> > I couldn't get the program to work - Joy keeps complaining how it
> > can't find the definition for pair. I did a grep on the libs
hoping
> > to find the definition but I only found unpair, pairset and
pairlist.
> > I assumed pair and pairlist were the same so I just added pair ==
> > pairlist but then the program produced some weird output.
>
> pair was definitely in the earlier definitions of joy - the fact
that
> it's not there now is a bug. Anyway, you can define it as:
>
> pair == unitlist cons;
>

The program still produces garbage - I'll have a look at why it's
doing that a bit later.
By the way pairlist is defined as [] cons cons which is identical to
unitlist cons so pair seems to have been renamed into pairlist.
seqlib.joy still seems to use the old definition though.

Ivan

Manfred von Thun — 2002-04-03 07:14:32

On Fri, 29 Mar 2002, e1_t wrote:

[...]
> I couldn't get the program to work - Joy keeps complaining how it
> can't find the definition for pair. I did a grep on the libs hoping
> to find the definition but I only found unpair, pairset and pairlist.
> I assumed pair and pairlist were the same so I just added pair ==
> pairlist but then the program produced some weird output.

Yes, the old pair operator has become pairlist, but I cannot remember
when I made that change. The reason was of course that there are
three sorts of aggregates: lists, sets and strings. To combine two
things into an aggregate-of-some-sort, Joy needs to be told what-sort.
So one needs pairlist, pairset and pairstring. One the other hand,
unpair takes any aggregate and takes out the first two members.

And by the way, the Mandelbrot programs are very impressive.
Congratulations.

Would one you clever authors be willing to collect the various
versions into one file and put it into the concatanative files area?

- Manfred