Very nice - I really like your approach. And, I am tempted to carry it
a bit further.
First, we can take your manual procedure and turn it into an explicit verb:
abase=:4 :0
z=.y
r=.i.0
for_b. |.x do.
a=. b|z
z=. (z-a)%b
r=. r,a
end.
|.r
)
2 5r2 2 5 abase 38
1 1r2 1 3
That looks basically right, but there's a couple issues which nag at
me. One of them is that this won't work like #: if we give multiple
numbers on the right or multiple rows of numbers on the left. Another
is that I am reversing x and then reversing the result. A quicky
change to address these issues in the function definition might look
like this:
abaseB=: 4 :0&.|."1 0
z=.y
r=.i.0
for_b. x do.
a=. b|z
z=. (z-a)%b
r=. r,a
end.
)
2 5r2 2 5 abaseB 38
1 1r2 1 3
Note that I am taking advantage of the fact that r=. is the last part
of a sentence in each block of code in that verb. Note also that the
explicit definition is now anonymous and the named definition is a
tacit definition which happens to have an embedded explicit
definition. This would make debugging difficult, since the debugger
does not support tracing execution in tacit definitions. So perhaps
the earlier approach was better.
Still, I am tempted to take it just a bit further, because of a
concept of "functional purity". Now... from my point of view, a big
motivation for functional programming is that a functional style makes
debugging easier. You can stop execution on any line of an explicit
definition and (in principle) back up and try again after changing
something if the code is written in a functional (single assignment)
style. But the reassignment of variables in a loop sort of defeats
that point of view (you would have to restart the loop if we had that
kind of debugging environment and debugging situation).
So how would this look in a "purely functional" style? I would
probably stick the 38 on the right hand side of the left argument, and
then use the / adverb to achieve the looping effect. Since a / verb
operates from right to left that gets rid of the need to reverse
anything. In this view of things, b (from the above explicit
definition) could be expressed as [ and z could be expressed as ] -
though if we are building up the result we should actually use {.@] to
distinguish z from the partial result.
In other words:
B=: [
Z=: {.@]
A=: B|Z
ZZ=: (Z -A)%B
R=: }.@]
RR=: ZZ,A,R
RR/2 5r2 2 5 38
0 1 1r2 1 3
Note that we can't just copy the definition of r in abase because we
are assembling the result from right to left (instead of assembling it
from left to right and then reversing it).
Note also that I did not do word equivalences for x and y - b and z
are close enough and loops are already a bit awkward to reason about -
that was my motivation for this rephrasing.
Finally, to replace abaseB:
ABASE=: }.@(RR/f.)@,"1 0
2 5r2 2 5 ABASE 38
1 1r2 1 3
Thanks,
--
Raul
On Sun, Jan 26, 2014 at 12:53 AM, Nollaig MacKenzie
<[email protected]> wrote:
>
> On 2014.01.25 20:33:55, you,
> the extraordinary David Lambert, spake thus:
>
>> NB. convert 38 cents to pennies, nickels, dimes, quarters.
>>
>> 38 #:~ COINS =: |. 1 5 2 5r2 2
>> 1 1r2 1 3 0
>>
>> NB. why do I get a half dime and a nickel?
>>
>> COINS #. 1 1 0 3 0
>> 38
>>
>
> foo=. ((<.@:(%~)),|)
> C=. 2 5r2 2 5
>
>
> 5 foo 38
> 7 3
> 2 foo 7
> 3 1
> 5r2 foo 3
> 1 1r2
> 2 foo 1
> 0 1
>
> and the result of C #: 38 (tracing upward) is 1 1r2 1 3
>
> C#.1 1r2 1 3
> 38
>
>
> --
> Nollaig MacKenzie
> http://www.yorku.ca/nollaig
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm