Transpose
[1/12] from: al::bri::xtra::co::nz at: 6-Oct-2000 1:11
Joel wrote:
> Finally, I'd considered handling the structure-traversing issues
separately from the data-manipulation issues, by defining (this version is
VERY quick and dirty):
> >> transpose: function [b [block!]] [w i s r] [
> [ r: make block! w: accum length? b/1 map b :length? :min
<<quoted lines omitted: 9>>
> >> transpose [[1 2 3] [14 15 16] [27 28 29]]
> == [[1 14 27] [2 15 28] [3 16 29]]
I've cleaned it up a bit:
[
Rebol [
Name: 'Transpose
Title: "Transpose"
File: %"Transpose.r"
Author: "Andrew Martin"
eMail: [Al--Bri--xtra--co--nz]
Date: 5/October/2000
Enhancement: 'Transpose
Acknowledgements: "Joel Neely"
Example: [
transpose [[1 2 3 4 5] ["a" "b" "c" "d" "e"]]
; [[1 "a"] [2 "b"] [3 "c"] [4 "d"] [5 "e"]]
transpose [[1 2 3] [14 15 16] [27 28 29]]
; [[1 14 27] [2 15 28] [3 16 29]]
]
]
Transpose: function [
[catch]
"Transposes Matrices"
Matrix [block!]
][
Results Width Height Column
][
Results: make block! Width: length? Matrix/1
Height: length? Matrix
repeat Index Width [
Column: make block! Width
foreach Row Matrix [
insert/only tail Column Row/:Index
]
insert/only tail Results Column
]
Results
]
]
>> transpose [[1 2 3 4 5] ["a" "b" "c" "d" "e"]]
== [[1 "a"] [2 "b"] [3 "c"] [4 "d"] [5 "e"]]
>> ; [[1 "a"] [2 "b"] [3 "c"] [4 "d"] [5 "e"]]
>> transpose [[1 2 3] [14 15 16] [27 28 29]]
== [[1 14 27] [2 15 28] [3 16 29]]
>> ; [[1 14 27] [2 15 28] [3 16 29]]
> Critiques/comments/debugging welcome!
I totally agree. :-)
Andrew Martin
ICQ: 26227169
http://members.nbci.com/AndrewMartin/
[2/12] from: joel:neely:fedex at: 6-Oct-2000 8:26
(The following note was written while softly humming, "
...
I get by with a little help from my friends,
Gonna try with a little help from my friends.
...
)
I'm really interested in the idea of a common/shared library of
functions/objects such as found on www.rebol.com, contained in
Ladislav's
http://www.rebol.org/advanced/highfun.r
(as one example of the MANY sites that REBOLlistfolk have),
or some of my scribbles earlier in this thread. I'll address
the library issue in a follow-up post. As for the function at
hand, let me raise a couple of questions:
[Al--Bri--xtra--co--nz] wrote:
> Joel wrote:
> > Finally, I'd considered handling the structure-traversing
<<quoted lines omitted: 4>>
> I've cleaned it up a bit:
> ...
j> transpose: function [b [block!]] [w i s r] [
A> Transpose: function [
A> [catch]
A>
Transposes Matrices"
A> Matrix [block!]
A> ][
A> Results Width Height Column
A> ][
Nice choice of names (but I MUST remember to ask you about the caps)
Since we're discussing, I'll take the liberty to explain my abbrevs
as (w)idth (i)ndex (s)ubresult (r)esult :-/
j> r: make block! w: accum length? b/1 map b :length? :min
A> Results: make block! Width: length? Matrix/1
A> Height: length? Matrix
That bit of obscurity in the initialization of w is explained
in a footnote (1) in case I mangled it so badly that no-one can
read it. My real question here is this, if we collectively are
going to build up a small pile of useful extensions, would it be
good to have some conventions re defensive programming, or would
that be the sort of thing that should simply be documented (for
each) as "possible failure modes"? Alternately, should we have
a rating (I do NOT mean "value judgement", but simply accurate
labeling of content!) with values such as:
"fragile" - "arguments not vetted, you can crash this if
you don't play well with others"
"robust" - "good faith argument checking done, but there
may be some gotchas left"
"ironclad" - "we've collectively banged on this one REALLY
hard, and are confident that errors will be
pre-empted"
j> s: make block! length? b
A> Column: make block! Width
(Boneheaded mistake on my part -- thanks for the correction!)
J> foreach c b [append/only s c/:i]
j> append/only r s
A> foreach Row Matrix [
A> insert/only tail Column Row/:Index
A> ]
A> insert/only tail Results Column
(Sigh... You'd think I'd have learned by now. Thanks for cleaning
append/only
up into "insert/only tail" -- repeatedly!)
> > Critiques/comments/debugging welcome!
>
> I totally agree. :-)
>
-jn-
FOOTNOTE:
1) Regarding the peculiar initialization code
r: make block! w: accum length? b/1 map b :length? :min
------1-------
-----2-----
--------------------3-------------------
Step 1 gets the lengths of all sub-blocks in the argument,
step 2 assumes the length of the first as a default, and
step 3 sets w to the length of the shortest sub-block.
This was done so that a collection of (sub-)blocks of different
lengths wouldn't cause an error, but would be transposed as far
as possible:
>> transpose [[1 2 3 4 5] [1 2 3] [1 2 3 4]]
== [[1 1 1] [2 2 2] [3 3 3]]
Of course, this is still not totally robust, as an empty arg
block will still not be swallowable (mea culpa!):
>> transpose []
** Script Error: length? expected series argument of type:
series port tuple struct.
** Where: r: make block! w: accum
This is easy to handle by adding
if 0 = length? b [return copy []]
to the very beginning of the function, or wrapping the body with
either 0 = length? b [
r: copy []
][
r: ...etc...
...etc...
]
r
which would then ensure that the basis for accum given by
length? b/1 was well-defined.
I assume your [catch] was a faster way of addressing this
same issue, by simply passing the error resulting from an
empty argument list back to the caller.
So... should we prefer a style for common/standard library
functions, or at least document which position the author (and
maintainers) took?
[3/12] from: news:ted:husted at: 6-Oct-2000 9:47
[Al--Bri--xtra--co--nz] wrote:
"fragile" - "arguments not vetted, you can crash this if
you don't play well with others"
"robust" - "good faith argument checking done, but there
may be some gotchas left"
"ironclad" - "we've collectively banged on this one REALLY
hard, and are confident that errors will be
pre-empted"
How about applying the SourceForge nomenclature for applications:
1: Planning
2: Pre-Alpha
3: Alpha
4: Beta ("fragile")
5: Production-Stable ("robust")
6: Mature ("ironclad")
> So... should we prefer a style for common/standard library
functions, or at least document which position the author (and
maintainers) took?
How about starting with Carl's style guide <
http://www.rebol.com/users/scrstyle.html >, and extending from there?
-T.
[4/12] from: joel:neely:fedex at: 6-Oct-2000 11:13
Hi, Andrew,
[news--ted--husted--com] wrote:
> [Al--Bri--xtra--co--nz] wrote:
> "fragile" - "arguments not vetted, you can crash this if
<<quoted lines omitted: 11>>
> 5: Production-Stable ("robust")
> 6: Mature ("ironclad")
I like 'em (especially since this puts tradition on our side...), with
one minor reservation. There's an implication among the choices of
beta
, "production-stable", and "mature" that has to do with an item's
progression toward completeness.
There is, to my mind, a slightly different implication to describing
a function as "fragile" vs. "robust" than as "beta" vs. "production-stable"
in that I may want to use the robust version if I'm handling external data
(input from console, data file, etc.) but may be willing to use the fragile
version (for the speed gain of less checking) if I'm at a point in the code
where I'm working with data that has already passed some level of validity
checking -- or that I've constructed earlier in a way that ensures its
validity.
> > So... should we prefer a style for common/standard library
> functions, or at least document which position the author (and
> maintainers) took?
>
> How about starting with Carl's style guide
> <http://www.rebol.com/users/scrstyle.html >
> , and extending from there?
>
I'm sorry... I guess I didn't express that very well.
I think Carl's source coding style guide is a great place to start, for
all the issues it addresses. I was really thinking more of design style
questions, such as the choice between these hypothetical offerings:
max-in-block-fragile: func [b /local x] [
x: first b
foreach y next b [x: max x y]
x
]
max-in-block-sturdy: func [[catch] b [block!] /local x] [
x: b/1
foreach y next b [x: max x y]
x
]
max-in-block-sturdier: func [[catch] b [block!] /local safemax x] [
safemax: func [[catch] a1 a2] [
either any [(type? a1) = (type? a2) all [number? a1 number? a2]] [
max a1 a2
][
max to-string a1 to-string a2
]
]
x: b/1
foreach y next b [x: safemax x y]
x
]
...where we get...
>> max-in-block-fragile []
** Script Error: Out of range or past end.
** Where: x: first b
foreach y
>> max-in-block-sturdy []
== none
>> max-in-block-sturdier []
== none
>> max-in-block-fragile [1 #"a" http://www.rebol.com [carl--rebol--com]]
** Script Error: Expected one of: integer! - not: url!.
** Where: x: max x y
>> max-in-block-sturdy [1 #"a" http://www.rebol.com [carl--rebol--com]]
** Script Error: Expected one of: integer! - not: url!.
** Where: x: max x y
>> max-in-block-sturdier [1 #"a" http://www.rebol.com [carl--rebol--com]]
== "http://www.rebol.com"
If I built a block (e.g. of numbers) myself, and I already know that it is
non-empty, then MAX-IN-BLOCK-FRAGILE may be just fine, but maybe not in
the general case...
...and do we ever need the level of protection afforded (at a cost) by
MAX-IN-BLOCK-STURDIER ?
-jn-
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
[5/12] from: al:bri:xtra at: 6-Oct-2000 13:40
jn wrote:
> Nice choice of names...
Thanks, Joel.
> (but I MUST remember to ask you about the caps)
Why capitals? Here's the Transpose function again:
Transpose: function [
[catch]
"Transposes Matrices"
Matrix [block!]
][
Results Width Height Column
][
Results: make block! Width: length? Matrix/1
Height: length? Matrix
repeat Index Width [
Column: make block! Width
foreach Row Matrix [
insert/only tail Column Row/:Index
]
insert/only tail Results Column
]
Results
]
Note that every word that is defined here is in Title case. Also note that
every common word that's in Rebol like 'insert, '/only, 'length? etcetera
are in lower case. What's _important_ is signalled by the Title case words.
Here's Transpose again but in a sea of lower case.
transpose: function [
[catch]
"transposes matrices"
matrix [block!]
][
results width height column
][
results: make block! width: length? matrix/1
height: length? matrix
repeat index width [
column: make block! width
foreach row matrix [
insert/only tail column row/:index
]
insert/only tail results column
]
results
]
Can you _easily_ see if I've made a mistake? What are the important words?
> My real question here is this, if we collectively are going to build up a
small pile of useful extensions, would it be good to have some conventions
re defensive programming...
Don't bother with defensive programming. It's just more stuff to debug and
put right Put the [catch] attribute in and let the problem in the code be
caught as early as possible. I'd still use 'try around disk and net i/o, as
this makes sense. And the argument type specifiers are good as well.
> I assume your [catch] was a faster way of addressing this same issue, by
simply passing the error resulting from an empty argument list back to the
caller.
It's a whole lot simpler and catches the error earlier and it runs faster.
Andrew Martin
Look what happens when I go to sleep! :-)
ICQ: 26227169
http://members.nbci.com/AndrewMartin/
[6/12] from: al:bri:xtra at: 6-Oct-2000 13:48
Ted wrote:
> How about starting with Carl's style guide:
> http://www.rebol.com/users/scrstyle.html,
> and extending from there?
Rebol Crew wrote:
> The contents of a block are indented, but the block's enclosing brackets
[] are not. That's because the brackets belong to the prior level of syntax
as they define the block, but are not contents of the block. Also it's
easier to spot breaks between adjacent blocks when the brackets stand out.
I disagree with Carl's reasoning here, but I can cope with it. I prefer the
better human readable style like this example:
repeat Index Width [
Column: make block! Width
foreach Row Matrix [
insert/only tail Column Row/:Index
]
insert/only tail Results Column
]
Andrew Martin
Style Curmudgeon
ICQ: 26227169
http://members.nbci.com/AndrewMartin/
[7/12] from: lmecir:geocities at: 6-Oct-2000 23:46
Hi,
Andrew wrote:
> Why capitals? Here's the Transpose function again:
> Transpose: function [
<<quoted lines omitted: 18>>
> every common word that's in Rebol like 'insert, '/only, 'length? etcetera
> are in lower case. What's _important_ is signalled by the Title case
words.
[...snip...]
> > I assume your [catch] was a faster way of addressing this same issue,
by
> simply passing the error resulting from an empty argument list back to the
> caller.
<<quoted lines omitted: 4>>
> http://members.nbci.com/AndrewMartin/
> -><-
I would say, that your source is (as long as :make, :block!, :length?,
:repeat, :foreach, :insert, :tail are normal, unchanged natives) exactly
equivalent to the same function not having [catch] refinement, because there
is no Throw for it in the source.
Cheers,
Ladislav
[8/12] from: joel:neely:fedex at: 6-Oct-2000 17:00
This is clearly one of those "you say tomato, I say ketchup" issues.
Anyone who doesn't like ketchup on his steak (or steak under his ketchup)
is welcome to skip this post entirely!
-jn-
[Al--Bri--xtra--co--nz] wrote:
> Rebol Crew wrote:
> > The contents of a block are indented, but the block's enclosing brackets
<<quoted lines omitted: 10>>
> insert/only tail Results Column
> ]
I've always understood INdentation as showing what was IN something else.
Viewed strictly as a block (i.e. ignoring the fact that I think I know what
some of those words mean...) the example above has this shape to my mind's
eye (abbreviating a few places -- strictly for space -- and making explicit
an enclosing block...):
[*]
/----------^---------\
repeat Index Width [*]
/-------------------------------------------^------------------------\
Column: make block! Width foreach Row Matrix [*] append Results Column
/---------^---------\
append Results Column
(Those hyphens, carets, asterisks, slashes, and backwardslashes are
standing in for the nice pretty lines in my head...)
The top level block contains 4 things -- three words and another block.
That last block contains 11 things -- the eighth of which is another
block. etc... Notice that the contents are UNDER the brackets -- [*] --
that mark the boundaries of the block.
Of course, this horizontal layout is not going to work typographically,
especially in email, as my lists get longer. So we can rotate it to run
vertically. Unfortunately I don't have rotated brackets on my keyboard,
so I'll just have to use the same old more-or-less-vertical ones:
/ repeat / Column:
[ | Index | make
*-< Width | block!
] | [ | Width
| *------< foreach
\ ] | Row
| Matrix
| [ / append
| *-------< Results
| ] \ Column
| append
| Results
\ Column
Notice that the contents of a block are still under the brackets that
mark the block's boundaries (although logical "under" is now geometrically
to the right
). Of course all these overlapping columns of words and
lines are a little cluttered (even though more compact) so let's try to
declutter by putting contents between the boundaries of their blocks
(but still INdenting to make it clear that they are INside the blocks):
[
repeat
Index
Width
[
Column:
make
block!
Width
foreach
Row
Matrix
[
append
tail
Column
Row/:Index
]
append
tail
Results
Column
]
]
Now let's remember that we know what these "words" mean. If we do,
we'll tend to think of bigger units, perhaps called "phrases", that
group words into fewer, bigger chunks. If I do that, I'll have to
keep the first word of a new phrase back at the same level that
it had before I started "chunking", so I don't lose track of my
levels.
If one of these phrases includes a block, I may try to write it out
all at once. but if it doesn't fit, I'll try to pull the open brace
into the line with the rest of the phrase, but leave the content
indented with the closing brace "outdented" back to its own level
to make it clear that I've come back up/out a level in the structure.
[
repeat Index Width [
Column: make block! Width
foreach Row Matrix [ append tail Column Row/:Index ]
append tail Results Column
]
]
This also lets me work top-down/breadth-first into the structure,
only disclosing lower levels as I work my way down to them. To
my eye, an empty (or hidden) block is ONE thing even if it's written
with two keystrokes "[]". When I have to break the case open, I
put the two halves at the same level
Level 0 view ("outside"):
[]
Level 0 opening:
[
]
Level 1 revealed:
[
repeat Index Width []
]
Level 1 opening:
[
repeat Index Width [
]
]
...
Well, no point in beating this dead horse further -- the horse steak
is as tender as its going to get!
However, notice that (in the spirit of comprimise) I've tried to keep
the initial caps on Important Words! ;-)
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
[9/12] from: al:bri:xtra at: 6-Oct-2000 16:07
> This is clearly one of those "you say tomato, I say ketchup" issues.
Anyone who doesn't like ketchup on his steak (or steak under his ketchup) is
welcome to skip this post entirely!
This is religious war territory! :-)
I prefer a slightly modified form of:
begin-end Block Boundaries
from:
Code Complete by Steve McDonnell, chapter 18.3.
But it's up to people to choose their own style when they're fully informed.
And Rebol can put it's own style onto to 'mold-ed scripts.
Andrew Martin
Ayatollah of my indentation style...
ICQ: 26227169
http://members.nbci.com/AndrewMartin/
[10/12] from: lmecir:geocities at: 7-Oct-2000 1:09
Hi,
I don't think, that I can bring any theoretical reasons for preferring one
style over the other. I tried both. I must admit, that I liked the style
Andrew is evangelizing more and tried to use it exclusively. The difference
(for me) has shown itself when I wrote a script having six-page listing.
Then I found out, that the orientation in the script using enclosing bracket
indentation worsened drastically (for me) against its RT approved version.
That is why I am currently using the RT approved version and knowing, that
there is a good reason for it.
Cheers
Ladislav
[11/12] from: larry:ecotope at: 6-Oct-2000 18:07
Hi Andrew, Joel
I'll throw in one more implementation of transpose. Way back last January
and December, Gerald Goertzel and I wrote many routines for linear algebra
and matrix manipulation. We tested many versions of basic matrix functions
like add, multiply, transpose and inverse for speed. Jerry won the speed
contest for transpose with this function which assumes matrices are in the
form created by the ARRAY function. (row major order)
transpose: func [m /local r c mt] [
r: length? m
c: length? m/1
mt: array reduce [c r]
repeat i r [
repeat j c [
poke pick mt j i pick pick m i j
]
]
mt
]
Enjoy
-Larry
[12/12] from: jelinem1:nationwide at: 9-Oct-2000 9:38
>I disagree with Carl's reasoning here, but I can cope with it. I prefer
the
better human readable style like this example:
> repeat Index Width [
> Column: make block! Width
<<quoted lines omitted: 3>>
> insert/only tail Results Column
> ]
Why is this a better "human readable" format? I must not be human. Thanks
for pointing me to Carl's style guide, however. I find it interesting that
I've been using 4-char tabs and the same indentations for 10 years.
- Michael Jelinek
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted