# 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