patternMinor
Interface and implementation of this replacement for Rebol/Red REJOIN
Viewed 0 times
thisrebolredinterfaceforrejoinandimplementationreplacement
Problem
This is a draft implementation of a function called COMBINE. It's not intended to be a complex formatting dialect, just a replacement for REJOIN that has a better name and more useful behavior. Its purpose is laid out pretty thoroughly in this blog entry:
http://blog.hostilefork.com/combine-alternative-rebol-red-rejoin/
But to make a long story short, it is supposed to let you flatten expressions into a string. If an expression returns a block, then that block will be recursively evaluated using the same rules as if it had been handed to COMBINE directly:
`combine: function [
{Combine evaluated expressions and substitute block variables to produce a string}
block [block!] "Specification to process"
/with "Add delimiter between values (will be combined if a block)"
delimiter [block! any-string! char!]
/into "Insert output into an existing string instead of making a new one"
out [any-string!]
/local
value
] [
;-- No good heuristic for string size yet
unless into [
out: make string! 10
]
if block? delimiter [
delimiter: combine delimiter
]
needs-delimiter: false
pre-delimit: does [
either needs-delimiter [
out: append out delimiter
] [
needs-delimiter: true? with
]
]
;-- Do evaluation of the block until a non-none evaluation result
;-- is found... or the end of the input is reached.
while [not tail? block] [
set/any 'value do/next block 'block
;-- Blocks are substituted in evaluation, like the recursive nature
;-- of parse rules.
case [
unset? :value [
;-- Ignore unset? (precedent: any, all, compose)
]
none? :value [
;-- Skip all nones
]
any [
function? :value
closure? :value
] [
throw make error! "Evaluation in COMBINE gave f
http://blog.hostilefork.com/combine-alternative-rebol-red-rejoin/
But to make a long story short, it is supposed to let you flatten expressions into a string. If an expression returns a block, then that block will be recursively evaluated using the same rules as if it had been handed to COMBINE directly:
`combine: function [
{Combine evaluated expressions and substitute block variables to produce a string}
block [block!] "Specification to process"
/with "Add delimiter between values (will be combined if a block)"
delimiter [block! any-string! char!]
/into "Insert output into an existing string instead of making a new one"
out [any-string!]
/local
value
] [
;-- No good heuristic for string size yet
unless into [
out: make string! 10
]
if block? delimiter [
delimiter: combine delimiter
]
needs-delimiter: false
pre-delimit: does [
either needs-delimiter [
out: append out delimiter
] [
needs-delimiter: true? with
]
]
;-- Do evaluation of the block until a non-none evaluation result
;-- is found... or the end of the input is reached.
while [not tail? block] [
set/any 'value do/next block 'block
;-- Blocks are substituted in evaluation, like the recursive nature
;-- of parse rules.
case [
unset? :value [
;-- Ignore unset? (precedent: any, all, compose)
]
none? :value [
;-- Skip all nones
]
any [
function? :value
closure? :value
] [
throw make error! "Evaluation in COMBINE gave f
Solution
Some thoughts:
Initialize String
Don't know how else to discern the initial string allocation, perhaps just start with zero?
OUT might be a strange word for a value that is both input and output. I'd also allow a NONE! value here.
Then you can initialize like:
Delimiter
Cool, a delimiter can be combined on the fly!
Rather than an extra function and an extra value for this, why not just an extra value:
Then set
Iteration
I'm not certain about this, but I believe FOREACH is faster than WHILE. This seems like an inefficient way of expressing:
Functions
Are you just testing for these two types of function? Otherwise ANY-FUNCTION? would catch both.
Throwing Errors
I don't think this works in Rebol 3, at least not without wrapping the function call in a CATCH block. As I understand it, you need to DO an error to trigger it.
Coerce Output Type
An /AS refinement might be a good way to do this, so long as the type is with the ANY-STRING! typeset. It'd be a close call as to whether /INTO or /AS would take precedence for output type:
None/Empty
My opinion here is:
Should return
Should return
Initialize String
unless into [
out: make string! 10
]
Don't know how else to discern the initial string allocation, perhaps just start with zero?
OUT might be a strange word for a value that is both input and output. I'd also allow a NONE! value here.
/input out [any-string! none!]
Then you can initialize like:
out: any [out make string! 0]
Delimiter
if block? delimiter [
delimiter: combine delimiter
]
Cool, a delimiter can be combined on the fly!
needs-delimiter: false
pre-delimit: does [
either needs-delimiter [
out: append out delimiter
] [
needs-delimiter: true? with
]
]
Rather than an extra function and an extra value for this, why not just an extra value:
active-delimiter: none
Then set
active-delimiter to delimiter after the first step through BLOCK.Iteration
while [not tail? block] [
set/any 'value do/next block 'block
...
]
I'm not certain about this, but I believe FOREACH is faster than WHILE. This seems like an inefficient way of expressing:
foreach value reduce block [
...
]
Functions
function? :value
closure? :value
Are you just testing for these two types of function? Otherwise ANY-FUNCTION? would catch both.
Throwing Errors
throw make error! "Evaluation in COMBINE gave function/closure"
I don't think this works in Rebol 3, at least not without wrapping the function call in a CATCH block. As I understand it, you need to DO an error to trigger it.
Coerce Output Type
An /AS refinement might be a good way to do this, so long as the type is with the ANY-STRING! typeset. It'd be a close call as to whether /INTO or /AS would take precedence for output type:
type: any [type string!]
out: any [out make type 0]
None/Empty
My opinion here is:
combine []
combine [none]
Should return
""combine/with [none none] ","
Should return
","Context
StackExchange Code Review Q#54466, answer score: 2
Revisions (0)
No revisions yet.