Newsgroups: comp.lang.apl
From: pmoore@cix.compulink.co.uk (Paul Moore)
Subject: Re: A verb to trim spaces from a string
Reply-To: pmoore@cix.compulink.co.uk
Date: Thu, 17 Dec 1992 00:09:00 +0000


Thanks to all who helped with my query on how to write verbs to trim
leading and trailing spaces from a string. The responses were most
illuminating. My original query was:

> Specifically, I'm after 3 verbs
>
>    c ltrim str     Remove all occurrences of character c from
>                    the start of str.
>    c rtrim str     Remove all occurrences of character c from
>                    the end of str.
>    c trim str      Remove all occurrences of character c from
>                    both ends of str.
>
> For the monadic cases, assume c is ' '.

Roger Hui suggested

   ltrim =. ' '&$: : (+./\ @:~: # ])
   rtrim =. ' '&$: : (+./\.@:~: # ])
   trim  =. ' '&$: : ((+./\ *. +./\.)@:~: # ])

These are very much like what I was aiming at with my third approach at
the problem - I described this as an "APL-ish" solution, in its use of a
boolean array and # to strip the required characters from the string. It
is encouraging to see that I was thinking along the right lines. The use
of the prefix and suffix adverbs \ and \. is interesting. I shall
certainly remember the idioms

   +./\ boolarray        0 until first 1, then 1
   +./\. boolarray       same, but from the right

so

   +./\ 0 0 0 1 0 1 0 1 0 1 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1

   +./\. 0 0 0 1 0 1 0 1 0 1 0 0 0
1 1 1 1 1 1 1 1 1 1 0 0 0

The use of

   verb =. default&$: : <defn>

is also a useful idiom to remember.

Emmet McLean suggested a number of interesting solutions. First, some
recursive solutions

   ltrim =. ' '&$: : (]`($:}.@]) @. ( = {.@]))
   rtrim =. ' '&$: : (]`($: (}:@])) @. ( = {:@]))
   ctrim =. ' '&$: : ([ ltrim [ rtrim ])

The use of agenda @. and self-reference $: to make a recursive verb in
tacit form is a useful thing to remember. My attempts at recursion had
used $: in explicit forms. I find this tacit recursion much more
idiomatic (but it takes a lot more study to understand the workings of
the verbs! There is a price to pay for anything, I suppose...)

Then, some fascinating solutions involving the power conjunction ^:

   rtrim =. ' '&$: : (}:@]^:([ = {:@]))
   ltrim =. ' '&$: : (}.@]^:([ = {.@]))
   ctrim =. ' '&$: : ([ ltrim [ rtrim ])

Until I studied these, I had completely missed the point of using u ^: v
to make something like a DO-WHILE loop in J. I know that translating J
conjunctions into traditional control structures loses some of the
meaning, but I find the following pseudo-code interpretation of u ^: v
somewhat illuminating - maybe others could comment?

   To evaluate (u ^: v) y, proceed as follows

   1. Set R = y
   2. If v R is zero, stop. The result is R.
   3. Apply u to R (v R) times, setting R to the calculated value.
      (ie, set R = (u ^: (v R)) R, using the simpler case of u ^: n)
   4. Return to (2) with the new R.

The fact that (v R) can be other than 0 or 1 is what makes this more
powerful than a simple DO-WHILE, but nonetheless, the similarity holds.

The dictionary definition

   u^:v y is 'u^:(v y.)y.' : '' ^: _

hides an awful lot of this in the ^: _ which, by virtue of its limiting
process, forms a very powerful looping construct, which deserves much
more study, I suspect...

I shall also have to study the dyadic forms

   x u^:n y
   x u^:v y

and I see J 6.1 introduces u^:g (presumably g is a gerund) - I wonder
what this will do. Is anybody willing to offer hints/examples?

Finally, I note Emmett's definition of ctrim as

   ctrim =. ' '&$: : ([ ltrim [ rtrim ])

I see that this works, but I am a little surprised that this is the
simplest form - it seems to use too many [ and ]. What is happening is I
am looking for a combination fg of f and g, such that

   x fg y     <==>     x f (x g y)

A dual concept is

   x fg y     <==>     (x f y) g y

I would have expected some elegant combinator, in the spirit of hooks
and forks, for these - they seem fairly common operations. But I cannot
find anything simpler than Emmett's expression.

[I note that convert-to-tacit : 11 does not always give the simplest
form. For example,

   '(x. f y.) g (x. h y.)' : 11
+-------+-+-------+
|+-+-+-+|g|+-+-+-+|
||[|f|]|| ||[|h|]||
|+-+-+-+| |+-+-+-+|
+-------+-+-------+

rather than

+-+-+-+
|f|g|h|
+-+-+-+

This can make it quite an act of ingenuity to find the "simplest" tacit
form of an expression.]

Anyway, this posting has become much too long. Thanks once again to all
those who suggested solutions to my little problem - the answers
provoked much interesting thought, and increased my understanding of J
significantly.

Paul Moore.

------------------------------------------------------------------------
Paul Moore (pmoore@cix.compulink.co.uk)   |
------------------------------------------------------------------------
"You're talking about a pope who can't find a chicken in a cave."
------------------------------------------------------------------------
Newsgroups: comp.lang.apl