From J Wiki
Jump to navigation Jump to search

Group project, Save Work, persistent data, raising interest in J, language as culture, picture albums, date arithmetic, catalog obverse, CSV files, beginner questions

Meeting Agenda for NYC JUG 20050208

1. Group project: focus on good design - see Cooper*, et al.

    a. What will it be?  Suggestions so far:

        i) brief tutorial on my backup utility; perhaps also alarmMsg ->
        sub-project of persistent window data -> user preference tracking.

        ii) sketch of an OpenGL project: boolean solids operation;
        (show de Casteljau algorithm);

        iii) further thoughts on what we might do with MIDI or other
        music-based idea;

        iv) collections utilities: mass rename, tracking of MP3s, photos;

        v) backtrack and code collection utility;

        vi) any other ideas?  General-purpose utilities like CSV read/write?

    b. How should we structure it?

    c. What are small sub-projects into which we can break it?

        i) what are general classes of utility functions? e.g.
        date-time (see "DateAdd" attached), file-handling.

    d. Use version control?
        Or use J projects?  SubEthaEdit?

    e. Coding standards?  Aim for multi-OS version?

2. Learning and creating learning materials: how to start this?  See point
   1.c. above - a general framework will give a broad target at which to aim.

   How to structure it?  As a FAQ?  Hypertext?

   What's in my "J/primer" directory?  Show DHMIdioms.txt - too idiosyncratic?

   Feedback to J Software.

3. Preliminary assignments: who can commit to how much by next month?

4. Show and tell: "DateAdd" -> dates.ijs & sfl.ijs: illustrating
   the difficulty of re-use.
  • The Inmates are Running the Asylum by Alan Cooper; see



Save Work Project - Possible Core: parseDir

I told a little bit about how "parseDir.ijs" works: File:ParseDir.ijs.

This is the backup facility I've been using for years - it could form the core of a "Save Work" project.

One feature of the script file is that it outputs the most commonly-used commands to the J session upon loading:

   load '~user/code/parseDir.ijs'
6!:2 '''FLNMS FLDTS FLSZS FLPARENT DIRNMS DIRDEP''=: getDirFlInfo_parseDir_ ''C:\'''
(<'\amisc\') fileVar_WS_&.>'FLNMS';'FLDTS';'FLSZS';'FLPARENT';'DIRNMS';'DIRDEP'
'batfl cmds'=. buildBatFl_parseDir_ 700e6;'C:\Temp\Recent\'
winexec ('cmd /c ',batfl);1

This makes it simple to avoid typing long commands by grabbing the lines from above that are close to what I want and modifying them if necessary.

First, build the global variables with information about all the files and directories on my C: drive (timing it):

   6!:2 '''FLNMS FLDTS FLSZS FLPARENT DIRNMS DIRDEP''=: getDirFlInfo_parseDir_ ''C:\'''
   0 60#:785.195
13 5.195

This was run on my laptop - 1.5GHz Thinkpad, 512M RAM, 31GB disk with 3.2GB free. As you can see above, it took about 13 minutes.

Now build the .BAT file to create target directories and copy 100M (=1e8) of the most recently-changed files to my thumb (K:) drive:

   'batfl cmds'=. buildBatFl_parseDir_ 1e8;'K:\'

Run the .BAT file (asynchronously):

   winexec ('cmd /c ',batfl);1
|33|cmd /c C:\DOCUME~1\DMCCOR~1\LOCALS~1\Temp\CDMDCopy.bat|1|

Build another command file to dump more files to a network drive:

   6!:2 '''batfl cmds''=. buildBatFl_parseDir_ 5e8;''U:\'''

   winexec ('cmd /c ',batfl);1
|33|cmd /c C:\DOCUME~1\DMCCOR~1\LOCALS~1\Temp\CDMDCopy.bat|1|

AlarmMsg: GUI Example

"AlarmMsg.ijs" (File:AlarmMsg.ijs) is a simple GUI application I wrote that allows me to have a window pop up after a specified time to remind me of something.


It's interesting in relation to the "Save Work" example only in that it exemplifies how one might save information between invocations of code. This code uses the file "AlarmParms.ini" to retain the settings entered by the user between invocations. The simple text file consists simply of "Name=Value" pairs corresponding to the three input fields on the dialog box:

ALRMSG=NYCJUG at Heartland on 34th at 18:30

So, each user update is written to this file to be available the next time the code is called. This persistence can be very useful as we often specify very similar parameters on subsequent invocations of code. It's a nice touch if the code remembers what we usually do and makes it available.

How To Get People Interested in J: Games?

Date:	Wed, 26 Jan 2005 12:36:26 -0500
From:	"Miller, Raul D" <rdmiller@USATODAY.COM>
Subject:	Re: [Jforum] Programming language (fwd)

Fraser Jackson wrote:
> When I asked one small group of 12 year old boys what they wanted
> to program their answer was simple - games.  If Raul can write up
> and share some of his explorations of OpenGL it would be great.
> If we could have a 'Beginning OpenGl Game Programming'(Astle and
> Hawkins) but using J and its marvellous capability of interactive
> function development it would be a vast step forward in creating
> an environment for wider use of J.

I don't think I'm really ready to tackle these kinds of issues
yet.  My knowledge of OpenGL at the moment is extremely
sketchy and well below the level needed for a game more
advanced than "pong".

However, it's my impression that if J were to serve as a game
engine (as opposed to a game design tool), you would need
to incorporate some bits of C into the application, to get
performance to acceptable levels.

Of course, if you're using opengl 2.0 (shader language), you're
also using C (or something extremely close), but the compilation
and loading of that code is handled by the opengl drivers.  I'm
talking about the bits of code which run on the J side of the
opengl interface.

For example (and this example might be more a demonstration of
my ignorance of opengl than anything else), I'm under the impression
that the fastest way to pump vertex information into an opengl
driver is using glVertexPointer -- which has some implications
for the use of display lists (I'm presuming that a display
list would persist beyond individual calls to glVertexPointer).

Anyways, I'm likely to put together some small physics simulations
well before I'm likely to put together something which I think
fits in the "game" classification.  [And keep in mind that
my explorations of OpenGL are, at most, only a few hours a week.]

But I will try to take a look at the Astle and Hawkins book.



Language as Culture

[from] [interview with Alan Kay in ACM's Queue magazine]

[Alan Kay] In a history of Smalltalk I wrote for ACM, I characterized one way of looking at languages in this way: a lot of them are either the agglutination of features or they’re a crystallization of style. Languages such as APL, Lisp, and Smalltalk are what you might call style languages, where there’s a real center and imputed style to how you’re supposed to do everything. Other languages such as PL/I and, indeed, languages that try to be additive without consolidation have often been more successful. I think the style languages appeal to people who have a certain mathematical laziness to them. Laziness actually pays off later on, because if you wind up spending a little extra time seeing that “oh, yes, this language is going to allow me to do this really, really nicely, and in a more general way than I could do it over here,” usually that comes back to help you when you’ve had a new idea a year down the road. The agglutinative languages, on the other hand, tend to produce agglutinations and they are very, very difficult to untangle when you’ve had that new idea.

Also, I think the style languages tend to be late-binding languages. The agglutinative languages are usually early-binding. That makes a huge difference in the whole approach. The kinds of bugs you have to deal with, and when you have to deal with them, is completely different.

Some people are completely religious about type systems and as a mathematician I love the idea of type systems, but nobody has ever come up with one that has enough scope. If you combine Simula and Lisp—Lisp didn’t have data structures, it had instances of objects—you would have a dynamic type system that would give you the range of expression you need.

It would allow you to think the kinds of thoughts you need to think without worrying about what type something is, because you have a much, much wider range of things. What you’re paying for is some of the checks that can be done at runtime, and, especially in the old days, you paid for it in some efficiencies. Now we get around the efficiency stuff the same way Barton did on the B5000: by just saying, “Screw it, we’re going to execute this important stuff as directly as we possibly can.” We’re not going to worry about whether we can compile it into a von Neumann computer or not, and we will make the microcode do whatever we need to get around these inefficiencies because a lot of the inefficiencies are just putting stuff on obsolete hardware architectures.

I just think that’s a two-culture divide. I’ve seen many meetings where people are unable to communicate just because of the stylistic differences in approaches.

Building Picture Albums

Date:	Tue, 25 Jan 2005 09:24:37 -0800
From:	"Joey K Tuttle" <jkt@QUED.COM>  Add to Address BookAdd to Address Book
Subject:	Re: [Jforum] Programming language (fwd)

On Fri, 21 Jan 2005, Brian M. Schott wrote:

>  to produce a dynamic webhosted application. Being a
>  (retired) kid at heart, myself, I know that I have had to
>  seek out perl for two of my own apps -- to get them on the
>  web -- because J cannot do so.
At 21:17 -0500 2005/01/24, Brian M. Schott wrote:
>afaik: J only supports html (right?);

At 08:40 -0500 2005/01/25, Brian M. Schott wrote:
>	I mean that the only web-related feature provided by
>j is html encoding. My terminology may be wrong (worse yet,
>my last statement may be wrong), but I mean that there are
no facilities for cgi interfacing, though.


I meant (tried) to post this last friday when it was more
timely, but I failed twice (my own problems and distractions).

I'm not sure what you did with the PERL, but I happily use
j as CGI calls on my Apache web server - that is, a user
somewhere on a browser can create dynamic pages that are
built by j - this requires no knowledge of what is in the
background, and I like writing CGI in j much more than in
PERL -- although PERL can be a "module" in Apache, j could
be too with a little porting effort. This would make things
even faster and more efficient - but they work very well
already. As an added thought from one of the other posters,
the most used such application I have is building picture
albums dynamically. I gave a talk on this subject to the
APLbug (SF Bayarea User Group) a couple of years ago.

- joey

Date Arithmetic

A common thing we want to do is to find the difference between dates or add a certain number of days, weeks, or months to a given date. Visual Basic has a nice function "DateAdd" which does this.

DateAdd=: 3 : 0
NB.* DateAdd: limited mimic of VB DateAdd - DateAdd <unit to add>;date;num.
NB. Date in form YYYYMMDD.
   ts=. i. 0 [ units=. 'YMDW'      NB. Units are Year, Month, Day, Week.
   'unit dt addnum'=. y.
   assert (unit=. {.toupper unit) e. units
   dpu=. (372 31 1 7){~units i. unit    NB. 372=12*31: provisional "year"
   mobase=. 0 12 31
   assert. dt>18000101   NB. todayno only goes back to this date
   dt=. 0 100 100#:dt
   select. unit
   case. 'D';'W' do.
       dt=. 100#.todate (dpu*addnum)+todayno dt
   case. 'M';'Y' do.
       fakedayno=. mobase#.0 _1 0+dt
       dt=. 100#.todate todayno 0 1 0+mobase#:fakedayno+dpu*addnum
   assert. dt>18000101   NB. todayno only goes back to this date
NB. dtdifs=. 2-/\todayno&>(<0 100 100)#:&.> dtsa=. DateAdd&>(<'D';20050101),&.><&.>i:_10000
NB. 1 *./ . = dtdifs
NB. dtdifs=. 2-/\todayno&>(<0 100 100)#:&.> dtsa=. DateAdd&>(<'W';20050101),&.><&.>i:_10000
NB. 7 *./ . = dtdifs

This uses following J-supplied code:

NB. From ~system\main\dates.ijs
NB. =========================================================
NB.*todayno v converts dates to day numbers
NB. converts dates to day numbers, converse <todate>
NB. y. = dates
NB. x. = optional:
NB.   0 - dates in form <yyyy mm dd> (default)
NB.   1 - dates in form <yyyymmdd>
NB. 0 = todayno 1800 1 1, or earlier
NB. example:
NB.    todayno 1998 5 23
NB. 72460

todayno=: 3 : 0
0 todayno y.
a=. y.
if. x. do. a=. 0 100 100 #: a end.
a=. ((*/r=. }: $a) , {:$a) $,a
'y m d'=. <"_1 |: a
y=. 0 100 #: y - m <: 2
n=. +/ |: <. 36524.25 365.25 *"1 y
n=. n + <. 0.41 + 0 30.6 #. (12 | m-3),"0 d
0 >. r $ n - 657378

Did not find something to use exactly from Oleg's "sfl" addon (see his website [2]). This could form the basis of a more thorough version of "DateAdd".

NB. see for detailed description
NB. J Script  template
NB. Wednesday, May 17, 2000
NB. SFL dates routines

require jpath '~addons\sfl\sfl.ijs'


date_now=: '   date_now + i' cdm NB.             (void);
time_now=: '   time_now + i' cdm NB.	      (void);
leap_year=: '   leap_year + i i' cdm NB.	      (int year);
julian_date=: '   julian_date + i i' cdm NB.         (long date);
day_of_week=: '   day_of_week + i i' cdm NB.         (long date);
week_of_year=: '   week_of_year + i i' cdm NB.        (long date);
year_quarter=: '   year_quarter  + i i' cdm NB.       (long date);
next_weekday=: '   next_weekday  + i i' cdm NB.       (long date);
prev_weekday=: '   prev_weekday  + i i' cdm NB.       (long date);
pack_date=: '   pack_date     + i i' cdm NB.       (long date);
pack_time=: '  pack_time   + i i' cdm NB.         (long time);
unpack_date=: ' unpack_date   + i i' cdm NB.       (word packdate);
unpack_time=: ' unpack_time    + i i' cdm NB.      (word packtime);
default_century=: 'default_century  + i i'cdm NB.    (long *date);
date_to_days=: 'date_to_days   + i i' cdm NB.      (long date);
days_to_date=: 'days_to_date   + i i' cdm NB.      (long days);
date_to_timer=: ' date_to_timer   + i i i'cdm NB. time_t     (long date, long time);
timer_to_date=: ' timer_to_date  + i i' cdm NB.      (time_t time_secs);
timer_to_time=: ' timer_to_time  + i i' cdm NB.     (time_t time_secs);
timer_to_gmdate=: 'timer_to_gmdate + i i' cdm NB.     (time_t time_secs);
timer_to_gmtime=: 'timer_to_gmtime + i i' cdm NB.    (time_t time_secs);
time_to_csecs=: ' time_to_csecs   + i i' cdm NB.    (long time);
csecs_to_time=: ' csecs_to_time   + i i' cdm NB.    (long csecs);
future_date=: ' future_date  + i *i *i i i'cdm NB.       (long *date, long *time, long days, long csecs);
past_date=: '   past_date + i *i *i i i'cdm NB.          (long *date, long *time, long days, long csecs);
date_diff=: '  date_diff +i i i i i *i *i'cdm NB.           (long date1, long time1, long date2, long time2, long *days, long *csecs);
valid_date=: '   valid_date + i i'cdm NB.         (long date);
valid_time=: '   valid_time + i i'cdm NB.         (long time);
date_is_future=: ' date_is_future  + i i i'cdm NB.    (long date, long time);
date_is_past=: '  date_is_past  + i i i'cdm NB.      (long date, long time);
timezone_string=: ' timezone_string + *c'cdm NB.    (void);
local_to_gmt=: '   local_to_gmt  + i i i *i *i'cdm NB.      (long date, long time, long *gmdate, long *gmtime);
gmt_to_local=: '   gmt_to_local  + i i i *i *i'cdm NB.      (long gmdate, long gmtime, long *date, long *time);

NB. =========================================================

datenow=: first@ date_now
timenow=: first@ time_now
leapyear=: first@ leap_year
juliandate=: first@ julian_date

dayofweek=: first@ day_of_week
weekofyear=: first@ week_of_year
yearquarter=: first@ year_quarter
nextweekday=: first@ next_weekday
prevweekday=: first@ prev_weekday
packdate=: first@ pack_date
packtime=: first@ pack_time
unpackdate=: first@ unpack_date
unpacktime=: first@ unpack_time
datetodays=: first@ date_to_days
daystodate=: first@ days_to_date
timetocsecs=: first@ time_to_csecs
csecstotime=: first@ csecs_to_time
validdate=: first@ valid_date
validtime=: first@ valid_time
dateisfuture=: first@ date_is_future
dateispast=: first@ date_is_past
timezonestring=: memr0@first@ timezone_string

Catalog Obverse

Some interesting forum traffic on the catalog verb and its obverse.

Date:	Mon, 14 Feb 2005 13:09:03 -0500
From:	"Roger Hui" <rhui000@SHAW.CA>
Subject:	Re: [Jforum] Inverse of Catalogue

x=: (2 3$'abcdef');'ghij'
   y=: catalogue x
   uncatalogue y
|index error: uncatalogue
|       uncatalogue y

On Sun, 13 Feb 2005 18:46:21 -0500, Mark D. Niemiec <mniemiec@INTERSERV.COM>

>J does not provide an inverse of { Catalogue, but it is an easy operation
to perform:
>   uncatalogue =: (>`(i.@#@$<@([{&>({:@$$,)@|:)"0 _])@.(*@#@$))
>   catalogue =: { :. uncatalogue
>   [ y =: 'ht';'ao';'gtw'
. . .

An idea for the inverse of catalog.

Date:	Sun, 13 Feb 2005 18:46:21 -0500
From:	"Mark D. Niemiec" <mniemiec@INTERSERV.COM>
Subject:	[Jforum] Inverse of Catalogue

J does not provide an inverse of { Catalogue, but it is an easy operation to

   uncatalogue =: (>`(i.@#@$<@([{&>({:@$$,)@|:)"0 _])@.(*@#@$))
   catalogue =: { :. uncatalogue

   [ y =: 'ht';'ao';'gtw'
   [ caty =: { y

   uncatalogue caty
   |.&.catalogue y
   |."_1&.catalogue y
   |."_2&.catalogue y

-- Mark D. Niemiec <>

Beginner's Session

We had a computer available so we showed how to answer some questions people had.

NB. [Session started: 2005 2 8 20 29 33.137]

NB. Jim has a matrix of boxed items he wants to convert to plain
NB. ASCII (including the boxing display characters).
   nn=. 3 3$'';'x';'y';'min';'3';'2';'max';'9';'10'
|   |x|y |
|min|3|2 |

NB. He has only to do this:
|   |x|y |
|min|3|2 |

NB. Looks the same but the shape tells us it isn't:
  $ ":nn
7 10

NB. I would probably put it a more common format (e.g. .CSV):
   matrix2csv nn

NB. Example of standard function to use to split, e.g. headers from data:
   split 1 2 3 4
|1|2 3 4|
   2 split 1 2 3 4
|1 2|3 4|
NB. It works on items, so:
   split nn
|||x|y|||min|3|2 ||
|      ||max|9|10||
|      |+---+-+--+|

NB. In discussing the difficulties of handling .CSV files efficiently,
NB. particularly the overhead of checking whether a cell is numeric or
NB. not, Dan suggests grouping entire columns thusly:
   d                               NB. We have mixed cells but columns
+-+-----+-----+---+                NB. have homogenous types.

NB. So, group elements of columns together.
   tocol d
|4 4 4 4 4|hello|devon|9j9 9j9 9j9 9j9 9j9|
|         |hello|devon|                   |
|         |hello|devon|                   |
|         |hello|devon|                   |
|         |hello|devon|                   |

NB. My own, much-used, matrix-to-CSV-file function.
4 : 0
NB.* m2c: Matrix x. to .CSV file y.
   dlim=. '' [ writeInPieces=. 0   NB. Default to write as single piece.
   if. 1=L. y. do. 'writeInPieces y.'=. y. end.
   if. writeInPieces do.           NB. Underlying function handles writing
       (1;',') matrix2csv x.;<y.   NB.  in pieces.
   else.                           NB. A "file number error" here
       (matrix2csv x.) 1!:2 <y.    NB.  may indicate a held file.
NB.EG data m2c filename
NB.EG data m2c 1;<filename     NB. Write file in pieces as we go to save space.

NB. and its inverse:
3 : 0
   ',' csv2matrix 1!:1 <y.
   x. csv2matrix 1!:1 <y.

3 : 0
NB.* csv2matrix: change contents of .CSV file -> matrix of items from
NB. Comma-Separated-Values file y.  Left arg is delimiter if not comma.
NB. Handles quoted strings.
   ',' csv2matrix y.
   if. x.-:'' do. delim=. ',' else. delim=. x. end.
   if. 0=L. y. do. vec=. l2v y.   NB. Box lines if simple vec ->
   else. vec=. y. end.            NB.  vector of text lines.
   mat=. matMakeMaskedPtn vec;delim;<'"'
   mat=. mat-.&.>'"'              NB. Remove quotes.

NB. Example of using to read in .CSV file->J boxed matrix:
   $fl=. c2m '\gtaap\gaa\data\rawdatfl.csv'
365 101
|Code      |BRITPUS                            |JAPYNUS               ...
|Currency  |£                                  |Y                     ...
|12/31/1974|#n/a                               |#n/a                  ...
|1/31/1975 |#n/a                               |#n/a                  ...

NB. Split off the header from the data:
   'hdr fld'=. 3 split fl
|Code    |BRITPUS                            |JAPYNUS                 ...
|Currency|£                                  |Y                       ...
|1/31/1975 |#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|76....
|2/28/1975 |#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|#n/a|81....
   'hdr fld'=. tocol each 3 split fl
|Code    |BRITPUS                            |JAPYNUS                 ...
|Currency|£                                  |Y                       ...
|9/30/1986 |1.44800|0.00647999|0.49350|0.60730|0.150700|0.43670|0.6284...
|1/30/1987 |1.51350|0.00651499|0.54660|0.64810|0.163900|0.48600|0.6622...
|2/27/1987 |1.55500|0.00652500|0.54670|0.64850|0.164100|0.48480|0.6805...
|3/31/1987 |1.60750|0.00685899|0.55430|0.66310|0.166500|0.49040|0.7062...
|4/30/1987 |1.66150|0.00710699|0.55800|0.68100|0.167100|0.49320|0.7020...
|5/29/1987 |1.62950|0.00695200|0.54840|0.66230|0.164300|0.48690|0.7123...
|6/30/1987 |1.61750|0.00681200|0.54800|0.66050|0.164200|0.48700|0.7211

NB. Example of converting text to numbers with an error flag of _99:
   _99 ". '1 2 3 4'
1 2 3 4
   _99 ". '1 2 3 4'
1 2 3 4
    _99 ". '1 2 3 4 crap'
1 2 3 4 _99

NB. My own (external format) Number to J number function:

NB. and its inverse:
3 : 0
NB.* J2StdCvtNums: convert char rep of num from J to "Standard", or
NB. vice-versa if left arg is 'J' or '2J'; optional 2x2 left argument allows
NB. 2 arbitrary conversions: col 0 is "from", col 1 is "to" char.
NB. Monadic case changes Standard numeric representation to J representation.
   (2 2$'-_Ee') J2StdCvtNums y.
   pw16=. 0j16                          NB. Precision width: 16 digits>.
   diffChars=. 2 2$'-_Ee'               NB. Convert '-'->'_' & 'E'->'e'
   toStd=. -.'J'-:''$'2'-.~,x.          NB. Flag conversion J->Standard
   if. 2 2-:$x. do. diffChars=x.        NB. if explicit conversion.
   elseif. toStd do. diffChars=. |."1 diffChars end.   NB. Convert other way
NB.   if. 0=1{.0$y. do. y.=. pw16":y. end. NB. Numeric to character
   if. 0=1{.0$y. do.                    NB. Numeric to character
       fmts=. (8=>(3!:0)&.>y.){0,pw16   NB. Full-precision floats only
NB.       whvn=. isValNum &.> y.
NB.       tty=. fmts":y.                   NB. If this is too slow, go back
       y.=. fmts":y.                   NB. If this is too slow, go back
NB.       y.=. whvn}tty,:y.                NB. If this is too slow, go back
NB.       y.=. pw16":y.                 NB.  to this.

   y.=. y.-.'+'                         NB. EG 1.23e+11 is ill-formed & the
   wh=. y.=0{0{diffChars                NB.  '+' is unnecessary.
   cn=. (wh#1{0{diffChars) (wh#i. $y.)}y.    NB. Translate chars that need it
   wh=. y.=0{1{diffChars                     NB.  but leave others alone.
   cn=. (wh#1{1{diffChars) (wh#i. $cn)}cn
   if. -.toStd do.                      NB. Special handling -> J nums
       if. '%'e. cn do.                 NB. Convert nn% -> 0.nn
           cn=. pw16":0.01*".cn-. '%'
       cn=. cn-.','                     NB. No ',' in J numbers
NB.EG 'S' J2StdCvtNums _3.14 6.02e_23   NB. Convert J numbers to std rep

3 : 0
NB.* matrix2csv: create .CSV file from matrix of items y.
NB. Inverse of csv2matrix but doesn't write to a file; does quote literals.
NB. Optional left arg is (scalar) field separator character.
NB. Do large mats in pieces to avoid using up memory.
NB. Optional flag 0{x. is 1 if we are to write file instead of just
NB. creating result to write to file.
   ',' matrix2csv y.
   ctr=. i. 0 [ csvfl=. '' [ doWrite=. 0
   if. isEnclosed x. do.
       'doWrite x.'=. x.
       'y. flnm'=. y.
   y.=. (_2{.1 1,$y.)$,y.     NB. Ensure is a matrix.
   if. 0>4!:0 <'flnm' do. flnm=. 'TEMP.TMP',~getTempDir '' end.
   flnm=. boxopen flnm
NB. Estimate Number of Rows Per Iteration: was a global.
   NRPI=. 100>.1000*<.0.5+0.001*(#y.)%(7!:5 <'y.')%15e6 NB. 15e6 for 256MB mem.
   numrows=. NRPI<.#y.
   if. doWrite do.
       '' 1!: 2 flnm          NB. Initialize file because we'll append later.
   while. 0 < # y. do.        NB. Do in pieces if too large.
      mat=. numrows{.y.
      whchar=. ' '=&.>1{.&.>0$&.>mat    NB. Where non-num (=char) fields?
      if. 1 e. ,whchar=. ;,whchar do.
          quotes=. ($mat)$whchar#&.>'"' NB. Put quotes around char fields.
          if. +./,>'"'e.&.>mat do.           NB. Duplicate any quotes that
              mat=. (>:&.>mat=&.>'"')#&.>mat NB.  are part of data.
          mat=. quotes,&.>mat,&.>quotes
      if. 1 e. whnum=. ,-.whchar do.    NB. Convert numerics to char so
          shape=. $mat                  NB. can append field separator.
          mat=. ]&.>,mat                NB. Enclose if simple array.
          mat=. (":&.>whnum#mat) (b2i whnum)}mat
          mat=. shape$mat
      mat=. mat,&.>x.
      mat=. ;(_1}."1 mat),.(_1}.&.>_1{."1 mat),&.><CR,LF
      if. doWrite do.
          mat 1!:3 flnm
          csvfl=. csvfl,mat
      y.=. numrows}.y.
      numrows=. numrows <. # y.
NB.EG Either
NB.EG    (matrix2csv datamat) 1!:2 <flnm
NB.EG or
NB.EG    (1;',') matrix2csv datamat;<flnm

NB. Dan shows us the tree display form he finds handy.
NB. Start with a long train of constant functions:
   g =: 1: 2: 3: 4: 5: 6: 7: 8: 9:

NB. Display it (first word in the namelist consisting only of 'g')
NB. with "5!:4":
  +- 1:
  +- 2:
--+    +- 3:
  |    +- 4:
  +----+    +- 5:
       |    +- 6:
       +----+    +- 7:
            +----+- 8:
                 +- 9:
1: 2: 3: 4: 5: 6: 7: 8: 9:

NB. Try it with a more familiar train:
+/ % #
   g=. (+/%#)
  +- / --- +
--+- %
  +- #
-- {::

NB. Jim wants to know how to activate or execute a J expression given
NB. as a text string; specifically, how to assign a variable indirectly.

c=: dyad define
   ". x.,5!:5{.;:'y.'
NB. Function "c" applies J evaluation of x. to values y. :
   'A=:' c 3 4 5 6
3 4 5 6
NB. Now "A" is 3 4 5 6.
3 4 5 6
   ;/ 3 4 5
3 4 5 6
NB. Left-hand side doesn't have to be assignment, can be any expression.
   B =: '+/'
   B c 3 4 5 6 7

   3 ; 4; 5 ; 6
   C=:3 ; 4; 5 ; 6

Scan of Meeting Notes