AltME: Rebol School

Messages

Ladislav
I quoted you using cut and paste, so I do not know what you are talking about.
Also, it is you who is criticinzing the documentation while proving you haven't read it
DocKimbel
You wrote: "The specification [...] does not define the argument as a lit-word." This is a strawman, this is not what I said. But as usual, talking to you is like talking to a brick wall. Your condescendence gets in the way of any normal discussion.
Ladislav
Ok, if you insist, I can adjust the wording:
Using the specification
start: func ['block-name] ...
you do not not define the argument as a lit-word. Instead (see the documentation) you specifiy that literal argument passing shall be used, passing words literally (without getting their value).
Note that what I adjusted is not the citation, though. That remains valid.
DocKimbel
You're still misunderstanding my sentence. I was giving instructions to PatrickP61 to change the word argument in the specification to a lit-word argument. That's all. My sentence has nothing to do with how you interpret the specification block once that change has been done.
PatrickP61
My thanks to all.  My intention was not to start any flame wars!
Ladislav
Why do you think you did?
Bo
Ladislav does not mince words.  Everyone here knows that, so we come to expect it. :-)

GiuseppeC
I have a question on Foreach:
foreach [a b] [1 2 3 4 5 6]  [
    mycode
]
how do I know in "mycode" if I am at the last couple of the serie ? (Even the knowing if I am at the start could be useful)
DocKimbel
If you need such info in the loop body, you should use FORALL instead.
GiuseppeC
But in forall I can use only one word as first argument
I have a peseudo DB and I need the extract data in groups
GiuseppeC
I suppose it is better if I use a for loop like
for idx 1 lenght? series fields-number [
    a: series/(idx*1) a: series/(idx*2)
]
And check the position.
sorry:
for idx 1 lenght? series fields-number [
    a: series/(idx*1) b: series/(idx*2)
]
And check the position.
DocKimbel
With FORALL it's much simpler, FOR is not necessary:
forall series [
    set [a b] series    ;-- a and b are set to the first two elements
    ...your code...
    series: next series ;-- advancing series by one to account for the 2nd element    
]
FORALL will already advance the series by one position when looping, so you just need to manually skip the extra element that you read with SET.
GiuseppeC
Lets assume we have 8 fields:
numfields: 8
forall series [
    set [a b c d e f g h i ] series
    series: skip series numfields  - 1
]
Is it right ?
DocKimbel
Exactly.
GiuseppeC
Thanks doc !
DocKimbel
You can also do it with FORSKIP which will do the series advancement for you:
forskip series 8 [
    set [a b c d e f g h i ] series
    ...
]
GiuseppeC
... retaining the ability to read the series index ...
DocKimbel
Yep. Now, you know how to use both FORALL and FORSKIP. The advantage of FORALL is that it lets you have full control over how to process the series. FORSKIP is more convenient when you need to process the series with fixed sized records.
GiuseppeC
In fact I will use Forskip as I am processing a DB like series.
DocKimbel
Looks like the best option for your use case.
amacleod
Simplest way to remove a block from a block of blocks?
a: [[A] [B] [C]]
== [[A] [B] [C]]
>> remove third a
== []
>> a
== [[A] [B] []]
...but I want the block removed too!
Josh
>> a: [[A] [B] [C]]
== [[A] [B] [C]]
>> third a
== [C]
(that is a hint)
>> head remove next next [[A] [B] [C]]
== [[A] [B]]
Gregg
As Josh hinted, THIRD is returning the third element, which REMOVE then operates on. You'll want to use AT, or something, to remove the element. e.g.
>> a: [[A] [B] [C]]
== [[A] [B] [C]]
>> head remove at a 3
== [[A] [B]]
>> a: [[A] [B] [C]]
== [[A] [B] [C]]
>> head remove find/only a [c]
== [[A] [B]]
amacleod
head remove find/only a [c]
this is exactly what I need....
"at" ...new to me!
Thanks all!
Greg,
remove find/only a [c]
seems to work too, without head...
Gregg
Yes, as long as you don't need the result to be at the head.
>> a: [[A] [B] [C]]
== [[A] [B] [C]]
>> remove find/only a [c]
== []
I just included HEAD to make the result clear in this case.
amacleod
I see...I would want that result with head...thanks

GiuseppeC
Hope there is someone here in the morning as I need quick help:
Hope there is someone here in the morning as I need quick help:
GiuseppeC
I have a variable:
mycode: "CODE1"
I need to check  if exist a series named CODE1
If it does not exist create a series called CODE1
append to CODE1 (taken from mycode) something.
PeterWood
Is this any help?
>> value? 'mycode
== false
>> mycode: []
== []
>> value? 'mycode
== true
Something like this, if I understood what you are trying to do properly:
>> if not value? to-word mycode [set to-word mycode [something]]
== [something]
>> CODE1
== [something]
That will create CODE1 in the global context though.
GiuseppeC
I have tried also:
value? get first [mycode]
Lets assume mycode is: CODE1
I whish to create a series whose name as I would write:
CODE1: copy []
Sorry
I whish to create a series whose name is CODE1. Se the code should dinamically take it from MYCODE and execute a line like: CODE1: copy []
GiuseppeC
I don't know if it is the correct way:
mycode: "ONE"
do rejoin [get first [mycode] ":" " copy []"]
type? ONE
== block!
sqlab
do reduce [to-set-word mycode copy []]
GiuseppeC
How do I check if ONE has been set to SERIES dynamically ?
type? reduce [mycode]
does not work
GiuseppeC
Here some code is making me crazy:
>> mycode: "ABC"
== "ABC"
>> do reduce [to-set-word mycode copy []]
== []
>> type? ABC
== block!
>> type? get first reduce [to-word codice-temp]
== block!
>> [type? get first reduce [to-word codice-temp]] <> block!
== true
The last one should be FALSE
Ops,
[type? get first reduce [to-word codice-temp]]
should be:
(type? get first reduce [to-word codice-temp])
Now seems to be solved.
GiuseppeC
Following your code
codice-temp: "C001"
do reduce [to-set-word codice-temp copy []]
how do I check dynamically if the series C001 has been created ?
I have tried this
> type? get first [codice-temp]
== string!
But as you see it does not work
sqlab
type?  get to-word codice-temp
sqlab
better to use
do reduce [to-set-word codice-temp 'copy []] or you will
always produce two copies
sorry I just have an non ergonomic keyboard
so
do reduce [to-set-word codice-temp 'copy []]
type?  get to-word codice-temp
GiuseppeC
Thanks, I am exploring dynamic table view creations with my small REBOL knowledge

sqlab
a shorter solution is
set to-word codice-temp copy []

PeterWood
Is this method of providing "private" words in objects reliable?
>> a: make object! [ b: 1 set-b: func[v] [b: v] get-b: func[][b]]
>> o: make object! [set-b: get in a 'set-b get-b: get in a 'get-b]
>> unset 'a
>> o/get-b
== 1
>> o/set-b 2
== 2
>> o/get-b
== 2
Maxim
in R3 yes.. in R2 its almost impossible since you can always get a function's body.
but I prefer this pattern:
>> o: get in context [
[     priv: 1
[     pub: context [ set-b: func[v] [priv: v] b: func[][get 'priv]]
[    ] 'pub
>> o/b
== 1
>> o/set-b 2
== 2
>> o/b
== 2
>> words-of o
== [set-b b]
actually, replace this line in the above:
pub: context [ set-b: func[v] [set 'priv v] b: func[][get 'priv]]

MGilsanz
Can anyone explain  this:
MGilsanz
>> a: 33 * 0.939393939393939
== 31.0
>> b: 31.0
== 31.0
>> to-integer a
== 30
>> to-integer b
== 31
>>
Oldes
http://floating-point-gui.de/
in R3:
>> 33 * 0.939393939393939
== 30.999999999999986
R2 is hiding these details

caelum
Is there a way to preserve the modification date of a file when copying to a new destination using 'write'? As in:
        write/binary dest/:file read/binary source/:file
This produces a modification date of now().
        print modified? 29-Jun-2014/17:02:56-7:00
In the 'Write Function Summary' I do not see any Refinement to preserve the existing modification date. Is there a way to do this?
sqlab
http://www.rebol.org/ml-display-thread.r?m=rmlFDPC
set-modes %afile [modification-date: 12-May-2004/0:00:00+10:00]
Yoi have to manually set the date  of the new file to the date of the old file
Gregg
touch: func [
    {Set the modification timestamp of the file.}
    files [file! block!] "The file, or files, you want to stamp"
    /with "Use a specified time rather than the current time."
        time [date! file!] "The date and time to stamp them with"
    /local read-only?
][
    if not with [time: now]
    if file? time [time: modified? time]
    ; Do we want to do this?
    if 0:00 = time/zone [time/zone: now/zone]
    ; We have to turn off the read-only attribute if it's on.
    foreach item compose [(files)] [
        read-only?: not get-modes item 'owner-write
        ;print ['touching item 'with time]
        set-modes to-file item [owner-write: true modification-date: time]
        if read-only? [set-modes item [owner-write: false]]
    ]
    ; Should we return the time, even though it may not match the actual
    ; stamp on the files due to OS differences?
    ;time
]

caelum
Thanks Gregg and sqlab. Exactly what I was looking for.

caelum
This works fine:
    print get-modes %/path-to-file/filename [modification-date]
But this:
    print get-modes ftp://username@example.com:password@ftp.example.com/filename [modification-date]
produces the following error:
    Script Error: get-modes expected target argument of type: file url block port
    ** Near: system/words/get-modes port/sub-port modes
Does get-modes work over an ftp connection?

GrahamC
Don't think you can do anything except delete, upload and download.
the rebol3 protocol might give you more things you can do.

Reichart
I decided to post this here, since this is the closest topic.
Ever lose your glasses (and they are on your head), or lose your car keys (and they are in the door)?
Many many years ago I wrote a REBOL program that was self modifying.  It also checked to see if it could run, and revert and tell you what went wrong.
I do have a copy of this, but I don't have access to my head or door knob, er, I mean I don't have access to the harddrive (which is in a safe in another state) right now.
I'm hoping someone here has a copy of my old program, I want to show it to a friend I'm teaching REBOL to.

Gregg
I'm pretty sure I don't have it.
Maxim
I've never seen it.
PeterWood
You asked the same quesiton on 26th Jan 2012 on the REBOL3 World.
PeterWood
Endo
I nevet heard of it, but looks cool.

Reichart
Peter, yup, sometimes asking more than once gets a result, never know.
I know where I have a copy of it, but I have to dig into a safe and then pull some old drives out.

Endo
Just for the record: I've added Turkish chars support in pdf-maker.r (Gabriele's script),
I downloaded www.opensource.apple.com/source/vim/vim-44/runtime/print/cp1254.ps file and added Turkish chars from there to
/Differences [...]
If anyone need more info you can write me PM.

Arnold
Can a header be combined for a Red and a REBOL script:
Red [
REBOL[] ;] ; would this work??
Oldes
I don't think so, but this could:
REBOL [] Red [] print "hello"
(not tested)
Maxim
rebol ignores everything preceding the REBOL [  ]   for sure... in theory, Red should be doing the same thing.

Marco
Maxim
just for the record though, only one language at a time can load that script.   (you need to comment out the language you want to use )
Bo
Actually not.  This works in Rebol or Red:
RED []
rebol: none
REBOL []
print "This is a test"

Arnold
Thank you Bo! Very clever. Just to be sure use Red [] and not RED []

Reichart
What is the smallest simplest example script for "port" .  
Hopefully something that shows off how easy it is to connect two computers and send information back and forth.  Perhaps a file.  Although a message system is ok too of course.
Gregg
Something like this? Run once as server, then again as client.
role: ask "Run as [C]lient or [S]erver? "
; Server
if role = "s" [
    port: tcp://:9090
    server: open/direct/no-wait port
    wait server
    client: first server
    print "Client connected."
    forever [
        wait any [client .01]
        if msg: copy client [
            print [now/precise msg]
            insert client "pong"
        ]
    ]        
]
; Client
if role = "c" [
    port: tcp://127.0.0.1:9090
    server: open/direct/no-wait port
    forever [
        insert server "ping"
        if msg: copy server [
            print [now/precise msg]
        ]
        wait .1
    ]
]
halt
Or there are slightly more involved examples out there. Like http://www.rebol.net/cookbook/recipes/0028.html
The WAITs in mine aren't needed, just there to slow things down a bit for human consumption.
Reichart
In these examples, it is assuming a server and a client, as opposed to two clients, and then a way to get them to find each other?
Maxim
either attempt[port: open tcp://:33101] [
    print "Running as server^/----^/"
    forever [ probe copy client: first wait port   close client]
][
    print "running as client^/----^/"
    forever [ insert (server: open tcp://localhost:33101) ask "message to send: "  close server]
]
a much simpler server/client example...
am building a google wave equivalent peer to peer example using console port... should be ready in a few minutes

Maxim
almost done, but I've got an errand to do, will be back with the solution in about 1h30
Reichart
:)
Maxim
I had a LOT of fun building this... its not perfect (backspace and delete cannot function in this mode cause I am not storing the console's screen buffer, but it goes a long way with just 40 lines... the vast majority of the code is actually managing the console's low level port interface.
rebol []
either attempt [lcl-port: open/lines tcp://:33101] [
    rmt-port: 33102
][
    lcl-port: open/lines tcp://:33102
    rmt-port: 33101
]
con: open/binary [scheme: 'console]
remote-port: none
digit: charset "0123456789"
forever [
    p: wait [lcl-port con]
    either p == con [
        key: first con
        either key = 27 [
            read-io con io: head clear "" 3
            cmd: copy "K [27 "
            foreach c io [ append cmd to-integer c append cmd " "]
            append cmd "]^/"
            chars: join "^[" io
        ][
            cmd: rejoin [ "K " key "^/" ]
            chars: to-char key
        ]
        
        insert ( rp: open rejoin [tcp://localhost: rmt-port] ) cmd
        close rp
    ][
        cmd: first first lcl-port
        parse cmd [
            "K " here:
            "[" (chars: to-string to-binary load here)
            
            | ( chars: to-char load here )
        ]
    ]
    prin chars
]
basically, store the script and run it twice,  both consoles are linked as if you where typing in anyone of them.  type in any of the two, and the other types the same thing!
we could modify the script a little to make it work across two different machines.  in that case, instead of changing the port number, we'd change the remote ip address instead.
DocKimbel
Instead of:
    insert ( rp: open rejoin [tcp://localhost: rmt-port] ) cmd
    close rp
you could use simply:
    write rejoin [tcp://localhost: rmt-port] cmd
Gregg
That's very cool Max.
Reichart, you just asked for smallest and simplest. :-)
Maxim
doc, yeah, true, I forgot we could use write on tcp ports.
for those who did not try the above script... do it (in 2.7.8) its pretty fun.
Reichart
"we could modify the script a little to make it work across two different machines.
That is the KEY, add that :)

Gabriele
Arnold
Johnk replied pointing to so chat, where my answer is too. Not going to subscribe to yet another site, there's too many already.
I have another nice question. I have 6 integers from 0 to about 23000 and I like to hash these. I calculated the 6 integer would fit into 96 (3 x 32 bit) bits. Any FUN ideas on howto do this?
Gregg
What is the context and the goal?

Arnold
The context is creating a Chinese chess game. I divided the board into 6 equal pieces and use the fieldcode and piece to calculate a number, I took some precautions that should make it unique. For the startposition the values are hash-1: 1508 hash-2: 2232 hash-3: 1508 hash-4: 1802 hash-5: 2293 hash-6: 1802, When I calculate for a maximally filled area there is an upperbound of approximately 23000. But I think in practice it could always be under 8000.
I could have gone the easy path and copy existing C programs using the bitboards and corresponding Zobrist hashing functions. But the easy path is boring and leads nowhere too ;-) So I decided to play around & find out an alternative way.
Arnold
I will have to shuffle my multiplication factors a bit more for now a black king of value 129 can be placed on a field with factor 115 giving 14835, that is a bit too much of a good thing :-)
Arnold
Placed a file in Rebol-school folder. You can see the board with pieces and a multiplication table that is the original field number multiplied with prime factor 3, 5, 7 and 11 for columns 2, 3,4 and 5. After that it is mirrored and reshuffled a bit to the other 5 sixths.
Maxim
Reichart, revised script with setup for two hosts.  all you need to setup the host names. if machines are on the same intranet, just their local host name should be ok.
rebol []
;-------
; note:  app must be launched on hosts in the order they are given here (this is a quick demo)
;
; replace foo & bar with hosts, or use localhost in both to launch both on a single host.
;-------
host-A: tcp://foo:33101
host-B: tcp://bar:33102
spec-A: net-utils/url-parser/parse-url ( context [url: host-A  host: port-id: none  serv-url: does[rejoin [tcp://: port-id ]]] ) host-A
spec-B: net-utils/url-parser/parse-url ( make spec-A [url: host-B] ) host-B
; try to connect to first host as client... if not available, then we are first host
either (attempt [ rmt-port: open host-A  close rmt-port true ])[
    lcl-spec: spec-B
    rmt-spec: spec-A
][
    lcl-spec: spec-A
    rmt-spec: spec-B
]
    
lcl-port: open/lines lcl-spec/serv-url
rmt-port: rmt-spec/url
print rejoin ["'" lcl-spec/host "' serving shared terminal on port: " lcl-spec/port-id]
con: open/binary [scheme: 'console]
remote-port: none
digit: charset "0123456789"
forever [
    p: wait [lcl-port con]
    chars: ""
    either p == con [
        key: first con
        either key = 27 [
            read-io con io: head clear "" 3
            cmd: copy "K [27 "
            foreach c io [ append cmd to-integer c append cmd " "]
            append cmd "]^/"
            chars: join "^[" io
        ][
            cmd: rejoin [ "K " key "^/" ]
            chars: to-char key
        ]
        
        insert ( rp: open rmt-port ) cmd
        close rp
    ][
        conn: first lcl-port
        if  (cmd: pick conn 1) [
            parse cmd [
                "K " here:
                "[" (chars: to-string to-binary load here)
                
                | ( chars: to-char load here )
            ]
        ]
    ]
    prin chars
]
Reichart
....that is very nice.  I will set up a second computer soon to play with this.
Next step, get them talking outside the net.    
The reason this "seed" of code is important, is once people see how truly easy this is, there are hundreds of cool little tools that use this as a base.
Gregg
It looks like they should already talk to any machine Reichart. Just config the names in Host-A/B.
Maxim
yep exactly.  you can put any hostname or ip address.  as long as dns resolves it you can reach it.
Gregg
Arnold, thanks for the info. Since I know nothing about Chinese Chess, I still don't know what the exact criteria are, so won't have any great suggestions. e.g., criteria being: given an integer of 0-23000, return a result that is <between M and N, and is otherwise totally random> .
Arnold
I know nothing about it too, I have bought a set say 20 years ago, never played. Since Doc is now in China and I did a checkers game in Rebol before, it looked like a nice challenge doing it the Rebol way.
Reichart
Indeed, i was speaking to the UI.  Making it for example so that your IP pops up, and you can tell that IP to another computer.
I have been working on a "trick" to get through firewalls and get two clients talking "without" a thrid party server.
It would use a third party of course, it would just be ...........well, using a trick so no one needs to pay for it and it is fast.

Cyphre
I believe it is possible to do do NAT UDP hole puching uisng pure R2. Couple years ago I tried that  just for fun and it sort of worked, but I haven't made any deep tests after that.
Gabriele
yes, i was doing things like that while playing with Chord in 2004
Pekr
Reichart - back at the time, I created one script for my friend. He had some HW device, sending data, and wanted to store the data into files. So I created kind of multiserver, which is able to gather data from multiple clients, and store it in separate files. You can find it in Folders/pekr
Reichart
Richard, exactly!
Perk - cool, I will take a look at that.
Here is a note a friend of mine just posted:
"STEM, CS, and couples therapy (!) musings: I had a teacher once explain to me that learning a foreign language was a way of thinking differently.
I have always applied this to computer languages, too.
The past few weeks I've been relearning/finally understanding a language I was introduced to about a decade ago. In a way, the language itself isn't important, rather the shift in thinking required for me to produce code that worked the first or third time  is what I want to focus on.
The language is, I believe, my first functional language and I quickly learned that the techniques for picking up a new programming language that I have always used, would not work here. I kept encountering weird and inscrutable errors.
So I went back to square one again and again and again, reading the docs, looking at code, and finally opening my mind to what was being said instead of what I thought was being said.
It's a skill usable in all aspects of life, to listen rather than interpret or, worse, assume.
Couples therapy, alluded to earlier, is really shorthand for clear communication. It is so easy, when you have a close and long-term relationship with someone, to think you know what they are telling you, so much of couples therapy, IME, is about letting go of what you think your partner is saying and to listen to what your partner is saying instead. I am thinking that this programming languages metaphor may be helpful for various friends in their own clear communication challenges.
So, thank you Mr. Locke, for teaching me the importance of language and thought, and thank you Reichart, for being the final push I needed to jump back into Rebol and not only gain a really useful skill that I need now more than ever (application #3 is being written, this one is client/server  but also for this useful insight about communication, presumption, and partnership."
Pekr
Reichart - you might also look into Rebol wiki - there is a section called Other Sections, where TCP port related stuff is placed. There is a chapter called TCP port examples. Just not sure, if it works with latest of R3 releases though - http://www.rebol.net/wiki/Table_Of_Contents
Pekr
They guy put it all into a nice perspective. Good read!

Marco
Is there a way to reset the internal state(s) of R2 (clearing all new words and objects) so that it will be in the same state as if it were just started?
Arnold
I ran into this quite a few times. That would be very helpfull.
Gregg
What is the problem you're trying to solve Marco?

Gabriele
the old (~2000) rebol apache module did that. that's why QUERY on objects was introduced (QUERY on SYSTEM/WORDS then reset all changed words). I don't remember if librebol did that natively (i think so) or at the mezz level. i don't think there is an easy way to do it at the mezz level in the general case, however, it may be easy in your specific case.

Arnold
One of the things to consider is that you can theoretically redifine pretty much everything you have in Rebol. (In practise I tend not to redefine function that come with the system, but it can be done) Restarting Rebol is the only way to be sure all is back to normal/original state.

Geomol
To get around this, in many scripts I enclose all my code within:
context [
...
]
It solves many situations.
Henrik
Same here

Marco
The situation that happens to me is simply that after a while that I am writing something in the console or in my mini-edit-do.r I start to forget that I have (already) assigned values to a variable and things start to appear strange and so it takes a little to relize that those variables simply already have a value.

Geomol
In that situation, I quit and relaunch REBOL. I use a shell script to launch REBOL into the console. The script is:
cd /Users/john/rebol/view/
./rebol --noviewtop
Maybe it is possible to do something clever with the REBOL LAUNCH function!?
Gregg
LAUNCH (and RUN) were problematic in the past, but you can do the same thing with system/options/boot and CALL. One catch is if you may run encapped or not. A lesson for Redbol is making header info universally available for consistent access.

Marco
I am trying to write a function to replace find/any with parse and I have done this:
    find-any: func ["Finds a value in a series using wildcards and returns the series at the start of it."
        series [series!] value /local elem pos
        ][
        value: copy value
        while [find value "**"] [replace/all value "**" "*"]
        replace/all value "*" ":*:"
        replace/all value "?" ":?:"
        value: parse value ":"
        remove-each elem value ["" = elem]
        replace/all value "*" 'thru
        replace/all value "?" 'skip
        value: compose/deep [any [to (first value) pos: (value) to end | thru (first value)] ]
        either parse/all series value [pos][none]
    ]
Could you please give it a try and tell me if it works and how to improve it?
Gregg
Is your goal to emulate find/any's behavior, or more to learn parse? I have a LIKE? func that does similar pattern matching, generating parse rules from a simple pattern grammar. Replace is a concise, if not the most efficient, way to break things up, and you handle compressed * runs as well, whcih is nice.
It doesn't work if * is the first or last thing in your pattern.

Gabriele
I think it will also fail if your pattern has colons in it.
Gregg
Good point Gab.

Marco
I found like.r and I will investigate it, thank you.

Marco
After investigatin like.r this is my second try:
    find-any: func [
        "Finds a value in a string using wildcards and returns the string at the start of it."
        series [series!] value [string!] /match /last
        /local str give_head emit pos pos2 non-wild-chars plain-chars tmp rule
        ][
        last*: get 'last
        give_head: none
        str: copy to string! series
        value: copy value
        if empty? value [return none]
        ; normalize pattern
        while [find value "**"] [replace/all value "**" "*"]
        while [find value "*?"] [replace/all value "*?" "*"]
        if value = "*" [return series]
        if last [
            value: reverse value
            str: reverse str
        ]
        if #"*" = first value [
            remove value
            if not any [last match] [give_head: series]
            match: none
        ]
        emit: func [arg][append rule arg]
        non-wild-chars: complement charset "*?"
        plain-chars: [copy tmp some non-wild-chars (emit copy tmp)]
        rule: copy []
        parse/all value [
            some [plain-chars | "*" (emit 'thru) | "?" (emit 'skip)]
        ]
        ; If the last thing in our pattern is thru, it won't work so we
        ; remove the trailing thru.
        if 'thru = last* rule [remove back tail rule]
        value: compose/deep [any [(all [none? match 'to]) (first rule) pos: (rule) pos2: to end | thru (first rule)] ]
        if none? parse/all str value [return none]
        if last [pos: skip series (length? series) - (index? pos2) + 1]
        any [give_head pos]
    ]
Perhaps still not perfect but should work in most cases.
Gregg
Sometimes I'll include a sampling of test cases, so people can see what's covered, and quickly try functions out.

Gabriele
I don't think that:
    last*: get 'last
does what you expect it to do. You probably want:
   last*: get in system/words 'last
Though, since I think you only use last* once, it may be easier to just replace last* with system/words/last, like:
    if 'thru = system/words/last rule [...]
Steeve
Hi, it's been a while since I talked here (2 years ?)
Do you know  if there is a better way to code this function  ?
extend-mask: func[i][
    ; set bits at the right of the MSB
    ; used to control if joining ADD operations together
    ;   is allowed by their prefixed casting operation (and MASK).  
    ; e.g. 00100100 => 00111111
    ; Sorry if it's ugly since REBOL does not have a native for that.
    ; Well, the utility is rare, except when you write a code optimizer.
    int(2 ** (int (log-2 i) + 1) - 1)
]
(int) is a shortcut fot to-integer
Steeve
I don't want to use a  precompiled array as a solution, the speed is not a problem... (currently)
Gregg
No quick suggestions here, but it's nice to see you again.
Geomol
Some ideas, but yours seem to be faster:
extend-mask: func [
    i
][
    i or either i > 0 [extend shift i 1] [0]
]
extend-mask: func [
    i
    /local r
][
    r: i
    while [0 < i: shift i 1] [r: r or i]
    r
]
hm, *extend* should be extend-mask in first one.
so a recursive

Gabriele
If speed is not a problem, then your version is probably the best choice.
If speed becomes a problem and you want to avoid floating point, there is a faster version of what Geomol proposed:
func [i] [
    i: i or shift i 1
    i: i or shift i 2
    i: i or shift i 4
    i: i or shift i 8
    i or shift i 16
]
You need an extra line if you are using R3 and 64 bits integers.
Geomol
That's neat, Gabriele!
It seems, Steeve only need the function to work on 8 bits at a time, so this is faster!
extend-mask: func [i] [i: i or shift i 1 i: i or shift i 2 i: i or shift i 4]
DideC
With Steeve func optimized, it's as fast as Gabriele's one on 8 bits :
extend-mask: func [i] [to integer! 2 ** (1 + to integer! log-2 i) - 1]

Gabriele
In REBOL's case the interpretation overhead is probably much bigger than the floating point operations.

Steeve
Hi, playing with perf measures today.
It comes that calling a function vs. inlining it gives a +20%  speed overcost in my R3 version.
And you people ?
>> f: does [1 + 1]
>> comp 1000000 [1 + 1][f]
core 2.100.111.3.1 Windows win32-x86 20-Feb-2011/16:24:43
[1 + 1]
0:00:00.131209
[f]
0:00:00.15853
== 20% (on average)
I should add that I run REBOL with WINE on Ubuntu 32 bits.
Here the mezz I used for:
perf: func [n [integer!] b [block!] /local t] [
    bind b 'n t: stats/timer
    repeat i n [n: i do b] stats/timer - t
]
comp: func [n [integer!] a [block!] b [block!] /ref][
    print reform bind [product version platform build] rebol
    ref: perf n [] ; time reference for empty code block
    a: to-decimal probe abs (perf n probe a) - ref
    b: to-decimal probe abs (perf n probe b) - ref
    to-percent (to-integer b - a / a * 100) / 100
]
Gregg
[1 + 1]
0:00:00.04964
[f]
0:00:00.091698
== 84%
Atronix 64-bit on Win7.
Steeve
Did you run it sevearl times  just to be sure ?
the overhed seems huge. An explication ?
*overhead
perhaps you should raise the number of iterations. If it's too low for your cpu power. There is more variance in  the measures
Gregg
Yeah, could be something funny:
>> comp 1000000 [1 + 1][f]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[1 + 1]
0:00:00.043496
[f]
0:00:00.06899
== 58%
>> comp 1000000 [1 + 1][f]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[1 + 1]
0:00:00.038712
[f]
0:00:00.07201
== 86%
>> comp 1000000 [1 + 1][f]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[1 + 1]
0:00:00.005999
[f]
0:00:00.120692
== 1911%
Gregg
>> comp 10000000 [1 + 1][f]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[1 + 1]
0:00:00.545457
[f]
0:00:01.114441
== 104%
>> comp 10000000 [1 + 1][f]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[1 + 1]
0:00:00.825999
[f]
0:00:01.327313
== 60%
Steeve
It comes to my mind that if recycle is not turned off during the tests, it could explain the variance.
So I did the test, ans yes, it's a lot better.
Here the new version:
comp: func [n [int!] a [block!] b [block!] /local ref][
    print reform bind [product version platform build] rebol
    recycle/off
    ref: perf n []
    a: to-decimal probe abs (perf n probe a) - ref
    b: to-decimal probe abs (perf n probe b) - ref
    recycle/on
    to-percent (to-integer b - a / a * 100) / 100
]

Steeve
Again I fucked up ref calculation. Lot more stable now
perf: func [i [integer!] b [block!] /local t n] [
    n: 0 t: stats/timer
    bind b 'n ; to use vars i,n in b  
    loop i [do b ++ n]
    stats/timer - t
]
comp: func [n [int!] a [block!] b [block!] /local adjust][
    print reform bind [product version platform build] rebol
    recycle/off
    adjust: n / to-decimal perf n []
    a: adjust * to-decimal probe perf n probe a  
    b: adjust * to-decimal probe perf n probe b
    recycle/on
    to-percent (to-integer b - a / a * 100) / 100
]
And my result  for calling a function:
>> comp 100000 [to integer! 8.0][to-integer 8.0]
core 2.100.111.3.1 Windows win32-x86 20-Feb-2011/16:24:43
[to integer! 8.0]
0:00:00.025229
[to-integer 8.0]
0:00:00.038491
== 52% (overhead)
Gregg
COMP n arg needs to be integer!, not int!.
>> comp 100000 [to integer! 8.0][to-integer 8.0]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[to integer! 8.0]
0:00:00.046459
[to-integer 8.0]
0:00:00.028882
== -37%
>> comp 100000 [to integer! 8.0][to-integer 8.0]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[to integer! 8.0]
0:00:00.021502
[to-integer 8.0]
0:00:00.029488
== 37%
>> comp 100000 [to integer! 8.0][to-integer 8.0]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[to integer! 8.0]
0:00:00.024317
[to-integer 8.0]
0:00:00.028619
== 17%
>> comp 100000 [to integer! 8.0][to-integer 8.0]
atronix-view 3.0.91.3.3 Windows win32-x64 2-Dec-2014/18:03:44
[to integer! 8.0]
0:00:00.04053
[to-integer 8.0]
0:00:00.038208
== -5%

Gabriele
make it run for at least a couple seconds each if you want a stable result.
DideC
Gregg: it seems your machine has several process that take CPU in the background. Hence the funny results.
Has Gab say: make a longer loop (1M) to reduce this effect... or kill process ;-)
Could be funny to 'comp the exact same code and has so different results.
Pekr
Maybe Gregg's machine is reporting to NSA, FBI, CIA and other agencies in the background? :-)

Gabriele
the code i used on R2 was:
time*: func [n block /local start] [
        start: now/precise
        loop n block
        difference now/precise start
]
time: func [block /local count time result] [
        time: 0:00
        count: 1
        while [time < 0:00:01] [
                time: time* count block
                result: divide to decimal! time count
                ; multiply by two for faster convergence
                ; (ie. aim for 2 seconds)
                count: 0:00:01 * count * 2 / time
        ]
        result
]
>> time [1 + 1]
== 7.25799625998013E-8
>> f: does [1 + 1]
>> time [f]
== 1.39604952270899E-7

Drake
How do I save the contents of  dir-list to a file from the console ?
Drake
Solved.   Checked out  http://business-programming.com/business_programming.html#section-12.8 and saw the code snippet that uses echo which I didn't know existed.
amacleod
Drake, No need to post in multiple groups...we will see it.

Endo
Does DIFFERENCE works faster on hash! than block! ?
Endo
How can I upload files to a already open FTP port?
p: open ftp://localhost/
INSERT or APPEND don't work. WRITE doesn't accept port!.
If I use WRITE ftp://test:test@localhost/ READ %file.txt then it opens a new connection each time, which I don't want.
sqlab
ftp (re)uses up to the value of cache-size different ports. If you set p/cache-size to 1, it should always use the already opened port.
sqlab
or maybe it is system/schemes/ftp/cache-size. At the moment I can not test it.
Endo
Thank you sqlab. Still is there a way to use OPEN port and upload files via already open port?
Do I remember correctly? CALL hangs on Windows only on R2/view (if no CALL/SHOW " " trick), no such bug in R2/Command right?
Gregg
I don't know if the problem affects command as well, but I would guess it does. My workaround is to make at least one CALL on startup with /SHOW, then the rest work fine without it.
reb-console-ctx: context [
    console-primed?: no
        
    set 'prime-call-console does [
        if not console-primed? [
            ; Under some versions of Windows, and recent versions of REBOL,
            ; we have to prime the console to make /output work correctly
            ; without using /show with every call (which flashes).
            ; Only do this if CALL has a /SHOW refinement though, otherwise
            ; it will crash.
            ; The /wait is important. If it isn't used, sometimes a console
            ; app will stop the windows message pump until you open a menu
            ; or something else that gets it going again.
            if find first :call /show [call/wait/show ""]
            console-primed?: yes
        ]
    ]
      
]
sqlab
@Endo, do you mean using the same port for ftp commands and data? If yes then you have to set passive to true.
Endo
@Gregg: Yes, I encapped my script with Command (no View) and it hangs when I use CALL/wait/console. I thought that the problem was on View only, but it's not.
Endo
@sqlab: I meant uploading a file via already open port!
ftp-port: open ftp://localhost/
; do something ...
; upload using ftp-port, how?
insert, poke, append etc. don't work..
@sqlab: I meant uploading a file via already open port!
ftp-port: open ftp://localhost/
; do something ...
; upload using ftp-port, how?
insert, poke, append etc. don't work..
@sqlab: I meant uploading a file via already open port!
ftp-port: open ftp://localhost/
; do something ...
; upload using ftp-port, how?
insert, poke, append etc. don't work..
@sqlab: I meant uploading a file via already open port!
ftp-port: open ftp://localhost/
; do something ...
; upload using ftp-port, how?
insert, poke, append etc. don't work..
oh my internet connection problem leads to multiple send, sorry about that.

sqlab
If I remember right, Rebol2 should cache an already opened port to the same destination an reuse it for follwing actions.

Endo
Hi Ashley, I started using Munge in a project, it is great, thank you for all your effort.
First of all, I couldn't find a group for munge, it would be better to have !munge or #munge group in Altme. So I'm writing here.
I would like to ask my questions & share my experiences here.
First one is a possible bug report:
worksheet/save ["Name" "Age" "Bob" 33 "Joe" 44] 2 %t.xlsx  ;this one works as expected
worksheet/save ["Name" "Age" "Bob" 33 "Joe" 44] 2 %t.xml  ;this one creates a .xml file which has 3 sheet with same data.
Gregg
Semseddin/Endo, if you can't find a group, create one. You should have rights to do so.

Endo
Anyone already wrote a function something like REPLACE-DEEP (similar to COMPOSE/DEEP) which deeply replace any match in a given block:
>> REPLACE-DEEP [ 1 [  2 "one" [ 3 "one" <something-else> ] ] ] "one" "two"
== [ 1 [  2 "two" [ 3 "two" <something-else> ] ] ]
I know it's not difficult using PARSE, but if anyone has already wrote, I don't waste my time. Thanks in advance.
Rebolek
Endo
Ah thanks! I wrote mine, I'll compare them.
replace-deep: func [ series [series!] value1 value2 /local rule m] [
    rule: [
        some [
            into rule
            |
            m: any-type! (if :value1 = first m [probe m: insert remove m :value2] :m)
            |
            skip
        ]
    ]
    parse series rule
]

DocKimbel
replace-deep: func [s [any-block!] value new /local rule pos][
    parse s rule: [any [pos: value (pos/1: new) | into rule | skip]]
    s
]
Gregg
Niiiiice. :-)
All of them, that is.
Endo
I think all of them have some problems including mine.
Doc: Your version stuck if no match:
>> replace-deep x: [a] 1 2   ;waits for ever
My version stucks if new value is a block that includes the search value:
>> replace-deep x: [a b [b] b] 'a [a b a]  ;infinite loop
Rebolek: Your version doesn't work for some values
>> replace-deep3 x: [1 2] 2 3  ; x stays unchanged
Rebolek
Oh, integers...
DocKimbel
It might be very complicated to achieve it using PARSE in Rebol2 due to the lack of escaping mechanism for words and integers like QUOTE in Red and Rebol3.
In Red, this version passes all the tests:
replace-deep: func [s [any-block!] value new /local rule pos][
    rule: [any [pos: quote _ (pos/1: new) | into rule | skip]]
    rule/2/3: value
    parse s rule
    s
]
probe replace-deep x: [a] 1 2
probe replace-deep x: [a b [b] b] 'a [a b a]
probe replace-deep x: [1 2] 2 3
[a]
[[a b a] b [b] b]
[1 3]
Rebolek
Endo's replace function (m: any-type! and then check for values in paren!) can do it
Nenad, your version is missing  ANY-STRING! rule before INTO RULE rule to ignore string!s, otherwise INTO will try to parse inside them.
DocKimbel
Indeed, with an INSERT/ONLY instead of INSERT, it would pass the second test.
Any-string!: good point.
Endo: the [ | skip ] part of your rule looks superfluous.

PeterWood
How does the /only refinement of find work?
Rebolek
>> find [a b c d] [a]                
== [a b c d]
>> find/only [a b c d] [a]
== none
>> find/only [[a] b c d] [a]
== [[a] b c d]
Pekr
for nested blocks?
C: [ 1 [ 2 3 4] 5 6 ]
find/only C [2 3 4]     ;--- should be find/deep then imo :-)
PeterWood
Thanks Rebolek and Pekr

Endo
I wrote some optimization questions in munge! group but not directly related to MUNGE, so I'll be appriciated if anyone can take a look and give sme ideas.
Ashley
INSERTing into a [large] block! is significantly slower than APPENDing. Likewise, REMOVEing from the head is much slower than the tail. For this reason it is often faster to create a new block than modifying [entensively] an existing one.

Endo
Doesn't it strange that THROW throws an exception, not CATCHed but execution stops where THROW is if block executed by CONTEXT
>> b: [print "1" throw "catch!" print "2"] print catch [do b "3"]
1
catch!
>> b: [print "1" throw "catch!" print "2"] print catch [context b "3"]   ; unexpected result when using CONTEXT
1
3
I think it is a bug on R2, R3's result is
1
catch!
for both.

amacleod
What's the best way to search a block of blocks for specific values. Is there a more efficient way other then looping through each block?
would key-value scheme make it easier?
Bo
amacleod: We just were discussing that in the !REBOL3 group.
amacleod
k, thanks

Sunanda
Gregg suggests this is a good group to post puzzles.....Actually, it is a real situation for which I wrote some grossly inelegant code. My code works, but it hardly shows off the beauty of Rebol or the power of Parse. So looking to see if anyone can do better than my 15 or so lines of procedural code....
I have a block that consists of string!s and blocks!s -- think of it as a set of parameters: a keyword string is usually followed by a [set of options], eg:
   parameters: ["keyword1" [char 20] "keyword2" [num max 999] "keyword3" [] "keyword1" [not null] ]
There can be blocks without keywords and keywords without blocks -- and keywords can be duplicated as above with "keyword1".
What I need is a normalization routine to insert empty strings or blocks such that every string is followed by a block and every block is preceded by a string Example:
    In:  [   [upper]   "key 1"      "key-2" [no]      [off]   "key 1"    ]
    Out: ["" [upper]   "key 1" []   "key-2" [no]   "" [off]   "key 1" [] ]
You can assume that there are only strings and blocks in the input -- or for bonus points, come up with something cleverer than my code (an initial REMOVE-EACH loop to quietly throw away non-conforming datatypes).
Thanks!
sqlab
How about
>> out: collect [
[    parse In [ some [
[            [copy str string! copy bl block!  (keep  str keep bl)]
[            | [copy str string! (keep  str keep copy []) ]
[            | [copy bl block! (keep  copy "" keep bl) ]
[            | skip
[            ] ]
[    ]
== ["" [upper] "key 1" "key-2" [no] "" [off] "key 1"]
>  ?
Sorry that was wrong (:
sqlab
keep/only does the trick
out: collect [
    parse In [ some [
        [copy str string! copy bl block!  (keep  str keep  bl)]
        | [copy str string! (keep  str keep/only  []) ]
        | [copy bl block! (keep   "" keep bl) ]
        |  skip
    ]   ]
]
== ["" [upper] "key 1" [] "key-2" [no] "" [off] "key 1" []]
Sunanda
That looks good, sqlab -- thanks!
One minor change:   keep/only  []   ===> keep/only  COPY []
Then each inserted empty block is a different one (which wasn't explicitly stated in the puzzle description; but it helps the actual app).
Ditto (keep COPY "" keep bl)
Endo
I constantly forget about COLLECT and KEEP, and everytime I say "cool!" when I see them :)

CelesteM
This might not be the best place to ask this but since it directly involves learning it seems as good a place as any. I'm wondering what books any of you might deem essential for programming and systems architecture. Do any of you have a favorite book on system architecture?
Gregg
On Software Architecture
- Beautiful Atchitecture is real world stories, but not all will teach you something. Overall I like it.
- Software Architecture in Practice is dry and rigid. I don't like it.
- Software Architecture and Design (Witt, Baker) is pretty good, if somewhat dated
- Software Architecture (perspectives on an emerging discipline) (Shaw, Garlan) I like, as it's not huge and their views align with mine. :-)
- Beyond Software Architecture didn't grab me. Lots of business related stuff in it.
- Domain Driven Design is good, as it applies to DSLs and such.
On programming, are you looking for coding specific stuff (e.g. Programming Pearls, Code Complete) or more general (Making Software, Rapid Development)?
SWhite
CelesteM
I'm looking to improve the way I structure my code so that it's both more readable and easier to maintain.
Geomol
Books I often use in combination with programming/development/language design:
- The C Programming Language (Kernighan and Ritchie).
    Most out of need, as I program in C also. Wish I didn't have to.
- Object-oriented Software Construction (Bertrand Meyer)
    Many very good ideas, even for outside real object-oriented languages.
- Programming Languages: Design and Implementation (Terrence W. Pratt)
    Cover lots of languages and designs.
- Data Structures and Algorithm Analysis (Mark Allen Weiss)
    The data structures ABC.
- Amiga ROM Kernel Reference Manual, Libraries & Devices
    Yeah, it actually still has useful stuff, even if it is old.
Carl's Style Guide has good tips for readability:
http://www.rebol.com/docs/core23/rebolcore-5.html#section-5
I changed my way of writing code, after I looked at the sources for Lua. Now I tend to write condenced code without empty lines, and then have two empty lines between functions.
And putting brackets on the same line as function definition, and space before parenthesis:
    void my_function (arg1, arg2) {
        ...
    }
Same with IF, WHILE, etc in REBOL:
    if something [
        do this
    ]
    while [this-is-true] [
        do this
    ]
CelesteM
That's how I format my code as well but I'm looking for something more along the lines of naming convention dos and don'ts. And how to create useful objects in OO programming.
Geomol
On naming, Carl has the best suggestions, as I see it:
5.2 Word Names
5.2.1 Use the Shortest Word that Communicates the Meaning
5.2.2 Use Whole Words Where Possible
5.2.3 Hyphenate Multiple Word Names
5.2.4 Begin Function Names with a Verb
5.2.5 Begin Data Words with Nouns
5.2.6 Use Standard Names
CelesteM
That looks like an excellent list right there.
Geomol
I don't do much OO programming, because it is so hard to find useful objects. :)
If I was to create a game, I would make a character object (the character, you play), objects for objects in your surroundings, etc. That is easy, because it relaty to the real world.
If I should write code, which would sort filenames in a directory, I would write a function, not use OO.
CelesteM
But in reality, each file is a separate object...
Geomol
I can only recommend reading Bertrand Meyer, if you wanna do OO (and even if you don't do OO). And I don't program in Eiffel, which is used in his book. He just have many real good ideas.
*has*
"But in reality, each file is a separate object..."
Yes, it just confuses, when what you need really is a function to just do the job.
CelesteM
That sounds like the kind of book that I'm looking for. Thanks!
I know. LOL It was sarcasm.
Gregg
Meyer is very good.  Reusable Software talks about library design, which is the most general kind of development.
Geomol
You are welcome. :)
OO was thought to be the breaktrough in programming and to be used for all programming. It wasn't and it isn't.
Gregg
Code Complete, while dated, was a seminal text on the subject. Anything by McConnell is good.
Geomol
back in the 80ies.
(80ies was for my comment about OO, not your comment, Gregg.)
CelesteM
Reusable software sounds like a good place to start for what I'm looking for.
Gregg
201 Principles of Software Development (Davis) is also wonderful IMO. It may seem like a silly little book, but I think it has more tabs in it than any other book I own.
Also, not on coding specifically, but anything by Robert Glass is worth reading. He writes about software failure.
Finally, the Pragmatic Programmer (Thomas and Hunt) is great.
CelesteM
Excellent.
Sunanda
For some very historical roots (yet still completely relevant issues), take a look for David Parnas and Information Hiding -- it's perennial guidelines (from the 1970s!) for healthy ways to structure large systems.

GiuseppeC
Hi, I am aways confused about blocks, code, reduction, molding,, nested bloks, series.
They are the hardest topic for me.
Are there any good articles I could read to lear the inner work of this part of REBOL ?
Bo
I'm in the process of writing an interactive tutorial for Rebol3 (using Rebol3) here: http://video.respectech.com:8080/tutorial/r3/index.r3
If there are additional chapters or things that are hard to understand, please let me know.

DideC
Bo: nice tutorial!
SWhite
Lovin' the tutorial.  If I read enough of these that hit REBOL from enough different angles, I start to understand.  I am beginning to reach the point where things that once seemed so hard to understand how seem simple, and I am forgetting why they seemed hard at first.  I wish I could capture what it was in my head that made it hard, and then give it to someone else and say, "Here, this is why you are confused about REBOL.  Your problems are all in your own head.  Absorb this information, and then you will understand."
Gregg
Me too Steven.
Gregg
Nice work as always Bo. "Nesting Functions" led me to think the section was about nested function defintions, not calls in a call chain using returned expressions.
Bo
Thanks for the feedback! What chapter should I write next? Or does anyone have a topic they've already covered that they'd like me to add?

Gregg
Values and datatypes.
GiuseppeC
I would like to know step by step what happen during words and block evaluation and how rebol inner strucuture works.
Gregg
Good timing! I just posted thoughts about that in the #Red group. Wait for feedback before assuming what I wrote is correct though. And it is only a first step. The details of evaluation can be tricky (think of things like inline set-words, and how much evaluation is applied to different types). Even "how much" is not a clear description, but rather how each type is evaluated, and the control you have over it.
GiuseppeC
Another question: If I define some words inside to body of a FUNC or a FUNCTION, are they available outside the fuction itself ?
Endo
If did not provide the local words then yes, they will be available outside of the current function scope.
See the SOURCE of FUNCTION.
Gregg
And easy to test. :-)

Gabriele
(The heart of the matter is DO-STEP which in Topaz is an action and defined in https://github.com/giesse/Project-SnowBall/blob/master/topaz/actions.topaz )
In R2 that would be DO/NEXT

SWhite
Good points about evaluation.  Knowing what happens could have a direct effect on programming.  For example, when I pull things out of a database with SQL, and I want to set a word to refer to, say, the first item in the block of columns that is the result of the SQL, I find myself doing something like "DISPLAY-ITEM: to-string to-integer copy SQL-RESULT/1" or something like that, details not important.  The important point is that I am doing copying and converting only beause I want to be absolutely sure I get the result I want, and some of that probably is not necessary because it already is done as part of the word evaluation.  I just don't know.  I suppose that is an implicit admission that I am too lazy to do a little experimenting to find out.  I do like my ruts.

Sunanda
Any clever ideas on how to push past a error in DO/NEXT?
   do/next [1 / 0 2 + 2] 'var
I'd be very happy if I could get [2 + 2} into 'var
Gregg
I was going to suggest something like:
b: [1 / 0  2 + 2]
while [not tail? b] [
    if error? try [set [res b] do/next b] [b: next b]
]
But that's too simplisitic. In your example, it will skip the first 1, then / will act as a prefix func and consume the rest of the block.
Which brings up a good question, related to the other "How is DO special" chat. Can you safely push past an error? Probably not.

Sunanda
Thanks Gregg -- I tried various things, but none of them work very reliably in all conditions - like pushing correctly past, say [divide 9 + 4 / 0 2 + 2]
It seems likely that DO knows exactly which args were consumed, and so could return the block with those skipped past. If only we could make it talk :)
Gabriele
DO could, but, not in all cases, or rather, not correctly in all cases. But, yeah, you'd need a new refinement that returns the error instead of causing it.

Sunanda
Thanks Gabiele - glad to know it is at least technically possible (within limits)

Sunanda
This there anyy clever, quick, way to turn these two blocks into a single object?
   names: [field1 field2 field3]
   values: ["a" "b" "C"]
I've already done it the long way around:
   blk: copy [] for nn 1 length? names 1 [append blk reduce [to-set-word names/:nn values/:nn]] probe make object! blk
Endo
I wrote a build-object function does that, not more quicker/clever though
names: [field1 field2 field3]
values: ["a" "b" "C"]
build-object: funct [names values] [
    o: copy []
    parse compose names [some [set name [word! | set-word!] (append o to-set-word name) | skip]]
    set/pad words-of o: context append o none compose values
    o
]
probe build-object names values
== make object! [
    field1: "a"
    field2: "b"
    field3: "C"
]
My more general version is a bit longer, but works without values, word! or set-word!s:
build-object: func [
    "Builds an object from a block"
    names [block!] "Words or word/value pairs"
    /values val [block!] "Initial values"
    /local o name value
][
    o: copy []
    o: either values [
        parse compose names [some [set name [word! | set-word!] (append o to-set-word name) | skip]]
        set/pad reflect o: context append o none 'words compose val
        o
    ] [
        if any [
            parse compose names [some [set name [word! | set-word!] (append o reduce [to-set-word name none])]]
            parse compose names [some [set name [word! | set-word!] set value any-type! (append o reduce [to-set-word name :value])]]
        ] [context o]
    ]
    o
]
build-object [a b c]
build-object [a 1 b "2"]
build-object [a: 1 b 2]
build-object [a: 1 b 'c]
build-object/values [a: b] [c 1]
x: 1 build-object/values [a: b] [c (x)]
ChristianE
A slightly different approach:
context collect [until [keep compose [(to set-word! take names) (take values)] tail? names]]
ChristianE
Gabriele
if you can add an extra word to your names, there is another way to do it:
>> names: [self field1 field2 field3]
== [self field1 field2 field3]
>> values: [#[none] "a" "b" "C"]    
== [none "a" "b" "C"]
>> names: use names reduce [names]  
== [self field1 field2 field3]
>> set names values                  
== [none "a" "b" "C"]
>> object: bound? first names      
>> object/self: object
>> probe object
make object! [
    field1: "a"
    field2: "b"
    field3: "C"
]
Up to you to decide if it's better or worse. :)

Endo
More clever award goes to ChirtianE, more interesting award goes to Gabriele :)
Sunanda
Thanks guys: lots of good ideas - as usual!
Gregg
change-each: func [
    [throw]
    "Change each value in the series by applying a function to it"
    'word   [word!] "Word or block of words to set each time (will be local)"
    series  [series!] "The series to traverse"
    body    [block!] "Block to evaluate. Return value to change current item to."
    /local do-body
][
    do-body: func reduce [[throw] word] body
    forall series [change/only series do-body series/1]
    ; The newer FORALL doesn't return the series at the tail like the old one
    ; did, but it will return the result of the block, which is CHANGE's result,
    ; so we need to explicitly return the series here.
    series
]
names: [field1 field2 field3]
values: ["a" "b" "C"]
o: context append change-each name names [to set-word! name] none
set o values
print mold o
Not sure what I was thinking. Should use MAP, not CHANGE-EACH.
R2 has MAP-EACH, so use that instead, so 'names isn't changed.
Then the entire solution is:
    o: context append map-each name names [to set-word! name] none
A MAP func would make it a little shorter, but R2 doesn't have one by default.

Marco
Nice addition to my "-each"s functions Gregg!

Last message posted 61 weeks ago.