Clunky-looking code
[1/11] from: sanghabum::aol::com at: 2-Apr-2001 13:25
I'm trying to multiply respective elements of two blocks and get a single sum:
e.g.
[a b c] * [d e f] = a*d + b*e + c*f
I have no problem writing the code .... There are two versions of the
function listed below. But it looks irredeemably inelegant compared to almost
any other language I know .... I would not like to have to do matrix
operations in Rebol!
Am I missing some elegant way of running up two blocks in step?
;; ----- Method 1
MultiplyBlocks1: func [Block1 Block2 /local Sum ind]
[
sum: 0
for ind 1 Length? Block1 1
[
sum: sum + ((pick Block1 ind) * (pick Block2 ind))
] ; for
return sum
] ; func
;; ----- Method 2
MultiplyBlocks2: func [Block1 Block2 /local Sum]
[
sum: 0
Loop (Length? Block1)
[
sum: sum + ((first Block1) * (first Block2))
block1: Next Block1
block2: Next Block2
] ; loop
Return Sum
] ; func
;; ----- Example of execution
print MultiplyBlocks1 [1 5 10 25] [0 5 6 20]
print MultiplyBlocks2 [1 5 10 25] [0 5 6 20]
Thanks,
Colin.
[2/11] from: jelinem1:nationwide at: 2-Apr-2001 12:51
To write the most compact piece of code for performing this task one could
split some hairs and chop out a few chars here and there, but that does not
necessarily make it more readable/maintainable or better.
Despite the fact that this email will get like a zillion replies, here's my
2c. If you want to multiply two blocks, once, and have no need to get into
this sort of thing any more deeply, put your inelegant code in a function
(where it can elegantly be called) and get on with it. It you wish to use
the concept over again, and even expound on it, write a dialect. The
dialecting is the part that REBOL will excel at over other languages.
- Michael Jelinek
[Sanghabum--aol--com]@rebol.com on 04/02/2001 12:25:11 PM
From: [Sanghabum--aol--com]@rebol.com on 04/02/2001 12:25 PM
Please respond to [rebol-list--rebol--com]
Sent by: [rebol-bounce--rebol--com]
To: [rebol-list--rebol--com]
cc:
Subject: [REBOL] Clunky-looking code
I'm trying to multiply respective elements of two blocks and get a single
sum:
e.g.
[a b c] * [d e f] = a*d + b*e + c*f
I have no problem writing the code .... There are two versions of the
function listed below. But it looks irredeemably inelegant compared to
almost
any other language I know .... I would not like to have to do matrix
operations in Rebol!
Am I missing some elegant way of running up two blocks in step?
;; ----- Method 1
MultiplyBlocks1: func [Block1 Block2 /local Sum ind]
[
sum: 0
for ind 1 Length? Block1 1
[
sum: sum + ((pick Block1 ind) * (pick Block2 ind))
] ; for
return sum
] ; func
;; ----- Method 2
MultiplyBlocks2: func [Block1 Block2 /local Sum]
[
sum: 0
Loop (Length? Block1)
[
sum: sum + ((first Block1) * (first Block2))
block1: Next Block1
block2: Next Block2
] ; loop
Return Sum
] ; func
;; ----- Example of execution
print MultiplyBlocks1 [1 5 10 25] [0 5 6 20]
print MultiplyBlocks2 [1 5 10 25] [0 5 6 20]
Thanks,
Colin.
[3/11] from: rgombert:essentiel at: 2-Apr-2001 20:29
try :
MultiplyBlocks: func [
Block1 Block2
/local sum
][
sum: 0
repeat i min length? Block1 length? Block2 [
sum: sum + (Block1/:i * Block2/:i)
]
return sum
]
Renaud
[4/11] from: chris:arranfolkfestival at: 2-Apr-2001 14:36
Hi Colin,
> I'm trying to multiply respective elements of two blocks and get a
> single sum:
> e.g.
> [a b c] * [d e f] = a*d + b*e + c*f
This may be neater... Matter of opinion really.
multiply-blocks: func [
block-1 [block!]
block-2 [block!]
][
sum: make integer! 0
while [and not tail? block-1 not tail? block-2][
sum: add sum ((first block-1) * (first block-2))
block-1: next block-1
block-2: next block-2
]
return sum
]
Actually, its a fair bit longer than your suggestions - but it is an
alternative :o)
- Chris
[5/11] from: rgombert:essentiel at: 2-Apr-2001 21:09
It's also interesting to notice the relative speed of each function
(multiply 2 blocks of 15 integers):
multiply-blocs > 0:01:34.32
MultiplyBlocks1 > 0:01:46.32
MultiplyBlocks2 > 0:00:51.06
MultiplyBlocks3 > 0:00:38.46
Note that you don't need to explicitely use RETURN in your functions, since
the last value of the affectation is still availlable when Rebol exits the
loop.
MultiplyBlocks3: func [
Block1 Block2 /local Sum
][
sum: 0
repeat i min length? Block1 length? Block2 [sum: sum + (Block1/:i *
Block2/:i)]
]
Renaud
[6/11] from: brett:codeconscious at: 3-Apr-2001 10:20
> I'm trying to multiply respective elements of two blocks and get a single
sum:
> e.g.
> [a b c] * [d e f] = a*d + b*e + c*f
>
As you describe, you have two operations
1) Multiply the respective elements of two series.
2) Sum a series
> I have no problem writing the code .... There are two versions of the
> function listed below. But it looks irredeemably inelegant compared to
almost
> any other language I know .... I would not like to have to do matrix
> operations in Rebol!
I don't think Rebol was optimised as a language for doing matrix operations
and as far as I remember is no worse than any other language I know for this
type of operation - except for APL which I only experiemented in briefly.
As Michael Jelinek points out the best way to make it look elegant is to
code up your functions and call them. Functions effectively extend the
language to make it more expressive and perhaps elegant.
If you could assume things about your blocks then you can do the following:
vector-multiply: function [a b][result][
if not equal? length? a length? b [throw "Only accepts vectors of
the same size."]
result: array reduce [length? a]
for i 1 length? a 1 [
poke result i multiply a/:i b/:i
]
RETURN result
]
vector-sum: function [a][result][
result: 0
for i 1 length? a 1 [result: add result a/:i]
RETURN result
]
And therefore more elegantly code in you main function:
vector-sum vector-multiply [2 3 5] [3 5 7]
Next option would be to use Ladislav's %highfun.r script
(http://www.rebol.org/advanced/index.html). There you will find functions
that will make this work more elegant, or a technique to make the functions
I've shown more generic.
Last alternative is to ask RT really really nicely if they would consider
changing the semantics of "multiply" in order to accept two blocks and of
add
to accept a block to sum. But they could only go so far - at some
point such changes will conflict with pre-existing functionality/semantics.
Brett.
---
http://www.codeconscious.com
[7/11] from: sanghabum:aol at: 3-Apr-2001 19:00
Thanks Renaud,
<Renaud>
MultiplyBlocks: func [
Block1 Block2
/local sum
][
sum: 0
repeat i min length? Block1 length? Block2 [
sum: sum + (Block1/:i * Block2/:i)
]
return sum
]
</Renaud>
What was missing from my knowledge was how to reference a block using a
variable (pardon my non-Rebol terminology) ..... When I'd tried things like
Block1/Ind I got told that was a bad path. Your little colon makes all the
difference.
<Renaud>
Note that you don't need to explicitly use RETURN in your functions, since
the last value of the affectation is still available when Rebol exits the
loop.
</Renaud>
True for MultiplyBlocks1. But MultiplyBlocks2 does need an explicit return,
at least on my machine. And, maybe it's a matter of style, but I'd rather
have an explicit return: it helps a stranger's eye when looking at code. It
also means I can add debugging code without breaking assumptions.
<Renaud>
It's also interesting to notice the relative speed of each
function (multiply 2 blocks of 15 integers):
<snip>
</Renaud>
I've changed my code to your "block/:i" format. It knocks 15% of the
application run time. A worthwhile improvement indeed.
<Brett>
Next option would be to use Ladislav's %highfun.r script
(http://www.rebol.org/advanced/index.html). There you will find functions
that will make this work more elegant, or a technique to make the functions
I've shown more generic.
</Brett>
Thanks for this reference. I certainly don't want to spend my life
reinventing the wheel, and especially not clunky wheels
<Michael>
To write the most compact piece of code for performing this task one could
split some hairs and chop out a few chars here and there, but that does not
necessarily make it more readable/maintainable or better.
</Michael>
I wasn't trying to write the shortest possible code. But I like to think that
I write code that is easy to follow. Which is why the PICKs and FIRSTs in my
two samples niggled. They cluttered a function that ought to be simple. Call
it programmer's intuition, but I knew there must be a better way. But my
RTFMing skills had failed to find it.
Thanks for all the help guys. I think I am beginning to get the hang of this
language!
Colin
[8/11] from: athena:pop3-dfw:myfirstlink at: 7-Apr-2001 9:16
Can someone explain exactly what this code is doing? I'm confused by
this usage of ":" and its relationship to a block.
[Sanghabum--aol--com] wrote:
[9/11] from: rgombert:essentiel at: 7-Apr-2001 16:56
Not too difficult...
the function take 2 blocs of numbers, say [2 3 4] and [3 4 5 6], and return
the sum of the corresponding terms in each bloc, i.e. : 2*3 + 3*4 +4*5 +
(0)*6
the code :
repeat i min length? Block1 length? Block2 [...]
is used to loop i from 1 to the size of the smaller block, and then :
Block1/:i is similar to "pick Bloc1 i", and so is looped as Bloc1/1
when i=1, Block1/2 when i=2 and so on...
Hope that answer to your question ;-)
Renaud
[10/11] from: gjones05:mail:orion at: 7-Apr-2001 10:01
From: "Harold Grovesteen"
> Can someone explain exactly what this code is doing? I'm confused by
> this usage of ":" and its relationship to a block.
<<quoted lines omitted: 13>>
> > ]
> > </Renaud>
Hi, Harold,
Using the colon before a word retrieves its value. In the case where it is
used as a part of a path, then the value serves as an index.
A different example:
a: [cat dog]
:a ;returns the value of the word a, which is the block
a/1 ;returns cat
i: 1
a/:i ;returns cat
Hope this helps.
--Scott Jones
[11/11] from: athena:pop3-dfw:myfirstlink at: 8-Apr-2001 12:26
Thanks, Did not understand this aspect of "paths".
Harold Grovesteen
GS Jones wrote:
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted