REBOL 3 Docs Guide Concepts Functions Datatypes Errors
  TOC < Back Next >   Updated: 12-Aug-2010 Edit History  

REBOL 3 Functions: reduce

reduce  value  /no-set  /only  words  /into  out

Evaluates expressions and returns multiple results.

Arguments:

value

Refinements:

/no-set - Keep set-words as-is. Do not set them.

/only - Only evaluate words and paths, not functions

words [block! none!] - Optional words that are not evaluated (keywords)

/into - Output results into a block with no intermediate storage

out [any-block!]

See also:

compose   do   foreach  

Description

The reduce function evaluates multiple expressions and returns a block of results. This is one of the most useful functions in REBOL.

For example:

values: reduce [1 + 2 3 + 4]
probe values
[3 7]

Compare this with do, which only returns the result of the last expression:

values: do [1 + 2 3 + 4]
probe values
7

Part of other functions

The reduce function is important because it enables you to create blocks of expressions that are evaluated and passed to other functions. Some functions, like print, use reduce as part of their operation, as shown in the following example:

print [1 + 2  3 + 4]
3 7

The rejoin, repend, reform, remold functions also use reduce as part of their operation, as shown in the following examples:

rejoin ["example" 1 + 2]
example3
str: copy "example"
repend str [1 + 2] ; modifies (uses append)
example3
reform ["example 1 + 2]
example 3
remold ["example" 1 + 2]
["example" 3]

Ignored reduction

For convenience, expressions that are fully evaluated simply pass-through the reduce function.

reduce 123
123
reduce "example"
example

This makes it possible to use reduce in cases where other datatypes may be passed. For example, here is a common function for building HTML strings that relies on this behavior:

html: make string! 1000
emit: func [data] [repend html data]

emit "test... "
emit ["number is: " 10]
print html
test... number is: 10

Blocks with set-words

When you reduce blocks that contain set-words, those words will be set. For example:

a: 1
reduce [a: 2]
print a
2

There are times when you do not want this to occur. For example, if you're building a header for a file, you may want to leave the set-words alone.

The /no-set refinement can be used to handle this case.

full-name: "Bob Smith"
reduce/no-set [name: full-name time: now + 10]
[name: "Bob Smith" time: 15-Aug-2010/16:10:50-7:00]

Memory usage for large blocks

For most blocks you don't need to worry about memory because REBOL's automatic storage manager will efficiently handle it; however, when building large block series with reduce, you can manage memory even more carefully.

For example, it is common to write:

repend series [a b c]

which is shorthand for:

append series reduce [a b c]

The evaluated results of a, b, and c are appended to the series.

If this is done a lot, a large number of temporary series are generated, which take memory and also must be garbage collected later.

The /into refinement helps optimize the situation:

reduce/into [a b c] tail series

It requires no intermediate storage.

Common Problems

Although reduce will create a new outer block, all other series (blocks, strings, etc.) are referenced, not copied. If you modify those values, they will change in all blocks that reference them.

For example:

str: "name"
probe result: reduce [str]
["name"]
insert str "new-"
probe result
["new-name"]

You can see that it's the same string. To change that behavior use the copy function:

result: reduce [copy str]

or, for blocks that contain multiple strings or other values:

result: copy/deep reduce [str]


  TOC < Back Next > REBOL.com - WIP Wiki Feedback Admin