[REBOL] Efficient binary functions, Re:

2000-10-10 Thread KGD03011


Hi,

Ooops, coupla bug fixes. This thing has gotten a lot more complicated
than I'd anticipated. This crashes and burns if the first value in BLOCK
is a list, but so does REJOIN.

rejoin-fixed: func [
"Reduces and joins a block of values."
block [any-block!] "Values to reduce and join"
/local result i
][
if empty? :block [return copy ""]
either series? result: first block: reduce :block [
result: copy :result
][
result: form result
]
block: next :block
either any-block? :result [
while [not tail? block][
insert tail :result first block
block: next block
]
][
while [not tail? :block][
i: first :block
if any-block? :i [i: rejoin-fixed :i]
append result :i
block: next :block
]
]
:result
]

Eric




[REBOL] Efficient binary functions, Re:

2000-10-10 Thread KGD03011


Hi Phil,

This should work:

>> rejoin [v1 v2 v3]
== #{01237B30337D237B34347D}

but it doesn't, due to a bug acknowledged by Carl. Until it gets fixed
the best I can think of is to use:

rejoin-fixed: func [
"Reduces and joins a block of values."
block [any-block!] "Values to reduce and join"
/local result
][
if empty? block [return ""]
either series? result: first block: reduce block [
result: copy :result
][
result: form result
]
either any-block? :result [
foreach i next block [
insert tail :result :i
]
][
foreach i next block [
if any-block? i [i: rejoin-fixed i]
append result i
]
]
:result
]

>> rejoin-fixed [v1 v2 v3]
== #{010344}

This "fixed" version of REJOIN shows a couple of other differences,
which I think are improvements:

>> rejoin []
** Script Error: Out of range or past end.
** Where: append either series? first block
>> rejoin-fixed []
== ""

>> rejoin [[1 2 3][4 5 6][7 8 9]]
== [1 2 3 [4 5 6] [7 8 9]]
>> rejoin-fixed [[1 2 3][4 5 6][7 8 9]]
== [1 2 3 4 5 6 7 8 9]

>> rejoin-fixed [0 [1 2 3][4 5 6][7 8 9]]
== "0123456789"
>> rejoin [0 [1 2 3][4 5 6][7 8 9]]
== "01 2 34 5 67 8 9"

>> rejoin ['a/b/c 'd/e/f 'g/h/i]
** Script Error: Cannot use path on word! value.
** Where: insert tail series :value
>> rejoin-fixed ['a/b/c 'd/e/f 'g/h/i]
== a/b/c/d/e/f/g/h/i

I'd be very grateful to hear opinions or suggestions.

Eric

>Suggestions !!!
>
>v1: #{01}
>v2: #{03}
>v3: #{44}
>
>What's the most efficient way of concatenating v1, v2 and v3
>
>Obviously, I can use:
>
>append v1 v2
>append v1 v3
>
>However, if I have X vars to concatenate this is unwieldy.
>
>Phil Hayes




[REBOL] polymorphic object/block "VWord func" - ...Re:

2000-10-10 Thread KGD03011


Hi Doug,

I don't think it's usually a good idea to use any-type! arguments for
functions, since that can easily lead to bugs.

>> vword [a "APPLE" b "BANANA" c "CARROT"] 'c print "oops"
oops
== "CARROT"

Programmers less experienced than you might wonder why the statements
get carried out in the "wrong" order".

How about this:

vword: func [
  { Test to see if a certain word is found in a block or object.
If so, the value of the word is returned. (Hence, the name vword.)
If not, then the alternate value will be used.
If the word is not found and no alternate value is supplied, none is
returned.}
  item [block! object!] {The item containing the word you wish to search for.}
  i-word [word! block!] {The word / attribute you wish to search for.
An alternate value may be specified as the second item of a block.}
  /local ret i-alt
][
  if block? i-word [
i-alt: pick i-word 2
i-word: first i-word
  ]
  either block? item [
 either none? ret: select item :i-word  [ i-alt ][ ret ]
  ][
either none? ret: in item :i-word [ i-alt ][ get in item :i-word ]
  ]
]

>> vword [a "APPLE" b "BANANA" c "CARROT"] [d "DICED PEACHES"]
== "DICED PEACHES"
>> vword [a "APPLE" b "BANANA" c "CARROT"] [a "DICED PEACHES"]
== "APPLE"
>> vword [a "APPLE" b "BANANA" c "CARROT"] 'e
== none
>> vword [a "APPLE" b "BANANA" c "CARROT"] [e]
== none
>> xo: make object! [a: "ABC" b: "BOY"]
>> vword xo [a "alpha"]
== "ABC"
>> vword xo [c "alpha"]
== "alpha"
>> vword xo [c]
== none
>> vword xo 'c
== none

This also works:

>> vword [1 "APPLE" 2 "BANANA" 3 "CARROT"] [2]
== "BANANA"
>> vword [1 "APPLE" 2 "BANANA" 3 "CARROT"] [4 "DICED PEACHES"]
== "DICED PEACHES"

Eric

>For your consideration:
>
>We are using a function called "vword" as
>(value of word in block or object)
>a safe, easy way to get unknown values out of blocks or objects.
>
>For instance:
>   We store email/report templates in blocks, but can now safely skip
>   any report details by leaving the items out of the template/blocks or
>   providing a default value to use as a substitute.
>
>  Another great use for "vword" is when decoding CGI gets or posts.
>  You never really know what is in or out of CGI object,
>  so vword is a safe way to interogate the object and get all the values.
>
>
>Try it out and let me know what you think.
>
>REBOL []
>;---
>-
>vword: func [
>  { Test to see if a certain word is found in a block or object.
>If so, the value of the word is returned. (Hence, the name vword.)
>If not, then the alternate value will be used.
>If the word is not found and no alternate value is supplied, none is
>returned.}
>  item [block! object!] "The item containing the word you wish to search for."
>  i-word [word!]"The word / attribute you wish to search for."
>  i-alt  [any-type!]"The alternate value to use if the word is not found."
>  /local ret
>][
>  either block? item [
> if none? ret: select item :i-word  [
>if (value? 'i-alt) [ret: i-alt]
> ]
>  ][
>either none? ret: in item :i-word [
>   if (value? 'i-alt) [ret: i-alt]
>][
>   ret: get in item :i-word
>]
>  ]
>  return ret
>]
>;---
>-
>
>
>
>>> do %/e/scripts/rs/vword.r
>Script: "Untitled" (none)
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'd "DICED PEACHES"
>== "DICED PEACHES"
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'a "DICED PEACHES"
>== "APPLE"
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'b "DICED PEACHES"
>== "BANANA"
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'c "DICED PEACHES"
>== "CARROT"
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'e "DICED PEACHES"
>== "DICED PEACHES"
>>> vword [a "APPLE" b "BANANA" c "CARROT"] 'e
>== none
>
>
>
>
>>> print mold xo
>
>make object! [
>a: "ABC"
>b: "BOY"
>]
>>> vword xo 'a "alpha"
>== "ABC"
>>> vword xo 'c "alpha"
>== "alpha"
>>> vword xo 'c
>== none
>>> vword xo 'c "alpha"
>== "alpha"
>>> vword xo 'b "alpha"
>== "BOY"
>>>




[REBOL] Bug? 'func not really 'func Re:

2000-10-10 Thread KGD03011


Hi Andrew,

>> Load Mold is needed instead of Copy/deep (I think, that you will find out
>why)
>
>I think I found out why:
>
>>> type? block!
>== datatype!
>
>I am confused as to why 'copy seems to be evaluating the words in the block
>it's given. And also why it doesn't show up until after the function is put
>together.

COPY isn't evaluating the words in the block. The values in the "opt type"
subblocks of THIRD :FUNC are datatypes:

>> type? probe first fourth third :func
block!
== datatype!

whereas FUNC usually needs words in those subblocks. If you don't have a
word there, the contents of those subblocks are treated as samples of the
datatype:

>> cube: func [x [2 2.1]][x ** 3]
>> source cube
cube: func [x [integer! decimal!]][x ** 3]

LOAD MOLD, Ladislav's solution, converts the datatypes back to words.

Hope this makes some sense ...

Eric




[REBOL] Bug! - 'second on object containing ONE hash! has TWO hash! !! Re:

2000-10-05 Thread KGD03011


Hi Larry,

>It is interesting that second shows the actual hash as having the value
>[...] which is the new indicator for a recursive block, hash, list, object,
>etc. Probe shows the actual value, as does
>
>>>mold second second o
>
>It would be nice to hear from RT as to whether the [...] in your example is
>the intended behavior.

It seems the algorithm for detecting recursive blocks is a little too
simple-minded. When REBOL is representing a value, anytime it re-encounters
the same block, the contents of that block are replaced with [...] .  So some
things have become a little weird:

/Core 2.3  :

>> head insert/only/dup [] [] 5
== [[] [] [] [] []]

/View 0.10.38  :

>> head insert/dup/only [] [] 5
== [[] [...] [...] [...] [...]]

But if you have the same block alternating within another block the ...
don't show:

/View 0.10.38  :

>> b: [[1] [2]]
== [[1] [2]]
>> bb: []
== []
>> insert/dup bb b 4
== []
>> bb
== [[1] [2] [1] [2] [1] [2] [1] [2]]

Of course these really are the same blocks:

>> b/1/1: 3
== [3]
>> bb
== [[3] [2] [3] [2] [3] [2] [3] [2]]

>Here is a related fun puzzle ;-)
>
>>> b: [1 2]
>== [1 2]
>>> b/2: b
>== [1 [...]]

I'm not quite sure what the puzzle is ...

The ... here is only an artifact used to prevent stack overflow. AFAIK this
hasn't been possible until the recent experimental releases. It causes a
stack overflow with /Core 2.3 .

>>> save %junk.txt b
>>> b2: load %junk.txt
>== [1 [...]
>]
>>> second b
>== [1 [...]]
>>> second b2
>== [...]
>>> first second b
>== 1
>>> first second b2
>== ...

The ... here is now a word!

>
>So it is possible to create a block which cannot be saved and loaded. This
>may be a bug in load. Only RT knows what lurks in the heart of REBOL. ;-)

Lots of things get converted to words when you save and load them: TRUE,
FALSE, NONE and all the datatypes. Of course you can often reduce a block
to get the original values back. '... doesn't usually have any value, and
even if LOAD or REDUCE recognized this as a recursed block, it would often
be impossible to tell at what level a block was being recursed.

Also, LOAD has never been able to deal with the distinction between blocks
that are the same, and those that are merely equal. Both same and identical
blocks wind up as merely equal. And now there will be some same blocks
reloaded with an extraneous word in them.

>
>Cheers
>-Larry
>
>PS You can make a recursive block which cannot be saved and loaded.


>The line:
>
>>>o/self/self/self/self/self/self/h
>
>certainly indicates recursion. What is curious is that the ... shows up for
>the value block of the hash and has never showed up for the obvious
>recursive self-reference of 'self.

As you explained to Andrew, mold avoids representing 'self and its
value. With the ... convention, you could represent an object as:

make object! [ self: make object! [ ... ] a: "some value" ]

but that would make problems for LOAD.

Eric





[REBOL] Bug! - 'second on object containing ONE hash! has TWO hash! !! Re:

2000-10-05 Thread KGD03011


Hi Andrew,

Are you pulling our leg? Remember 'self ?

>> o: make object! [h: make hash! []]
>> second o/self
== [
make object! [
h: make hash! []
] make hash! []]
>> second o/self/self
== [
make object! [
h: make hash! []
] make hash! []]
>> o/self/self/self/self/self/self/h
== make hash! []

This is with the non-experimental REBOL/Core. It's interesting that /View
thinks it's necessary to put the ... indicating recursion when there's no
recursion involved. Maybe THAT's a bug.

Eric

>Bug! - 'second on object containing ONE hash! has TWO hash! !!
>
>REBOL/View 0.10.35.3.1 30-Sep-2000
>Copyright 2000 REBOL Technologies.  All rights reserved.
>>> o: make object! [h: make hash! []]
>>> o/h
>== make hash! []
>>> second o
>== [
>make object! [
>h: make hash! []
>] make hash! [...]]
>>> append o/h 1
>== make hash! [1]
>>> second o
>== [
>make object! [
>h: make hash! [1]
>] make hash! [...]]
>>>
>
>I'm fairly sure that this line:
>make hash! [...]
>shouldn't be present in 'o.




[REBOL] shifting characters in rejoin Re:

2000-10-04 Thread KGD03011


Hi Ryan,

Andrew Martin already answered you, but maybe this provides a little
different perspective ...

The results look strange because the < and > aren't part of the tag!
data, they just delimit it.

>> length? 
== 3

When you do

   markup-string: rejoin [open-tag data/name close-tag]

the first item in REJOIN's block argument is a tag, so the result is
a tag. But before close-tag is appended, it is formed to a string,
which causes the delimiting < > to actually become characters of data.

A tag! is meant to represent only one tag. If you want to have more than one
tag in an HTML element, you need to make a string. So it's very easy to
correct your function. Replace the line quoted above with:

   markup-string: rejoin ["" open-tag data/name close-tag]

Eric

>I have created a function which returns something strange when I use
>rejoin.
>
>The function is called build-html.r which builds a markup statement.
>Here is the console result. Notice the closing bracket for the opening
>tag is strangely moved to the end of the rejoined string:
>
>>> do %build-html.r
>Script: "Untitled" (none)
>== >
>>>
>
>Your input would be helpful.  -Ryan
>
>Here is the script:
>
>REBOL []
>
>author: make object! [
>name: "Ryan C. Christiansen"
>email-address: [EMAIL PROTECTED]
>stylesheet-info: make object! [
>tag-style: "font"
>   class-name: "author"
>]
>]
>
>build-html: func [
>{Build an HTML page element including the data to be displayed
> and the markup language surrounding the data.}
>data [object!] "the data to be marked up"
>][
>open-tag: build-tag [(data/stylesheet-info/tag-style) class
> (data/stylesheet-info/class-name)]
>
>close-tag: rejoin [{}]
>
>markup-string: rejoin [open-tag data/name close-tag]
>
>markup-string
>
>]
>
>build-html author




[REBOL] Problem with try [ open/direct/binary tcp://... ] Re:

2000-10-04 Thread KGD03011


Hi Elan,

Thanks for setting me straight on where my observations were lacking.
So, apparently INSERT and friends always use TO STRING! , but
TO STRING! 's behavior itself is a little harder to understand than I'd
thought.

I take it that of the three types of conversion, MOLD preserves the
integrity of the original value the most, TO STRING! compromises it the
most, and FORM is somewhere in between. TO STRING! wipes out the
distinction between the members of any block values it gets, but preserves
the internal integrity of individual members of its block value arguments.

This produces these results, which were unexpected for me:

>> to string! [abc/def/ghi jkl/mno/pqr]
== "abc/def/ghijkl/mno/pqr"
>> to string! [["abc" "def" "ghi"] ["jkl" "mno" "pqr"]]
== "abc def ghijkl mno pqr"

I'd like to know if Carl thinks this behavior is a bug as well.

You say,

>5. I think it is reasonable to expect that REBOL's conversion routines
>maintain CONVERSION INTEGRITY. Unfortunately that is not true. Examples:

I was thinking that CONVERSION INTEGRITY was the job of MOLD, which saves
the most integrity. But even that doesn't give quite the right answer
sometimes:

>> to block! mold ["abc" "def"]
== [["abc" "def"]]

although LOAD works OK for this case:

>> load mold ["abc" "def"]
== ["abc" "def"]

I think CONVERSION INTEGRITY can be achieved in most cases, but you have to
use a heterogenous set of tools on a case-by-case basis. Not an ideal
situation!

And it seems there's no way to maintain CONVERSION INTEGRITY with datatype!

>> to datatype! to string! string!
** Script Error: Cannot use to on datatype! value.
** Where: to datatype! to string! string!
>> load mold string!
== string!
>> type? load mold string!
== word!


Eric




[REBOL] Problem with try [ open/direct/binary tcp://... ] Re:

2000-10-03 Thread KGD03011


Hi Joel,

I think there's a big problem when the docs use a vague term like "convert
to a string," since there are several ways that values may be converted to
strings.

As Andrew Martin noted, the cause of the strange behavior seen by JOIN is
INSERT's behavior (also seen with APPEND).

It seems that INSERT uses FORM to convert values contained in blocks before
inserting them, and TO STRING! to convert values which aren't contained in
blocks. Most of the time the results of TO STRING! and FORM are the same, but
there are several differences.

>> to+form: func[v][print to string! :v print form :v]
>> to+form pi
3.14159265358979
3.14159265358979
>> to+form %file.ext
file.ext
file.ext
>> to+form to binary! "binary"
binary
#{62696E617279}
>> to+form first [abc/def/ghi]
abcdefghi
abc/def/ghi
>> to+form ["abc" "def" "ghi"]
abcdefghi
abc def ghi

These differences correspond exactly to the behavior of INSERT, APPEND and
JOIN:

>> append "" to binary! "binary"
== "binary"
>> append "" reduce [to binary! "binary"]
== "#{62696E617279}"
>> append "" first [abc/def/ghi]
== "abcdefghi"
>> append "" [abc/def/ghi]
== "abc/def/ghi"
>> append ""  ["abc" "def" "ghi"]
== "abcdefghi"
>> append ""  [["abc" "def" "ghi"]]
== "abc def ghi"

Eric

>Just a brief follow-up after checking the new docs...
>
>[EMAIL PROTECTED] wrote:
>>
>[...code samples snipped...]
>>
>> INSERT shouldn't use FORM when inserting a BINARY!. I'm sending
>> this to feedback too (I don't remember if I had already signaled
>> this to feedback...).
>>
>
>Page 7-3 (225 of 574) begins by saying
>
>This chapter will introduce functions that convert REBOL values
>into strings.  These functions are used often ... They include:
>
>followed by Table 7-2, titled "String Conversion Functions".  In
>that table  join  is described as "convert values with no spaces".
>
>Later on, page 7-4 (226 of 574) states:
>
>The  join  function takes two arguments and concatenates
>them into a single series.
>
>The data type of series returned is based on the value of the
>first argument.  When the first argument is a series value,
>that series type is returned.
>
>and then proceeds to give examples of computing  string! ,  file! ,
>and  url!  values via  join  invocations.
>
>The next page goes on to say:
>
>When the first argument is not a series, the  join  converts
>it to a string first, then performs the append.
>
>Finally the following page (7-6, 228 of 574) says
>
>When the second argument to  join  is a block, the values of
>that block are evaluated and appended to the series returned.
>
>This is not a smack-in-the-kisser blunt as I would like, but I
>think it means this (*WARNING* *MY NON-OFFICIAL READING*):
>
>Type of  Type of  Type of
>1st arg  2nd arg  result   Treatment of args
>---  ---  ---  --
>1)  any-string!  not block!   arg 1 type   arg 2 value converted to
>   string and appended to
>   copy of arg 1 value
>
>2)  any-string!  any-block!   arg 1 type   arg 2 values converted to
>   strings and appended to
>   copy of arg 1 value
>
>3)  not
>any-string!  any  string!  join to-string arg1 arg2
>   (now guaranteed to be one
>   of the first two cases)
>
>If I'm correct, the behavior with a  binary!  first argument is
>actually the intended, documented behavior, as the  binary!  type
>is subsumed under the  any-string!  type.
>
>-jn-
>
>P.S.  "I'm not a language lawyer, but I play one on the 'Net!"  ;-)
>
>  Isn't it fun having a spec?!?!




[REBOL] Re:Associative Array

2000-09-14 Thread KGD03011


>Has any one made an associative arrary in Rebol? Something like:
>a/Associate Key Value
>TheValue: a/find Key
>It would be nice to show this to people used to using associative
>arrays, that Rebol can do so as well.

Hi Andrew,

Here's my latest attempt.

make-hash: func [][
make object! [
pos: none
keys: make hash! 1000
values: make block! 1000
set: func [key value][
  either pos: find keys key
[poke values index? pos value]
[append keys key append values value]
]
get: func [key][
either pos: find keys key [pick values index? pos][none]
]
]
]

>> a: make-hash
>> a/set "brown" "chairo"
== ["chairo"]
>> a/set "green" "midori"
== ["chairo" "midori"]
>> a/set "brown" "kogechairo"
== ["kogechairo" "midori"]
>> a/get "brown"
== "kogechairo"
>> a/get "midori"
== none

Still, all the experimenting I've done indicates Rebol can't do
large associative arrays (more than a couple thousand keys)
nearly as efficiently as Perl.

Eric




[REBOL] Re:x-www-form-urlencoded (bug in bitset! or find ?)

2000-09-01 Thread KGD03011


Hi Alessandro,

>I've been examining the url-encode function from CookieClient.r, but
>there's something I'd most definitely call a bug... if I could manage to
>pinpoint it! :-0

Your problem reminded me of something, and after a good deal of poking
around in my old mail I found it. The bug lies in this part:

  find normal-char first data

When you pluck a character out of a string with FIRST or PICK, the return
value is not stable - it produces unpredictable errors when used with FIND
and bitsets. The workaround I found for the problem is this:

  find normal-char to-char to-integer first data

Here's a copy of the feedback I sent at the beginning of last November!
It sounds like you've gone through exactly what I did. Sure would be
nice to have an accessible bug data base! I've never had much luck with
getting bugs I've reported fixed. But perhaps if you complain too,
something will eventually be done for this bug.


>>I've run into more trouble with FIND (using 2.2.0.3.1). I've got a bitset
>>that defines all the possible characters that can be the first part of a
>>Shift-JIS two-bit character used to encode Japanese text:
>>
 zen1: make bitset! [#"^(81)" - #"^(9F)" #"^(E0)" - #"^(FC)"]
>>
>>It works fine with FIND if a character is expressed directly:
>>
 find zen1 #"^(90)"
>>== true
>>
>>But if the character is picked out of a string it doesn't:
>>
 find zen1 first "^(90)M"
>>== none
>>
>>Sometimes when I fiddle around a bit it starts working:
>>
 #"^(90)" = first "^(90)M"
>>== true
 find zen1 first "^(90)M"
>>== true
>>
>>but not consistently. One workaround is:
>>
 find zen1 make char! make integer! first "^(90)M"
>>== true
>>
>>which always seems to work.

Actually, maybe it's better to do this with PARSE:

url-encode: func [
{URL-encode a string}
data "String to encode"
/local new-data normal-char c
] compose [
new-data: make string! ""
normal-char: (charset [
#"A" - #"Z" #"a" - #"z"
#"@" #"." #"*" #"-" #"_"
#"0" - #"9"
])
if not string? data [return new-data]
parse data [ some [
copy c normal-char
(append new-data c) |
copy c skip
(append new-data reduce ["%" skip tail (to-hex 0 + first c) -2])
] ]
new-data
]

(Notice I've optimized a bit. Using COMPOSE means we only have to make the
bitset NORMAL-CHAR when the function is constructed. And in the original
line:

rejoin ["%" to-string skip tail (to-hex to-integer first data) -2]

TO-STRING isn't necessary, 0 + works faster than TO-INTEGER, and
REDUCE works just as well as REJOIN, replacing a function call with a
fast native.)


>BTW, is there an *easy* way to get a string from a bitset? For example, to
>get "123ABCabc" from charset "abcABC123".

This is a function I wrote a long time ago. I think it does what you want.
With the /ul refinement it does something completely different, which
is return a "case insensitive" form of a bitset.

unroll-bitset: func [
{return string listing all characters in B}
b [bitset!]
/ul "return B with all characters set for upper and lower case"
/local s i
][
b: copy b
s: copy ""
i: 0
while [ i <= 255 ] [
if find b to char! i [insert tail s to char! i]
i: i + 1
]
s: head s
either ul [
insert b uppercase s
insert b lowercase s
][s]
]

>> unroll-bitset charset "abcABC123"
== "123ABCabc"
>> unroll-bitset unroll-bitset/ul charset "abc123"
== "123ABCabc"

See you,
Eric




[REBOL] Re:Binary to Decimal Function

2000-08-26 Thread KGD03011


Hi Paul,

You should copy the argument before you reverse it, since reverse will
change the original data:

>> a: "1000"
== "1000"
>> bnfunc a
== 8
>> a
== "0001"

Instead of

  reverse bn

you could say

  reverse bn: copy bn

Also, an easier way to do

  if (to-string (pick bn x)) = "1" [ ... ]

is

  if ((pick bn x)) = #"1" [ ... ]


Here's another way to do the whole thing:

from-bin: func [
{convert a binary string representation into a numeric value}
b [string!]
/local x
][
x: 0.0
foreach bit b [
x: x * 2 + either #"1" = bit [1][0]
]
x
]


Eric

=

Here is a useful function for anyone needing to convert binary digits to
decimal.  Took me awhile but here it is:

bnfunc:  func [
"Convert Binary digits to Decimal equivalent"
bn [string!] "The binary representation"
/local holder count][
holder: make integer! 0
reverse bn
count: length? bn
for x 1 count 1 [
if (to-string (pick bn x)) = "1" [
holder: (2 ** (x - 1)) + holder
]
]
return holder

]

Let me know what you think.

I am gonna create some refinements to enhance it a bit.

Paul Tretter




[REBOL] Re:Trapping errors? - Not like the book says?

2000-08-03 Thread KGD03011


Hi Doug,

Why don't you try it this way:

if error? error: try [send  [EMAIL PROTECTED]  {test} true ][
   log-event/error system/script/header/file "error" (disarm error)
 ]

SEND doesn't return a value, so TRY doesn't return one either. As a
result all the set-word error: sees is the unset! value, which produces
the error. If you add 'true to the end of the try block, that
ensures you'll have some value to set 'error to. Here's an illustration
with PRINT, another function that returns no value.

>> type? try [print "hello"]
hello
== unset!
>> error? try [print "hello"]; ERROR? doesn't mind unset!
hello
== false
>> error? error: try [print "hello"] ; but error: can't stand it
hello
** Script Error: error needs a value.
** Where: error? error: try [print "hello"]
>> error? error: try [print "hello" true]   ; give it TRUE to keep it happy
hello
== false

See you,
Eric




[REBOL] converting I.P. Addresses to integer Re:

2000-08-01 Thread KGD03011


Hi Larry,

You wrote:

>tup-to-num: func [x /local out][
> out: 0.0
> x: head reverse parse to-string x "."
> repeat j 4 [
>  out: out + (256.0 ** (j - 1) * to-integer x/:j)
> ]
>]

How about ... ?

tup-to-num2: func [x /local z out][
  out: 0.0
  repeat j length? x [
out: out * 256 + pick x j
  ]
]

See you,
Eric




[REBOL] Bug in 'use? Re:

2000-07-23 Thread KGD03011


Hi Elan,

I think you're going to be really busy refuting Ladislav, so I'll keep
my comments brief.

You wrote:

>Observe:
>
>>> x: "This is global x."
>
>>> f: func [x] [
>[  g: func [] [
>[print x
>[  ]
>[]
>
>>> f "this is f's argument x"
>
>>> h: func [] [ print x ]
>
>>> h
>This is global x.
>
>>> g
>this is f's argument x
>
>Why does the function associated with 'g (I'll call it the 'g function)
>report f's argument, and not the global 'x, as 'h does?
>
>It's because the 'g function, which is defined in f's context, inherits f's
>context table. Therefore the 'x it prints is the 'x bound in f's context,
>not the global context.

Your explanation agrees with your example, but I don't think it's quite
the best one. I think the best explanation (which I'm mostly basing on
what Gabriele and others have said) is:

Before the function G is constructed, its body block, [print x] is
already bound to the context of the function F. Of the two words in this
block, 'x is defined in the "context table" of F. So when G is
constructed, this block is bound to G's context, but since 'x is not
redefined in that context it simply retains its binding. You could say
that G inherits the binding of 'x, but I don't see any proof that G
"inherits f's context table".

I think your explanation about embedded functions inheriting context
tables has the potential of causing major confusion. My previous example
was a lousy one, but here's an example involving embedded functions that
can easily occur:

>> b: [print x + y]
== [print x + y]
>> f: func[x][g: func[y] b print x]
>> x: 100
== 100
>> f 10
10
>> g 1
101

If you think in terms of "inheriting context tables", wouldn't you expect
G to print 11? That's certainly what I would think.

What happens here accords with my explanation, though. When G is
constructed, in its body block 'x hasn't been bound to the context of F,
and that binding doesn't change - it's still bound to the global context.
This happens because the body block wasn't actually in the block that
was bound to F's context - only the word 'b referring to the body block
was.  (Actually, the bindings in the original B are unchanged, since a copy
is used to construct G.)

>I think this inheritance behavior is expressed fairly well with the word
>"hierarchical inheritance". There is a hierarchy of context tables. REBOL
>constructs this hierarchy top-to-bottom, from the higher-level function
>down to the lower-level function defined in the higher-level function's
>context. REBOL consults with context tables in the hierarchy bottom-up when
>it resolves words and looks up what the value they are bound to, beginning
>with the context table for the lower-level function, and, if it can't find
>the word's definition there, it searches in the next-higher context table,
>and so on, until it arrives at the global context table.

When is it that "REBOL consults with context tables"? At run time? When the
function is constructed? Surely it's the latter.

I think a simpler explanation than hierarchical inheritance is that
when a function is constructed, it simply binds all the words in its
body block that are defined in its own context (that is, its own arguments
and local variables), and retains the binding of all other words. If one of
the words in its body block happens to be bound to the context of another
function, that word will retain its binding, whether or not one function is
embedded in another one.


Ladislav's tools for examining binding are very interesting. I'd just
like to extract and adapt the crucial part of his argument that proves
that contexts are not inherited:

>> x: y: z: 0
== 0
>> f: func[x z][g: func[y] [print [x y z]]]
>> f 10 30
>> g 20
10 20 30
>> b: reduce [
[bind 'x probe second second second :g
[bind 'x probe third second second :g]
y
z
== [x x]
>> reduce b
== [0 10]

This shows that the word 'x is nowhere in G's context table. The word 'y
which _is_ in G's context does not allow us to access any bindings for
'x except the global one. The word 'z which is in F's context table _does_
allow us to access F's binding for 'x.

Wish I'd thought of that!

See you,
Eric




[REBOL] Bug in 'use? Re:

2000-07-23 Thread KGD03011


Hi Elan,

You wrote:
>Example 1 for Context Hierarchy:
>
>global-word: "This is the global word."
>
>f: func [f-arg] [
>  g: func [g-arg] [
>print [g-arg f-arg global-word]
>  ]
>  g "This is g's argument."
>]
>
>In this example we are dealing with three contexts: the global context, in
>which global-word is defined, the function f's local context in which f-arg
>is defined, and finally, the function g, in whose local context its g-arg
>is defined.
>
>The g function inherits f's context table in which f-arg is defined.
>Therefore g has access to all three words: It can access global-word,
>because global-word is defined in the global context, and g has access to
>the global context. It can access g-arg, because g-arg is defined in its
>own private context table. The g function also has access to f-arg, which
>is defined in f's local context. The g function accesses f-arg in f's
>context table, which g inherits.

I think it's needlessly complex to say that the g function "has access
to f-arg". It's much simpler to say that the word 'f-arg is bound to the
context of the function F, and that the function G has no privileged access
to that binding of 'f-arg by being within some kind of hierarchy.
(The binding of 'f-arg of course took place even before the function G
was created.)

Here's proof, I think:

>> f: func[x y][x + y]
>> g: func[x y][x + y]
>> f 1 2
== 3
>> g 5 6
== 11
>> b: copy second :f
== [x + y]
>> c: copy second :g
== [x + y]
>> append clear second :f c
== [x + y]
>> append clear second :g b
== [x + y]
>> f 1 2
== 11
>> g 5 6
== 3
>> f 10 11
== 11
>> g 5 6
== 21


Here I've rebuilt the code for F and G, and now their bodies contain words
'x and 'y bound within each other's contexts. I think it's simplest to say
that those words "know" where they are bound. When you call F, it sets
the values of all instances of 'x and 'y bound to its context, but in this
case all those instances are now in the body of G, not within F's own
body. F doesn't see the word 'x within its body, and look up the value of
'x in some table, it just uses the value that results when 'x is evaluated.

See you,
Eric




[REBOL] Bug in sort/compare ? Re:

2000-07-13 Thread KGD03011


Hi Ole,

The problem is in your sort-func all the return values are true. I think
this'll give better results:

sort-func: func [n1 n2] [
  loop input-length [
n1: n1 + 1
n2: n2 + 1
if n1 > input-length [n1: 1]
if n2 > input-length [n2: 1]
c1: pick input n1
c2: pick input n2
if c1 > c2 [return  false]
if c2 > c1 [return true]
  ]
  return true
]

It seems a little odd, though, that there's no way for the comparison
function to say that the two values were equal.

By the way, your script redefines 'input, which might not be a good idea.

Eric




[REBOL] Find speed Re:

2000-07-07 Thread KGD03011


Hi,

>Umm, the reason that the hash is slow is that it only hashes string type
>values. The test you were using had numeric values. Try your tests with
>strings and you should see a significant difference and I will add numeric
>values to the hash as well for the next release... However, I'm not
>planning on hashing block values...
>
>  - jim

Well, that clears some things up!

Still, the big thing missing for me in Rebol is the lack of a really
fast associative array. With Thompson AWK, the language I most use for data
crunching, I can make an associative array with 100,000 keys in about
four seconds, and search for 100,000 key values in five seconds. With Rebol
it takes longer even with much smaller hashes. For example using a hash with
just 10,000 key values (with /Core 2.3.0.3.1):

  z: make hash! 2
  loop 1 [
x: random 200
if not select z x [
  append z reduce [to string! x x]
]
  ]

takes over a minute, and

  loop 1 [
if select z to string! random 200 [x: x + 1]
  ]

takes eight or nine seconds.

Hashes seem to be particularly slow when searching for nonexistent key
values. For 100,000 searches:

  loop 10 [ if select z "1533695" [x: x + 1]] ; first key value,   0:02
  loop 10 [ if select z "501730" [x: x + 1]]  ; 5000th key value,  0:53
  loop 10 [ if select z "1533696" [x: x + 1]] ; non-key value, 1:41

I figure the main difference is that Rebol remembers the order the
elements were saved in the hash, whereas with AWK that information is
discarded. Also, AWK allows a key value to be used only once whereas
with Rebol hashes you can have any number of identical values.

I figure the main reason for using a hash is to associate unique key
values with one other value. Trying to give hashes in Rebol all the
properties of a block introduces a lot of unnecessary overhead, and
means a lot more hand-coding to check for pre-existing key values.

Another problem with Rebol hashes is if you don't declare the size of the
hash to begin with, it crashes.

It would be really really nice to have a fast native data structure that
worked more like associative arrays in AWK or Perl!

Thanks,
Eric




[REBOL] Status words Re:

2000-06-22 Thread KGD03011


Hi Larry,

>Hi Harry
>
>The globally known words are returned in a block by
>
>words: first system/words
>
>You can print them one to a line with
>
>foreach word first system/words [print word]

That'll print out all the words, including words that were only defined
in a local context.

There's also huh.r:

http://www.rebol.org/utility/huh.r

It's not so necessary now with the improved help in View, but it still
comes in handy. It prints out the words grouped by datatype, and
in a console-space-saving table format.

I guess Larry didn't mention it because he wants me to come out of my
shell ;)

Eric

>You can use WHAT to list all functions.
>
>-Larry




[REBOL] solved (was detach-image: func (was: %detach.r ) ) Re:

2000-06-13 Thread KGD03011


Hi,

I don't know how helpful it will be, but here's the function I use for
detaching attachments. It only works for four types of encoding (the type has
to be specified), and only for attachments that have an associated file
name, but it's a pretty simple and general solution, I think. All the
attachments it can handle will be written into the current directory. If
the same file name appears more than once the first one will be overwritten.

Eric


det: func [
{takes a file and writes included MIME attachments to their
named files}
f [file!]
/local lines data name boundary encoding ptr ptr2 hex-digits byte
][
hex-digits: make bitset! [#"0" - #"9" #"A" - #"F"]
lines: read f
parse lines [ any [
thru "^/--"
copy boundary to "^/" "^/"
[
{Content-Type:}
thru {name="}
copy name to {"} {"}
thru {Content-Transfer-Encoding:}
any " "
copy encoding to "^/"
thru "^/^/"
copy data to boundary
ptr:
(
(print copy/part data 20)
print [name encoding boundary length? data index? ptr]
ptr: skip ptr -4
clear skip tail data -2
switch encoding [
{base64} [write/binary to file! name debase/base data 64]
{quoted-printable} [
ptr2: data
while [ ptr2: find ptr2 "="] [
either parse ptr2 [
"=" copy byte 2 hex-digits to end
][
remove/part ptr2 3
ptr2: insert ptr2 dehex join "%" byte
][ remove/part ptr2 2]

]
write to file! name data
]
{7bit} [write to file! name data]
{8bit} [write/binary to file! name data]
]
ptr: ptr) :ptr |
none
]
] ]
]




[REBOL] %"" Re:

2000-02-27 Thread KGD03011


Hi Olivier,

you wrote:

>Do you think that %"" should be accepted as a valid filename ?
>Personnally I don't think so, because no operating system I know accept
>that.
>%"" should return .
>This would solve many issues with filename handling (split-path,
>clean-path).

A valid filename and a valid file! datatype are completely different
concepts. A file! datatype is just a sort of string, and whether that
can serve as a valid filename is not something REBOL should have to
worry about. How about this?

>> nasty-file: to file! {echo "clobber" > rebol.exe}
== %echo%20%22clobber%22%20>%20rebol.exe
>> write nasty-file "I did it"
** Access Error: Cannot open /C/temp/echo "clobber" > rebol.exe.
** Where: write nasty-file "I did it"

It's the operating system that decides whether to allow a filename or not.

%"" by itself is not very useful, but how about this:

>> prefix: %X-
== %X-
>> join prefix %name.ext
== %X-name.ext
>> prefix: %""
== %
>> join prefix %name.ext
== %name.ext

Even a value that by itself is not a valid filename can make sense in
combination with another value.

>Another related problem:
>>> to file! none
>== %none
>
>It should return either the none value (of datatype none!) or %"" (depending
>on your answer to the previous question).

This behavior can be annoying, but it's fairly consistent. Compare:

>> join "a string: " none
== "a string: none"
>> head insert ", a string" true
== "true, a string"
>> to issue! file!
== #file

Your idea of having TO FILE! NONE return the value NONE is not a good idea.
TO always returns a value belonging to the datatype specified in its first
argument (or if that's not possible, an error is produced). To have TO
return various other datatypes depending on the circumstance would make
REBOL much more inconsistent.

Your idea of having TO FILE! NONE return the value %"" makes a lot of sense,
but still, what will you do with TRUE, FALSE, or datatypes? It's not always
obvious what is the most reasonable value. I personally find the present
behavior the best. I never intend to convert NONE to a file! , so when
I do and I see a file name like %abcnone.xyz it's a dead giveaway what
went wrong. If I just got %abc.xyz and that wasn't what I was expecting,
it'd be a lot harder to track down the problem.

See you,
Eric



[REBOL] [BUG] unset! (and "help" function lie!)

2000-02-27 Thread KGD03011


Hi Olivier,

you wrote:

>So unset! seems to be a datatype.
>Lets verify if unset! is a datatype :
>
>>> type? file!
>== datatype!
>>> type? unset!
>** Script Error: unset! has no value.
>** Where: type? unset!

One of REBOL's most confusing issues is that representations of some values
look exactly like the words they are assigned to. These values cannot be
directly parsed by REBOL - first they are parsed to words, and then the word
is evaluated.

When you did:

>> type? file!
== datatype!

REBOL first parsed the string you typed, "file!", to the word file!, and
then when that word is used as the argument of TYPE? it is evaluated. The
word FILE! is preset to the datatype! file!, which is the value that the
function TYPE? sees.

Try this:

>> a: [type? file!]
== [type? file!]
>> type? first a
== word!
>> type? second a
== word!

While they're still in an unevaluated block, type? and file! are still
just words. But when you do (that is, evaluate) that block, the correct
answer comes out:

>> do a
== datatype!

Here's another way to look at this:

>> a: ['type? file!]
== ['type? file!]
>> type? first a
== lit-word!
>> a: reduce a
== [type? file!]
>> type? first a
== word!
>> type? second a
== datatype!

First I made a block with one lit-word! and one word! . Then when I reduced
the block, the lit-word! was evaluated to a word! , and the word file! was
evaluated to its preset value, the datatype! file! . If we do that block:

>> do a
== datatype!

we still get the same answer, because when you evaluate a datatype! you
just get the same datatype! .


Now the problem with unset! is that there is no word set to the value
unset! . This is easily fixed:

>> unset: (type?)
== unset!
>> type? unset!
== datatype!

I put the paren around type? because if you do this in a script TYPE? will
take the value of whatever is next, but the paren prevents TYPE? from seeing
anything else.


You also wrote:

>>> type? file!
>== datatype!
>>> help file!
>file! is word of value: file
>
>This not ok!

It seems inconsistent, but this is the result of a REBOL trick. HELP has a
special way of specifying its argument:

help: func [
"Prints information about words and values."
'word [any-type!]
/local value args item refmode types
][

]

The argument is specified as a lit-word! (by using the ' ). This specifies
that if the argument is actually a word, that word is to be unevaluated.
That is, HELP wants to see the word itself, not what the word is set to.
This way you can use HELP to test if a word is set to a value:

>> help grog
No information on grog (word has no value)

Otherwise, trying to evaluate the word grog would result in an error
before HELP even had a chance to see it.

So, if you want to get help on the value that the word is set to, try this:

>> help (file!)
file! is datatype
>> help file!
file! is word of value: file

Putting the word file! in a paren prevents HELP from seeing it as a word.
So the paren is evaluated, the datatype! file! comes out, and HELP
tells you that the datatype! file! is a datatype.

One other little issue here is that there are two ways of representing a
value, forming and molding. Molding is better in that it gives you a string
that REBOL can use to get back the original value, but forming is supposed
to be easier on the eye. HELP forms the values, which is why you lose
the ! 's.


See you,
Eric



[REBOL] none

2000-02-26 Thread KGD03011


Hi folks,

I was just playing around with Ladislav's fix of SPLIT-PATH. I was
wondering why he converted the argument values to strings, since this
has the disadvantage that if the argument is a URL the result will
eventually get changed to a file.

Then I noticed something really weird:

>> path: file: %dir/file.ext
== %dir/file.ext
>> parse path [any [#"/" file: | skip]]
== true
>> file
== "file.ext"
>> insert path "parent/"
== %dir/file.ext
>> path
== %parent/dir/file.ext
>> head file
== "parent/dir/file.ext"

Even though we're parsing a file! , any pointer set within the parse
rule becomes a string! , and yet it's still pointing to the same
underlying data. It can't, however, be used as an index with COPY/PARSE:

>> parse path [any [#"/" file: | skip]]
== true
>> copy/part path file
** Script Error: Invalid /part count: file.ext.
** Where: copy/part path file

I never realized that you could view the same data with two different
datatypes. Is this intended? I think it would be much better to have
get-words in parse rules use the type of the data being parsed.


BTW, I agree with Andrew that this behavior of SPLIT-PATH is better
than Ladislav's fix (unless READ is also fixed to read the current
directory for %""):

>> split-path %file.ext
== [%./ "file.ext"]
>> read first split-path %file.ext
== [%USER.R %TALK.R %rebol.r %REBOL.exe ...

>> sp %file.ext; Ladislav's version
== [% %file.ext]
>> read first sp %file.ext
** Access Error: Cannot open /C/prog/rebol/.
** Where: read first sp %file.ext

See you,
Eric



[REBOL] format.r update on rebol.org

2000-02-23 Thread KGD03011


Hi,

I've just posted version 1.0.2 of format.r to rebol.org.

http://www.rebol.org/utility/format.r

It includes one bug fix and a couple of added features:

1. Option to insert commas in long numbers.

>> format 1e9 #..8
== "1,000,000,000"

2. Money values now formatted to various precisions:

>> format $20 / 3 #.4
== "$6.6667"

3. No longer chokes on values like set-word! and path! .

Have fun,
Eric



[REBOL] how to format the result of divide operation Re:

2000-02-18 Thread KGD03011


Hi Tiana,

There's a script on rebol.org called format.r that does that sort of thing
and more:

http://www.rebol.org/utility/format.r

>> format 1 / 3 #.1
== "0.3"
>> reformat [pi pi pi pi pi] [#.1 #.2 #.3 #.4 #.5]
== ["3.1" "3.14" "3.142" "3.1416" "3.14159"]


Hope it helps. Please send me any comments you have.

Cheers,
Eric

-

>Hello,
>
>Can anyone tell me how to format the result of divide operation?
>
>Say, 1 / 3 gave me the result 0.
>what can I do in order to get 0.3 which has only one digit after the point?
>
>Thanks for any information.
>
>Tiana






[REBOL] hostname parse rule Re:

2000-02-15 Thread KGD03011


Hi there,

This might be a good chance to plug my regular expression emulator,
search-text.r :)

http://www.rebol.org/utility/search-text.r

As far as I understand it, this should be the direct translation of the
BNF rule for hostnames as given by /PeO :

   let-char [*[let-digit-hyph-char] let-digit-char]

should be:

>> l: to-bits #!a-z; TO-BITS is included in search-text.r
== make bitset! #{ ; ! means upper and lower case
FE07FE07
}
>> ld: to-bits #!a-z0-9
== make bitset! #{
FF03FE07FE07
}
>> ldh: to-bits #!a-z0-9\- ; \ escapes the hyphen
== make bitset! #{
0020FF03FE07FE07
}
>> name-rule: [l 0 1 [any ldh ld]]
== [l 0 1 [any ldh ld]]

Unfortunately this almost never returns true when it should:

>> parse/all "abc-ef" name-rule
== false
>> parse/all "abcef" name-rule
== false
>> parse/all "a" name-rule
== true


This is very easy to do with SEARCH from search-text.r, and you don't
even have to prepare the bitsets beforehand:

>> search "abcdef" [head #!a-z  maybe [any #!a-z0-9\- #!a-z] tail]
== [1 6 "abcdef"]
>> search "abc-def" [head #!a-z  maybe [any #!a-z0-9\- #!a-z] tail]
== [1 7 "abc-def"]
>> search "abc--def" [head #!a-z  maybe [any #!a-z0-9\- #!a-z] tail]
== [1 8 "abc--def"]
>> search "abcdef-" [head #!a-z  maybe [any #!a-z0-9\- #!a-z] tail]
== none
>> search "0abcdef" [head #!a-z  maybe [any #!a-z0-9\- #!a-z] tail]
== none



SEARCH emulates the backtracking behavior of regular expressions.
PARSE on the other hand will match to the end of the line with
LET-DIGIT-HYPH-CHAR, leaving nothing for the last LET-DIGIT-CHAR to
match.


Actually, I have to admit this isn't so difficult with PARSE either.
You just have to look for sequences of any number of optional hyphens
followed by one or more alphanumerics:

>> name-rule: [l any [any "-" some ld ]]
== [l any [any "-" ld]]
>> parse/all "abcdef" name-rule
== true
>> parse/all "abc-def" name-rule
== true
>> parse/all "abc--def" name-rule
== true
>> parse/all "abcdef-" name-rule
== false
>> parse/all "0abcdef" name-rule
== false


See you,
Eric



[REBOL] Your invaluable assistance Re:

2000-02-12 Thread KGD03011


Hi Tim,

I enjoyed reading your description of your personal history and
your project. I don't know very much about web programming, but
I'll help when I can.

You wrote:

>P.S. I've got some ideas for a rebol "librarian",
>that could fetch reusable subroutines like the one
>the Eric wrote, and insert them into a project file.
>More about that later.

I'm not sure how necessary a project file is for REBOL programming,
at least at this stage. I never got to the point in C where I needed
a project file, but my understanding is that project files are handy
to speed up the process of compilation (so that you don't have to
recompile files if their code hasn't changed), and to link in compiled
libraries.

I think with REBOL you don't have to do (can't do) anything more
complicated than including files. A lot of us have written utilities
for this. I have one on rebol.org called dore.r that is a big help.
It indexes all the *.r files below the REBOL home directory. Then you
can do my-script.r with just:

   dore my-script; takes a word! argument

and,

   dore/maybe my-script

will do that script only if it hasn't been done. This is the statement
I use as an equivalent to an include statement. Also,

   dore/list my-script

will print out a list of functions and objects defined in that script.
I could send you the latest version if you're interested.

See you,
Eric



[REBOL] Inserting a series into a file Re:

2000-02-09 Thread KGD03011


Hi Tim,

I modified my last attempt to handle insertion of text as well. This
new version assumes that there's only one stretch of the file that
will be replaced.

Ladislav already told you the important point, although he didn't explain
it. Once you've inserted something into a series (or port), you can use
the return value of INSERT to get the position in the series following the
insert. This is great if you need to make several inserts.

Actually since this function only makes one replacement, it would have been
easier to remove the lines first and then make the insert, and not even
worry about where we are in the series after that. But it's just as well
to keep track of the position so it'll be easier to expand the code later.


In the previous thread you asked about reusing code in REBOL. There is
quite a lot of useful stuff on www.rebol.org, but it's all scripts that
people have posted - nothing that's been organized into a coherent library.
There are some folks who are working on improving rebol.org, but I don't
know how far they have gotten. I haven't noticed any changes yet.

See you,
Eric

==

replace-text: func [
fp [file!] "text file with lines to be updated"
rp [file!] "text file holding lines to be inserted"
][
fp: open/lines fp
rp: read/lines rp
lines_removed:  0
lines_inserted: 0
while [ not tail? fp ] [
if find first fp "begin replace here" [
print "found"
fp: next fp
lines_inserted: lines_inserted + length? rp
fp: insert fp rp
while [all [
not tail? fp
not find first fp "end replace here"
]][
lines_removed: lines_removed + 1
remove fp
]
break
]
fp: next fp
]
print [lines_removed "lines removed"]
print [lines_inserted "lines inserted"]
update fp
close fp
]



[REBOL] Why doesn't remove work? Re:

2000-02-08 Thread KGD03011


Hi Tim,

REMOVE removes by default the first element of a series. So when you say

remove first fp

the first element of FP is a string, and REMOVE will remove the first
element of that string. You want to zap the whole string, I take it,
so you should do:

remove fp

Here's a function based on your code to do what you want. I changed
remove-flag to a true/false flag, which is easier to test for. Also,
when you go through a series deleting some items and skipping others,
FORALL doesn't give you enough control. You have to use

while [ not tail? series-value ] [ ... ]

and use either NEXT or REMOVE every time you go through the loop.

remove-text: func [fp [file!]][
fp: open/lines fp
remove-flag: false
lines-done:  0
while [ not tail? fp ] [
if find first fp "begin insert here" [
print "found"
remove-flag: true
]
either remove-flag [
either find first fp "end insert here" [
remove-flag: false
print "done"
fp: next fp
][
either zero? lines-done [
print "setting lines-done"
lines-done: 1
fp: next fp
][
print ["Removing " first fp]
remove fp
]
]
][
fp: next fp
]
]
update fp
close fp
]

See you,
Eric



[REBOL] Need HELP with text fields and International characters Re:

2000-02-07 Thread KGD03011


Hi Carlos,

I've tried every way I could think of and nothing works.
I think this should be reported to feedback.

See you,
Eric


>Hi Rebols,
>
>How do I input international characters into text fields? It seems /View
>only accepts English chars. Am I correct?
>
>Carlos



[REBOL] New format.r on rebol.org Re:

2000-02-07 Thread KGD03011


Hi John,

It's a little harder to see what you're doing with all that HTML
formatting in your mail, but I think you can do what you want with:

write %filename.html reduce [  ..  ]

REDUCE will evaluate all those paths in the block like CGI/NAME etc.
PRINT does that automatically, but WRITE doesn't, so you have to
use REDUCE before you write it.

See you,
Eric



[REBOL] New format.r on rebol.org Re:

2000-02-06 Thread KGD03011


Hi Carl,

Thank you very much for your comments. I was discussing with Jerry and Larry
about the best value to use for passing the options, and wound up allowing
any value that could be formed to a reasonable string. I agree that
issues are the most suitable datatype.

#N.M always works as far as I know, and even N.M works as long as there are
no trailing zeroes. But given your preferences I will modify the script
to enforce #N.M and resubmit.

Thank you very much.

See you,
Eric

PS - I was trying to get carbon copies to work right on my mail program and
broke it, so the last message to the list didn't get a proper header. Hope
I've got it fixed now.

Here's revised code for the directory list function that I posted to
a related list, using the issue datatype as an argument to QC.

show-dir: func [
"List the specified directory. Inspired by Jos'h Fuller's DIR"
where [ file! ]  "Directory path."
/by 'sort-by [ word! ]   {Options are 'name (default) 'date 'size}
/desc"Sort in descending order"
/label   "Show column labels."
/local file files comp
][
sort-by: select reduce [none 1 'name 1 'date 2 'size 3] sort-by
comp: either desc [:greater?][:lesser?]
files: copy []
foreach file read where [
append/only files reduce [file   modified? file   size? file]
]
sort/compare files func [a b][
either a/:sort-by = b/:sort-by
[comp a/1 b/1][comp a/:sort-by b/:sort-by]
]
if label [insert/only files ["NAME" "DATE/TIME" "SIZE"]]
(qc files #40.0.2.1)
]



[REBOL] none

2000-02-06 Thread KGD03011

SubjectNew format.r on rebol.org Re:[EMAIL PROTECTED]@nifty.ne.jp (Eric 
Long)DateMon, 7 Feb 2000 11:22:09 +0900X-MailerREBOL 2.2.0
Hi Martin and Ted,

Martin wrote:

> <[EMAIL PROTECTED]> schrieb am Sun, 6 Feb 2000 16:31:37 +0900 $B—C(Ber
>"[REBOL] New format.r on rebol.org" in <[EMAIL PROTECTED]>:
>
>> The main reason for writing FORMAT (the main function in format.r) was the
>> lack of any control over how numbers are formed in REBOL. There are at least
>> three problems here that format.r solves:
>
>IMHO at least some of this functionality should actually go into
>REBOL/Core in some time.

I absolutely agree! Still, better to have this functionality in my kludgy
version, than not at all. If anyone has ideas on improvements, please
tell me!


Ted wrote:

>Did you use the mailbox to submit format.r or REBOL.ORG or the Web form?
>
>The Web form seems to be broken.

I just sent mail to rebol.org. Didn't try to use the Web form.

Even sending by mail there was a problem: The main index page wasn't
properly updated. I added the category MATH to the script, and that appeared
on the MATH index page. There are now seven scripts listed on that page, but
the main index page still says there are only six math scripts.

Also, my first update to search-text.r appeared among the new scripts on the
main index page. But this wasn't changed when I sent a second update. As a
result the main index page lists version 1.1, but if you click the link
you'll see version 1.2.

Anyway, I think it's best to send scripts to the rebol.org bot by mail,
and then announce them on the list. There haven't been very many new
scripts on rebol.org this year, so we ought to get some new stuff up
there and keep up the interest.


I've got a couple more scripts I wrote with Larry and Jerry that I'll be
posting probably by the end of the week.


See you,
Eric



[REBOL] New format.r on rebol.org

2000-02-05 Thread KGD03011


Hi,

I've just posted a thoroughly reworked version of format.r to rebol.org.
Please check it out.

http://www.rebol.org/utility/format.r

The information for the updated version doesn't appear on the index pages,
but the file itself has been replaced.

Larry Palmiter and Gerald Goertzel gave me enormous help in reworking
these functions into a more flexible and useful form.


The main reason for writing FORMAT (the main function in format.r) was the
lack of any control over how numbers are formed in REBOL. There are at least
three problems here that format.r solves:

1. You can't choose how many decimal points of precision to use.

>> form pi
== "3.14159265358979"

>> format pi %.4
== "3.1416"
>> format pi %.6
== "3.141593"

2. You can't choose between scientific and fixed point formats:

>> form pi / 100
== "3.14159265358979E-2"
>> form pi * 1e12
== "3141592653589.79"

>> format pi / 100 %.6
== "0.031416"
>> format pi * 1e12 %.4.1
== "3.1416E+012"

3. Often the formed value cannot be converted back to the original value:

>> x: 1 / 3
== 0.333
>> x - to decimal! form x
== 3.33066907387547E-16

>> full-form x   ; FULL-FORM also on format.r
== "3.333E-1"
>> x - to decimal! full-form x
== 0


There are other useful functions in format.r which can be used to
automatically display blocks in aligned columns. QT is used for simple
blocks:

>> arr: copy [] repeat x 25 [append arr log-e x]
== [0 0.693147180559945 1.09861228866811 1.38629436111989 ...
>> qt arr
0. 0.6931 1.0986 1.3863 1.6094 1.7918 1.9459 2.0794 2.1972 2.3026 2.3979
2.4849 2.5649 2.6391 2.7081 2.7726 2.8332 2.8904 2.9444 2.9957 3.0445 3.0910
3.1355 3.1781 3.2189

and QC for nested blocks, where each block contains a number of data fields:

>> arr: compose/deep [
[["pi" (pi)]
[["pi * pi" (pi * pi)]
[["exp pi" (exp pi)]
[["log-e pi" (log-e pi)]]
== [["pi" 3.14159265358979] ["pi * pi" 9.86960440108936] ["exp pi" ...
>> qc arr
pi3.14
pi * pi   9.87
exp pi   23.14
log-e pi  1.14


There's a whole lot more you can do with format.r. There are about 40
usage examples commented into the script to get you started.

Please send me any bugs you find, comments or suggestions! I'd be happy
to answer any questions about how to use the functions in format.r to
get the results you want.


Have fun,
Eric

===

Here's a directory display function based on one by Jos'h Fuller
that makes good use of QC:

show-dir: func [
"List the specified directory. Inspired by Jos'h Fuller's DIR"
where [ file! ]  "Directory path."
/by 'sort-by [ word! ]   {Options are 'name (default) 'date 'size}
/desc"Sort in descending order"
/label   "Show column labels."
/local file files comp
][
sort-by: select reduce [none 1 'name 1 'date 2 'size 3] sort-by
comp: either desc [:greater?][:lesser?]
files: copy []
foreach file read where [
append/only files reduce [file   modified? file   size? file]
]
sort/compare files func [a b][
either a/:sort-by = b/:sort-by
[comp a/1 b/1][comp a/:sort-by b/:sort-by]
]
if label [insert/only files ["NAME" "DATE/TIME" "SIZE"]]
qc files %40.0.2.1
]



[REBOL] Multidimensional arrays ...

2000-02-03 Thread KGD03011


Hi Petr,

You wrote:

>Could anyone elaborate on following, please?
>
>->> ar: array/initial [3 4] copy ""
>== [["" "" "" ""] ["" "" "" ""] ["" "" "" ""]]
>->>  change ar/1/1 "adfaf"
>== ""
>->> ar
>== [["adfaf" "adfaf" "adfaf" "adfaf"] ["adfaf" "adfaf" "adfaf" "adfaf"]
>["adfaf" "adfaf" "adfaf" "adfaf"]]
>
>How to simply write at any multidimensional array position? ar/:i/:j:
>value doesn't work ...

What happened in your example is that even though you used copy,
the same string was used to initialize every value in the array.
When you do CHANGE AR/1/1 you're changing that string, so the
change appears at every position in the array. You could do:

>> change ar/1 "adfaf"
== ["" "" ""]
>> ar
== [["adfaf" "" "" ""] ["" "" "" ""] ["" "" "" ""]]

Or you could do:

>> poke pick ar 1 1 "fafda"
== ["fafda" "" "" ""]

Or my favorite which is:

>> repoke ar [1 1] "fafda"
== ["fafda" "" "" ""]
>> source repoke
repoke: func [
"sets value within nested blocks"
block [block! hash! function! object!]
indexes [block!]
value [any-type!]
][
indexes: reduce indexes
while [1 < length? indexes] [
block: pick :block first indexes
indexes: next indexes
]
poke block first indexes value
]

Cheers,
Eric



[REBOL] tuple oddity

2000-02-03 Thread KGD03011


Hi,

Here's something weird I just noticed:

>> x: make tuple! [2 1]
== 2.1.0
>> third x
** Script Error: Value out of range: 3.
** Where: third x
>> length? x
== 2
>> x: make tuple! []
== 0.0.0
>> length? x
== 0

This kind of thing will only happen from a mistake in programming,
but debugging here would have been a lot easier if MAKE returned
an error when I tried to make a tuple out of less than three values.
Barring that, the resulting value shouldn't be displayed as a normal
three-value tuple if it only has one or two values.

In the program I was writing I intended to make a tuple with the third
value zero, so it was hard to understand why a value that looked just
like what I wanted wasn't working. If the extra zero(s) had actually been
supplied, the program would have done what I wanted and I'd have never
noticed my mistake, but I'd prefer to be forced to include all the values
explicitly.

Cheers,
Eric



[REBOL] Re:Arguments / refinements with default values

2000-02-03 Thread KGD03011


Hi Thomas,

I like your idea on how to provide default values for optional
arguments. I use arguments quite a bit in that way, and if FUNC
did that automatically it would make the code a bit cleaner.

The /tags refinement would make code involving calling functions with
complicated refinements much easier to understand. All you would have to
do is supply the one /tags refinement, and you wouldn't have to worry
about which order the tags are in versus which order the arguments are in.
The refinements would be right next to the values.


A similar capability is already built into some functions, such as
OPEN, where you can do:

file: open/mode %test.txt [binary new]

meaning the same as:

file: open/binary/new %test.txt

(This was from a message on the list from Jeff.)

Unfortunately this /mode refinement doesn't seem to allow passing of
arguments. It would be even more useful if you could do:

file: open/mode %test.txt [new with #"^L"]

to specify page-break as the line terminator.

Just a couple more ideas. I looked at the source of the function
you created:

my-function: func [
"My function"
a [string!] "required argument"
/b "A refinement" /c c-value [string!]
{An optional argument with the default value "Hello"}
/tags tag-list [block!]
"A block of words to set, ie [size: 50]"][
c: either c [c-value] ["Hello"]
if tags [
do bind (compose/deep tag-list) 'tags
]
print [a c]
]

The part

c: either c [c-value] ["Hello"]

Is not a good idea, since if somewhere else in the function you appended
something to C, the string "Hello" would change. Also, there's a slightly
more elegant way to do this check that I learned from a message from
Gabriele. (Oops, I see he answered before me.) Maybe the resulting code
should be something like:

c: any [c-value copy "Hello"]

But your function-making function would have to discriminate between
datatypes that needed to be copied, and those that didn't.


All this reminds me of another little idea I keep pushing:

>> unset!: (type?)
== unset!
>> say-hello: func[a [string!] b [string! unset!]]
[b: any [all [value? 'b b] "there!"] print [a b]]
>> say-hello "Hey"
Hey there!
>> say-hello "Hey" "man!"
Hey man!

This kind of optional argument has the disadvantage that something
that comes after might be taken as an unintended argument:

>> say-hello "Hey" s2: square-root 2
** Script Error: say-hello expected b argument of type: string unset.
** Where: say-hello "Hey" s2: square-root 2

so it's best in this case to always use the optional argument within
a program, unless you wrap it in parens, or it's at the end of a block:

>> (say-hello "Hey") s2: square-root 2
Hey there!
== 1.4142135623731
>> if now/time < 1:00 [say-hello "Hey"] s2: square-root 2
Hey there!
== 1.4142135623731

Nice talking to you,
Eric



[REBOL] mail question Re:

2000-01-30 Thread KGD03011


Hi Tom,

The short answer is, you use WRITE/APPEND instead of PRINT.

Here is the function I use to download the mail. It's really
primitive, but might give you some more ideas.

readmail: func [
{read mail from POP server}
/bak "save to a backup file with all header info"
/local mail url message bakfile emfile mail-directory
][
if not mail-directory: select directories 'mail [
mail-directory: %""
]
prin "Password: "
url: rejoin [
pop://
system/user/email/user
":" input/hide; get the user's the password
"@" system/schemes/pop/host
]
bakfile: join mail-directory %email.bak
emfile:  join mail-directory %email.em
mail: open url
while [ not tail? mail ] [
message: first mail
if bak [
write/append bakfile rejoin [
"^(page)^/"
message
]
]
message: import-email message
write/append emfile rejoin [
"^(page)" message/subject
"^/" message/from
"^/" message/date
either in message 'x-mailer [join "^/" message/x-mailer][""]
either all [in message 'cc message/cc] [join "^/" message/cc][""]
"^/^/" message/content
"^/"
]
remove mail
]
close mail
]


Cheers,
Eric



[REBOL] EBNF vs RE

2000-01-27 Thread KGD03011


Hi Joel,

I've been really frustrated too at how hard it is to do with parse
some very easy things for regexes. But for this kind job, parse is
great. You just have to embed a little code. This is what I did:

== Code:

testdata: [
  "Manager: John Doe [123 Jones St] ([EMAIL PROTECTED])"
  "Employee: Jane Doe ([EMAIL PROTECTED])"
  "Trainee: Bobby Shaftoe [555 Silver Buckle Ln] (no email)"
  "Contractor: Mary Lamb [ Shepherd's Cove, Apt 7]"
  "Executive: Mary Mary Q. Contrary"
]

nonbrack: complement to bitset! "([])"

foreach item testdata [
  print item
  set [title name address email] copy/deep ["" "" "" ""]
  parse item [
copy title to ":" skip  (trim title)
copy name some nonbrack (trim name)
any [
"[" copy address to "]" skip (trim address) |
"(" copy email to ")" skip (trim email)
]
  ]
  print join copy "^-" reduce [
"{" title "} {" name "} {" address "} {" email "}"
  ]
]

== Output:

Manager: John Doe [123 Jones St] ([EMAIL PROTECTED])
{Manager} {John Doe} {123 Jones St} {[EMAIL PROTECTED]}
Employee: Jane Doe ([EMAIL PROTECTED])
{Employee} {Jane Doe} {} {[EMAIL PROTECTED]}
Trainee: Bobby Shaftoe [555 Silver Buckle Ln] (no email)
{Trainee} {Bobby Shaftoe} {555 Silver Buckle Ln} {no email}
Contractor: Mary Lamb [ Shepherd's Cove, Apt 7]
{Contractor} {Mary Lamb} { Shepherd's Cove, Apt 7} {}
Executive: Mary Mary Q. Contrary
{Executive} {Mary Mary Q. Contrary} {} {}

==

Just a couple of observations, though I'm sure it's obvious to you now:

If spaces are not important for delimiting fields, it's easier to use
PARSE than PARSE/ALL. If you want to trim the spaces, it's easier to
do that with TRIM than with PARSE itself. This code allows address and
email to be in either order, though that's probably not an advantage in
this case. It's not always necessary for the parse to "succeed" (return
true) in order for it to do what you want, so the BLANKS END you used
at the end of your rule probably wasn't necessary. I put a COPY/DEEP in
there as insurance to reduce the chances of code revisions introducing
a you-know-what kind of bug.


Keep on shippin',
Eric



[REBOL] Polymorphic Re:

2000-01-27 Thread KGD03011


Hi Ladislav,

You're system of functions is quite amazing. I'm trying to digest
what you're aiming at, little by little.

I assume you meant:

register 'minus [integer! complex!] [] [
make complex [
re: a - b/re
im: - b/im   ; not im: b/im
]
]

I tried to register another combination of types:

register 'minus [complex! complex!][][
make complex [
re: a/re - b/re
im: a/im - b/im
]
]

And got this:

>> print mold _minus
make object! [
type: polymorphic!
args: [a b]
signatures: [integer! complex! complex! complex!]
implementations: [
func [a [any-type!] b [any-type!] /local][
make complex [re: a - b/re im:  b/im] ]
func [a [any-type!] b [any-type!] /local][
make complex [re: a/re - b/re im: a/im - b/im] ]
]
]

Shouldn't the signatures look more like:

 signatures: [[integer! complex!] [complex! complex!]]

? Because when you look for [complex! complex!] in the signatures
(that's what the function MINUS does) this happens:

>> find _minus/signatures [complex! complex!]
== [complex! complex! complex!]

That's going to lead to problems. I think each signature should be
within a nested block, and you should be using FIND/ONLY to look
for it.


I'm also a little puzzled by your latest PIF:

>pif: func [[throw]
>{
>polymorphic if
>lazy evaluation, minimum checking, no default
>compatible with:
>computed blocks
>Return
>Exit
>Break
>non-logic conditions
>}
>args [block!]
>] [
>if not unset? first args: do/next args [
>either first args [
>either block? first args: do/next second args [
>do first args
>] [
>first args
>]
>] [
>pif second do/next second args
>]
>]
>]

>> command: [print]
== [print]
>> pif [
false do append copy command "hello"
true do append copy command "goodbye"]
hello
goodbye

Is this what you intended?

Have a good one,
Eric



[REBOL] Polymorphic Re:

2000-01-26 Thread KGD03011


Hi Ladislav,

I did some investigation of the datatype test functions, such as
NUMBER? and BLOCK? I found they always return a logic value, no
matter what type of argument they have - even if it's UNSET! or
ERROR! I put together a number of functions testing for what you
called "predicate types". Here's an example from huh.r . This
merely excludes the most numerous datatypes, so HUH can print out
the names of all the blocks, strings, numbers etc, so that you
can check whether some function is leaking into the global context
(due to spelling error or whatever).

data?: func [
{returns TRUE for all data types except unset,
any-function and datatype}
value [any-type!]
][
all [
value? 'value
not any-function? :value
not datatype? :value
]
]

(Actually this is a streamlined version inspired by your post.)

In these functions you have to use [any-type!] in the header so that the
function will accept any value at all. Then it's important to check whether
the argument has a value. Otherwise, if the argument is unset anything else
you try to do with it will cause an error. Then it's a good idea to use
the get-word form of the argument until you're sure it's not an
ANY-FUNCTION! PAREN! SET-WORD! PATH! SET-PATH! - all these will produce
errors too. Then finally, if you want to look at the argument with anything
except another datatype test function, you have to be sure it's not an
ERROR!

Your NONZERO? could be done this way:

nonzero?: func [
{returns TRUE if not zero, but belongs to a type that has zeros}
value [any-type!]
][
all [
value? 'value
any [; all the types that have zero values
number? :value
char? :value
money? :value
time? :value
tuple? :value
]
not zero? value
]
]

I put it into a standard format, so that it will return true with the
following function:

type-tester?: func [
{Returns TRUE if VALUE is a datatype test function}
value [any-type!]
][
all [
value? 'value
any-function? :value
find/only third :value reduce [any-type!]
not find third :value lit-word!
string? first third :value
found? find first third :value "Returns TRUE"
]
]

>> huh * type-tester?

@@ action!
action?any-block? any-function?  any-string?any-type?
any-word?  binary?bitset?block? char?
datatype?  date?  decimal?   email? error?
file?  function?  get-word?  hash?  integer?
issue? list?  lit-path?  lit-word?  logic?
money? native?none?  number?object?
op?paren? path?  port?  refinement?
series?set-path?  set-word?  string?tag?
time?  tuple? unset? url?   word?

@@ function!
data? nonzero?  not?  type-tester?


Catch you later,
Eric


 You wrote:

3) Predicate Types vs. Pseudotypes

Pseudotypes are something added for the sake of conciseness, I
think.They can be simulated through Predicate Types as follows:

num?: func [x [any-type!]] [
any [integer? x decimal? x]
]

Predicate types are normally weak, as can be seen here from 1),
but you can have predicate types like:

nonzero?: func [x [any-type!]] [
all [number? x not zero? x]
]

, which may be of some use.

So, to finish this part: the Rebol typesystem is strong, the
organic approach should take that into account together with the
stress on the internal representation.

Bye 4 now



[REBOL] Polymorphic Re:

2000-01-26 Thread KGD03011


Hi Ladislav,

Except - doesn't work the same as SUBTRACT unless it's used as an infix:

>> bop - [3 2 1] [1 1 1]
== [-3 -2 -1]

I thought of providing special processing to switch SUBTRACT for - ,
but thought it would be more fun to use the operators as infixes.

Catch you later,
Eric

 You wrote:

Nice try, but it is only a more complicated version of:

bop: func [
{returns the results of operating on elements of b with those of bb -
last element of bb will be reused if necessary}
'op [word!] "name of function to use"
b [block!]
bb
/local r
][
op: get in system/words op
r: copy []
if not block? bb [bb: reduce [bb]]
while [not tail? b] [
append r op first b first bb
b: next b
if 1 < length? bb [bb: next bb]
]
r
]

>> bop / [4 2] 2
== [2 1]

, which is a pure prefix matter ;-)



[REBOL] Patches to REBOL 2.2.0 Re:

2000-01-25 Thread KGD03011


Hi Andrew,

You can do Patch_to-func a lot more easily if you use the latest version
of HUH (not yet available on rebol.org).

>> patch_to-func
Can't convert to-bin
Can't convert to-bin2
Can't convert to-bits
Can't convert to-idate
Can't convert to-matrix
Can't convert to-native; this isn't what you think!
>> source to-paren
to-paren: func ["Converts to paren value." value "Value to convert"]
[to paren! :value]
>> source to-money
to-money: func ["Converts to money value." value "Value to convert"]
[to money! :value]


See you,
Eric

==

Patch_to-func: function [][Old_to-Func][
foreach to-type huh/ret "to-*" function? [
Old_to-Func: get to-type
either 'value = last second :Old_to-func [
do reduce [
to set-word! to-type
'func
copy third :Old_to-func
head change back tail copy second :Old_to-func first 
[:value]
]
][print ["Can't convert" to-type]]
]
]

; new HUH (actually it's old - never got around to posting it)
; /verbose and /ret refinements not available in the one on rebol.org
; /verbose can be very very verbose!

huh: func [
{Print a list of globally defined words classified by datatype}
'pattern [word! string! unset!]  "matching pattern (. and * wild)"
'type[word! unset!]  "datatype test function (eg series?)"
/any {displays words containing any type of value, even unset}
/verbose {display help for all words}
/wc  {use ? and + for wild cards}
/ret {return the block of words}
/local tester word-array this-type ret-block
][
either value? 'type [
if unset? get/any type [
print [type "has no value"]
exit
]
tester: get type
if datatype! = type? :tester [
tester: get to-word head change back tail mold tester "?"
]
if not type-tester? :tester [
print [type "is not a datatype test function"]
exit
]
if do [tester] [any: true] ; if tester is UNSET? or ANY-TYPE?
][ tester: none ]

either wc [wc: "?+"][wc: ".*"]
either value? 'pattern
[pattern: to-string pattern]
[pattern: to-string last wc]   ; assign wildcard to match any string

word-array: copy []; to hold matching words
foreach word first system/words [
this-type: mold type? get/any word: in system/words word
if all [
system/words/any [
this-type <> "unset!"  ; ignore unset values
any; unless we got the /any refinement
]
system/words/any [
not :tester; unless we aren't using tester,
tester get/any word; check with datatype test function
]
"" = find/match/with word: mold word pattern wc
][
either find word-array this-type
[append select word-array this-type word]
[append word-array reduce [this-type reduce [word]]]
]
]
either tail? word-array [
print "no matching words found"
][
if ret [
ret-block: copy []
foreach [this-type word-block] word-array [
foreach word sort word-block [
insert tail ret-block in system/words to-word 
word
]
]
return ret-block
]
foreach [this-type word-block] sort/skip word-array 2 [
print join newline ["@@ " this-type]
either verbose [
foreach word sort word-block [
prin join ">> " [word ": "]
either any-function? get/any to-word word [
do join "help " word
print ""
][
either this-type = "unset!" [
print "has no value"
][
either this-type = "error!" [
print mold disarm get 
to-word word
][
word: get to-word word
either this-type = "object!" [
print ""
qt first word

[REBOL] Polymorphic Re:

2000-01-25 Thread KGD03011


Hi Ladislav,

What do you think of this? It's sort of polymorphic, but it's not the
right approach to handle complex numbers.

bop: func [
{returns the results of operating on elements of b with those of bb -
last element of bb will be reused if necessary}
'op [word!]   "name of function to use"
b   [block!]
bb
/local r -
][
op: get in system/words op
if op? :op [set '- :op]
r: copy []
if not block? bb [bb: reduce [bb]]
while [not tail? b] [
append r either :- [(first b) - (first bb)][op first b first bb]
b: next b
if 1 < length? bb [bb: next bb]
]
r
]

>> bop * [$2.00 $1.53] 2
== [$4.00 $3.06]
>> bop ** [2 3 4] [4 3 2]
== [16 27 16]
>> bop and [1 2 3 4 5 6 7 8] 5
== [1 0 1 4 5 4 5 0]

See you,
Eric



[REBOL] State Machine re:

2000-01-25 Thread KGD03011


Hi,

Elan wrote:

>to word! and make word! work:
>
>>> new-word: to word! :item
>== word
>>> new-word
>== word
>>> new-word: make word! :item
>== word
>>> new-word
>== word
>
>whereas to-word fails:
>
>>> new-word: to-word :item
>** Script Error: word needs a value.
>** Where: to word! value

Gabriele pointed out this or a similar problem with the to- functions.
They should really all be rewritten like this:

>> source to-word
to-word: func ["Converts to word value." value "Value to convert"]
[to word! value]
>> to-word first [this: that]
** Script Error: this needs a value.
** Where: to word! value
>> to-word: func ["Converts to word value." value "Value to convert"]
[to word! :value] ; last item should be a get-word
>> to-word first [this: that]
== this

This is a problem for (at least) value arguments that are set-words, parens
and paths. Another example:

>> to-block first [this/is/just/a/path]
** Script Error: this has no value.
** Where: to block! value
>> source to-block
to-block: func ["Converts to block value." value "Value to convert"]
[to block! value]
>> to-block: func ["Converts to block value." value "Value to convert"]
[to block! :value]
>> to-block first [this/is/just/a/path]
== [this is just a path]

See you,
Eric



[REBOL] Datatype hierarchy Re:

2000-01-25 Thread KGD03011


Hi Gabriele,

>Hi!
>
>I remember someone once posted a little C program that was able to
>execute a command from a REBOL-created file. Could anyone send it
>to me?
>
>Thanks in advance,
>Gabriele.

Is this it?

===

Executing system commands from the REBOL console
[EMAIL PROTECTED]
19-Dec-1999/10:08:05-5:00

Under windows 98 the following cpp program will execute system commands
from the REBOL console. If the version of dos used supports redirections,
the output, if any, will appear on the console screen. If not, the results
will appear in the dos box from which command.exe has been invoked. I use
4dos, which does support redirection. The cpp file was compiled using
Borland C++.

Jerry

#include 
#include 
#include 
#include 
void main()
{
   FILE *fp;
   while(5==5)
{
  sleep(2);
  if (fp = fopen("f.bat","rt"))
  {
 system("f.bat >& c.txt");
 fclose(fp);
 sleep(2);
 system("erase f.bat");
  }
   }
}

The REBOL function to invoke the system call is:

dos: func [cmd][
write %f.bat cmd
wait 2
print read %c.txt
exit
]




[REBOL] Printing decimal values Re:

2000-01-24 Thread KGD03011


Hi Michal, Joel,

Very very sorry. I forgot to mention that to use FORMAT you have to
first set the value of the word 'unset!

unset!: (type?)

Or if you don't want to use optional arguments, you can change the
header of FORMAT to:

format: func [
{CONVERTS Rebol data into formatted strings.}
item "value or block of values to format - block values are reduced first"
decimal [integer! block!]  {decimal places to leave (2 by default)}
width [integer! block!]{width of formatted string}
/full  "use extra precision in forming decimal values"
/local n neg p factor exponent
][ ... ]

Whoops!

Eric



[REBOL] Printing decimal values Re:

2000-01-24 Thread KGD03011


Hi Michal, Joel,

I've had format.r up on rebol.org for a long time, hoping someone
would give me a good idea on how to improve it. Joel's ROUND is a
great idea. First, here's a version of ROUND that can handle values
where to-integer chokes, fractions less than one, and negative numbers:

round: func [n [number!] p [integer!] /local factor neg] [
if negative? n [n: (- n)  neg: true]
factor: 10.0 ** p
n: n * factor + 0.5
n: n - (n // 1) / factor
either neg [- n][n]
]

Now I've made a new version of FORMAT, which uses the logic of ROUND and
produces a string representation in decimal format, pads with zeros, etc.
It also will format all the values in a block in one go. Note that REBOL
forms any value less than .1 into exponential notation, you have to use a
special formatting function to get it into decimal format. It's really
incredible that a language that prides itself on being readable to humans
doesn't have a standard way to do this.

>> pi / 100
== 3.14159265358979E-2
>> round pi / 100 5
== 3.142E-2
>> format pi / 100 5
== "0.03142"

Note that FORMAT has a refinement /full which won't work without the
function FULL-FORM. I've been working on this with Larry Palmiter and
Gerald Goertzel. It'll be available on rebol.org in a couple of days.
FULL-FORM is meant to give the simplest possible string representation
of a decimal value that will load back to exactly the same value.

>> form pi
== "3.14159265358979"
>> pi - load form pi
== 3.10862446895044E-15   ; not equal!
>> full-form pi
== "3.141592653589793"
>> pi - load full-form pi
== 0  ; equal!

Have fun,
Eric

===

format: func [
{CONVERTS Rebol data into formatted strings.}
item "value or block of values to format - block values are reduced first"
decimal [integer! block! unset!]
{optional decimal places to leave (2 by default)}
width [integer! block! unset!]
{optional width of formatted string}
/full  "use extra precision in forming decimal values"
/local n neg p factor exponent
;
; Examples:
;
;>> print format [pi exp 1]
;3.14 2.72
;>> print format [pi exp 1] 4  ; specifying precision
;3.1416 2.7183
;>> print format [pi exp 1][4 8]   ; using different precisions
;3.1416 2.71828183
;>> print format [pi exp 1] 4 10   ; pad with spaces
;3.1416 2.7183
;>> format pi * 1000 -2; round off to nearest hundred
;== "3100"
;>> print format pi 16
;3.1415926535897900; precision given by FORM
;>> print format/full pi 16
;3.1415926535897930; maximum precision
;>> print format exp 1 16
;2.7182818284590500
;>> print format/precise exp 1 16
;2.7182818284590452
;
; Note: DECIMAL must be specified before specifying WIDTH. Making DECIMAL and
; WIDTH optional is for convenience when entered at the prompt. Both should
; be specified within programs.
;
][
if not value? 'decimal [ decimal: 2 ]  ; supply defaults if needed
if not value? 'width   [ width: 0 ]
if object? item[ item: next second item ]
either any-block? item [
if integer? decimal[ decimal: reduce [decimal] ]
if integer? width  [ width: reduce [width] ]
n: to block! reduce item   ; won't change values in lists and hashes
while [not tail? n][
either any-block? first n [   ; recurse with all format values
change/only n format first n head decimal head width
][  ; use current format value
change/only n format first n first decimal first width
]
n: next n
; get next format values, or reuse the last one
if 1 < length? decimal [ decimal: next decimal ]
if 1 < length? width   [ width:   next width   ]
]
][
if block? decimal  [ decimal: first decimal ]
if block? width[ width:   first width ]
if not number? decimal [ decimal: 2 ]
if not number? width   [ width: 0 ]
either number? item [
if negative? item [item: (- item)  neg: true]
factor: 10 ** decimal
item: item * factor + 0.5
item: item - (item // 1)
n: either full [full-form item][form item]
if p: find n "." [
if 2 <> index? p [make error! "FORMAT: funny decimal point"]
remove p
p: remove find n "E"
exponent: to integer! p
clear p
insert/dup tail n "0" exponent + 1 - length? n
]
if positive? decimal [
insert/dup n "0" 1 + decimal - length? n
insert skip tail n (- decimal) "."
]
if all [
negative? decimal
n <> "0"
][insert/dup tail n "0" (- decimal)]
if neg [insert n "-"]
][
n: form item
]

[REBOL] Polymorphic Re:

2000-01-23 Thread KGD03011


Hi Ladislav,

You wrote:

>Sorry for disappointing you, but the proposed version doesn't
>handle correctly the computed blocks and Break. A different
>approach:

Actually you haven't disappointed me, because I didn't intend to
handle computed blocks, and BREAK seems to work as well as I'd hope
it to. But since you as the author of PIF have the final say as
to what is correct and incorrect behavior, I'll rename my reworking
of your function to REIF and try to explain clearly what I had
in mind. Note that this is a revision of my original suggestion to
Joel, but its handling of blocks and BREAK is still basically
the same.


REIF takes a block argument of the following structure:

[
sub-expression value
sub-expression value
...
sub-expression value
optional-value
]

Each sub-expression is evaluated until one returns a true value (i.e.
anything but NONE or FALSE). If the value following that sub-expression
is a block, its contents are evaluated and the return value is returned.
If that value is anything besides a block, it is returned. Any value
following a sub-expression that evaluates false is skipped over. If no
sub-expression returns a true value and there is a final optional-value,
it is handled as if it were a value following TRUE. If there is no
optional-value, FALSE is returned.

That's pretty simple-minded, I'll agree, but that's how I wanted it.
Here're a couple of examples of it in use:

>> for x 1 10 1 [ reif [
[zero? x // 2 [print [x "is even"]]
[x = 5[print [x "and no more!"] break]
[]]
2 is even
4 is even
5 and no more!

>> foreach x [
["various" "strings" "to test" "and examine" "with find and reif"
[][ reif [
[find x "x" [print "it's got an x - bailing out!" break]
[p: find x " " [print ["it's got a space at" index? p]]
[]]
it's got a space at 3
it's got an x - bailing out!

With your latest version of PIF this happens:

>> foreach x [
["various" "strings" "to test" "and examine" "with find and pif"
[][ pif [
[find x "x" [print "it's got an x - bailing out!" break]
[p: find x " " [print ["it's got a space at" index? p]]
[]]
== " find and pif"

which isn't so useful. If FIND returns a true value, you might want to
do something with that value before returning. I don't see why you
should restrict doing the following block only to those cases where
the sub-expression actually returns the logic value TRUE.

I'd be very happy to hear more about what you intended with PIF,
and where you think REIF could be improved.

Thanks again,
Eric

== code ==

reif: func [
[throw]
{if with multiple conditions - descended from,
but not to be confused with, PIF by Ladislav Mecir}
args [block!]
/local choice
] [
choice: false
while [not tail? args] [
if 1 = length? args [
choice: first args
break
]
args: do/next args
if all [
not unset? first args
first args
][
choice: first second args
break
]
args: skip second args 1
]
either block? choice [do choice][choice]
]

reif2: func [
[throw]
{recursive multiple-choice if - thanks Ladislav!}
args [block!]
/local choice
] [
either 1 = length? args [db first args][
args: do/next args
either all [
not unset? first args
first args
][
db first second args
][ reif2 skip second args 1 ]
]
]

db: func [[throw] arg] [
either block? arg [do arg] [arg]
]

pif: func [[throw]
{polymorphic if, lazy evaluation, minimal checking}
args [block!]
] [
either unset? first args: do/next args [] [
either first args [
either logic? first args [
db first do/next second args
] [
db first args
]
] [pif second do/next second args]
]
]



[REBOL] Nondeterministic REBOL (was: Polymorphic) Re:

2000-01-22 Thread KGD03011


Hi Joel,

Your non-deterministic control structures are very very interesting. I'm
going to have to play with them a bit before I can tell whether I'll want
to use them regularly, but the ideas behind them are definitely worth
pondering.

It took me a little while to catch on to what EWD/DO is up to, though on
rereading your explanation I see that it was very clear. At first I thought
it just did each true conditions once in random order.

Just a thought, but EWD/DO might be useful as a control structure for
servers - waiting for input and responding to it each time in a
non-deterministic way, to keep the clients interested. I think it could be
used in this way as-is, by sandwiching a wait-for-input instruction into the
first condition with ALL, but perhaps it would be nicer to have a more
explicit way to do this.

Also, just for the sake of a little more non-determinism it would be nice
to have _REDUCE evaluate the conditions themselves in a random order, but I
don't think DO/NEXT would be quite up to the job.



I've played around a little more with Ladislav's PIF to get it more to my
liking. It doesn't go beyond C-style if ... else if ... else, but at least
it's more flexible than SWITCH and easier to read than nested EITHERs.
Doubt this will be of use to you - it succumbs to the "fall through the
default" temptation - but here goes:

pif: func [
[throw]
{polymorphic if with lazy evaluation and minimal checking}
args [block!]
/local choice
] [
choice: false
while [not tail? args] [
if 1 = length? args [
choice: first args
break
]
args: do/next args
if all [
not unset? first args
first args
][
choice: first second args
break
]
args: skip second args 1
]
either block? choice [do choice][choice]
]


testcase: func [a b /local c] [
pif [
a < b [c: b - a print [b "-" a "=" c]]  ; block is DOne
a > b {c: a - b print [a "-" b "=" c]}  ; other values just returned
"they're equal" ; last single item is default
]
]

>> testcase 3 5
5 - 3 = 2
>> testcase 5 3
== {c: a - b print [a "-" b "=" c]}
>> testcase 5 5
== "they're equal"

See you,
Eric



[REBOL] Polymorphic Re:

2000-01-22 Thread KGD03011


Hi Joel,

How about this variation of Ladislav's function?

pif: func [
[throw]
{polymorphic if with lazy evaluation and minimal checking}
args [block!]
] [
result: false
while [not empty? args] [
args: do/next args
either all [
not unset? first args
first args
][
args: first second args
break
][
args: skip second args 1
]
]
if args [do args]
]

testcase: func [a b] [
pif [
a < b [print [a "<" b]]
a = b [print [a "=" b]]
a > b [print [a ">" b]]
]
]

paranoid: func [a b] [
pif [
a <= 0 [return 0]
b <= 0 [return 0]
]
print "Computing now!"
]


>> testcase 2 3
2 < 3
>> testcase 2 1
2 > 1
>> testcase 5 5
5 = 5
>> paranoid 4 6
Computing now!
>> paranoid 4 -6
== 0
>> paranoid -4 6
== 0

Cheers,
Eric



[REBOL] Modify an array element Re:

2000-01-18 Thread KGD03011


Hi Joel,

I think this is a better generalization:

>> source repoke
repoke: func [
"sets value within nested blocks"
block [block! hash! function! object!]
indexes [block!]
value [any-type!]
][
indexes: reduce indexes
while [1 < length? indexes] [
block: pick :block first indexes
indexes: next indexes
]
poke block first indexes value
]

>> a3: array [3 3 3]
== [[[none none none] [none none none] [none none none]] [[none none ...

>> repoke a3 [1 1 1] "something"
== ["something" none none]
>> a3
== [[["something" none none] [none none none] [none none none]] [[none ...

plus it's companion:

>> source repick
repick: func [
"picks repeatedly"
block [any-block! any-function! object!]
indexes [block!]
][
foreach i reduce indexes [block: pick :block i]
:block
]


Eric

>Try the following...
>
>>> a: array [4 4]
>== [[none none none none] [none none none none]
>[none none none none] [none none none none]]
>>> a
>== [[none none none none] [none none none none]
>[none none none none] [none none none none]]
>>> poke pick a 2 3 "Hello!"
>== [none none "Hello!" none]
>>> a
>== [[none none none none] [none none "Hello!" none]
>[none none none none] [none none none none]]
>
>Sorta uly, but easy to wrap into a func ...
>
>>> set2d: func [b [block!] d1 [integer!] d2 [integer!] x] [
>[poke pick b d1 d2 x
>[]
>>> set2d a 3 2 "Goodbye!"
>== [none "Goodbye!" none none]
>>> a
>== [[none none none none] [none none "Hello!" none]
>[none "Goodbye! none none] [none none none none]]
>
> and to generalize ...
>
>>> a3: array [3 3 3]
>== [[[none none none] [none none none] [none none none]]
>[[none none none] [none none none] [none none none]]
>[[none none none] [no...
>>> set3d: func [
>[b [block!] d1 [integer!] d2 [integer!] d3 [integer!] x][
>[poke pick pick b d1 d2 d3 x
>[]
>>> set3d a3 1 2 3 "YOW!"
>== [none none "YOW!"]
>>> a3
>== [[[none none none] [none none "YOW!"] [none none none]]
>[[none none none] [none none none] [none none none]]
>[[none none none] [...
>>>
>
> to even higher planes of existence.
>
>-jn-




[REBOL] Datatype Hierarchy Re:

2000-01-18 Thread KGD03011


Hi Elan,

Thanks for the comments, and thanks for the term "type designator". I wasn't
sure what to call it. But I'm not sure we understand each other yet. I
glossed over a few too many things.

>you report that
>
 third :f
>>== [x [decimal!]]
 first second third :f
>>== decimal!
 type? first second third :f
>>== datatype!
>
>in other words, the type designator we provided when we constructed the
>function
>a) continues to be a type designator as demonstrated by
 type? first second third :f
>>== datatype!
>b) it is the type designator we originally used to construct the function
 first second third :f
>>== decimal!

The original type designator, as I tried to point out before, was a word,
not a datatype.

This time let's store the specification of F in a block before we make F.

>> spec: [x [integer!]]
== [x [integer!]]
>> first second spec
== integer!
>> type? first second spec
== word!

So the type designator here is a word.

>> f: func spec [x * x]
>> third :f
== [x [integer!]]
>> first second third :f
== integer!
>> type? first second third :f
== datatype!

Now the type designator in the "compiled" F is a datatype, though it looks
the same. And notice that the type designator in the original spec block
is still a word:

>> type? first second spec
== word!

Now this is why I was so interested in your mention of past behavior of
REBOL. If we do the same thing with

>> system/version
== 2.0.4.3.1

We see basically the same thing happening:

>> spec: [x [integer!]]
== [x [integer!]]
>> type? probe first second spec
integer!
== word!
>> f: func spec [x * x]
>> third :f
== [x [integer!]]
>> type? probe first second third :f
integer!
== datatype!

But this is where the bug was:

>> type? probe first second spec
integer!
== datatype!

The spec block used in the construction of F was altered, so if we reuse it:

>> ff: func spec [x * x]
>> source ff
ff: func [x [datatype!]][x * x]

We get a different function than the first one - in this case one that
will give an error for any input. This is exactly the result we get with
the current version of REBOL doing:

>> ff: func third :f second :f
>> source ff
ff: func [x [datatype!]][x * x]

So one bug was fixed, presumably by having MAKE deep copy the original spec
block before using it to construct the function. But you still can't use the
spec block integrated into the function in constructing yet another function,
unless of course you want a function that requires datatypes as arguments.

I don't think this qualifies as a serious problem, but once I did try to
use THIRD :F in this way, saw that it didn't work, and got curious. That's
why I called it a "puzzle".

Now I've gotten myself all steamed up about words and datatypes again ;-)
so I think I'll start a new message and go over yet again what for me is the
most important issue regarding datatypes.

Your comments will be as ever most appreciated.

Thanks,
Eric



[REBOL] more (useful) REBOL arcana on datatypes

2000-01-18 Thread KGD03011


Hi,

A message from Elan got me foaming at the mouth about datatypes (it's not
Elan's fault, so don't blame him!), so if anyone out there is interested ...
(and sorry for shamelessly plugging my scripts - if people would just send
me a little feedback I wouldn't have to do this ;-)

If you haven't used HUH (available on rebol.org) yet, here's how you can
get a list of all the datatypes bound to words:

>> huh * datatype?

@@ datatype!
action!any-block! any-function!  any-string!any-type!
any-word!  binary!bitset!block! char!
datatype!  date!  decimal!   email! error!
file!  function!  get-word!  hash!  integer!
issue! list!  lit-path!  lit-word!  logic!
money! native!none!  number!object!
op!paren! path!  port!  refinement!
series!set-path!  set-word!  string!symbol!
tag!   time!  tuple! unset! url!
word!

Notice that in REBOL off-the-site, the datatypes ACTION! and UNSET! are
not assigned to words.

>> type? unset!
** Script Error: unset! has no value.  ; fresh instance of REBOL
** Where: type? unset! ; with no scripts run
>> type? action!
** Script Error: action! has no value.
** Where: type? action!

This was the very first "bug" I pointed out to feedback (the first time was
last July), and probably the easiest one to correct:

>> unset!: (type?)
== unset!
>> action!: type? :action?
== action!
>> type? unset!
== datatype!
>> type? action!
== datatype!

but it's still unfixed! Bo told me it was probably because there's no use
for it. Yet there is a use for defining the word unset!. One place I use
it is in FORMAT, from format.r (also on rebol.org).

>> format pi
== "3.14"
>> format pi 4
== "3.1416"
>> format pi 6
== "3.141593"
>> format pi "6"
** Script Error: format expected decimal argument of type: integer block unset.
** Where: format pi "6"

Notice the specification of FORMAT:

format: func [
"CONVERTS Rebol data into formatted strings."
item {value or block of values to format - block values are reduced first}
decimal [integer! block! unset!]
"optional decimal places to leave (2 by default)"
width [integer! block! unset!]
"optional width of formatted string"
/full "use extra precision in forming decimal values"
/local digits non-zero n fraction exponent neg
][  ]

Normally you can specify an optional argument by using any-type!, but then
your function will accept anything at all. To set up an optional argument
that will accept only certain types of data, you have to have the word
'unset! set to the datatype unset! .

Notice that there's a danger in using optional arguments like this. If you
use FORMAT within a script, and don't want to provide all three arguments,
it had better be at the end of a block or paren, or FORMAT will try to
use something else as an argument that you didn't intend!

Have fun!

Eric



[REBOL] Problems with blocks Re:

2000-01-18 Thread KGD03011


Hi Andrew,

>Short and somewhat surprising:
>>> [.]
>== [.]
>>> [,]
>** Syntax Error: Invalid word -- ,.
>** Where: (line 1) [,]

I think it's because Carl really hates commas. ;-)

But seriously, for some reason, the only place REBOL seems to use commas is
as an alternative decimal point in numbers.

You can put almost anything in a block, but it has to be loadable - meaning
REBOL can parse it and recognize everything in the block as some kind of
datatype. For example you can't do this:

>> [223abc]
** Syntax Error: Invalid integer -- 223abc.
** Where: (line 1) [223abc]
>> [22.3abc]
** Syntax Error: Invalid decimal -- 22.3abc.
** Where: (line 1) [22.3abc]

REBOL won't parse anything beginning with digits that doesn't turn out to
be a valid number. REBOL allows a lot of characters as parts of words that
most other languages don't allow in variable names:

   ? ! . ' + - * & | = _ ~  (from the beta manual)

which fosters the impression that "anything goes", but that's not quite the
case:

>> [abc,def]
** Syntax Error: Invalid word -- abc,def.
** Where: (line 1) [abc,def]

So apparently when REBOL tries to load a single comma, it doesn't have any
other evidence as to what kind of data type you meant, so assumes you
meant a word.

>The first example uses a full stop ".", the second uses a comma ",". Now
>this:
>
>>> [1,2]
>== [1.2]
>
>Note that the comma changed to a full stop.

So here REBOL parses "1,2" as a decimal, and shows it back to you in the
"standard" way. A decimal value has no way to "remember" the original form
it was parsed from:

>>> [12.30]
>== [12.3]
>
>>> [%]
>** Syntax Error: Invalid file -- %.
>** Where: (line 1) [%]

You can construct a valid filename of length zero this way:

>> [%""]
== [%]

>I was under the impression a block could contain virtually anything and was
>not evaluated. What about a block containing, perhaps some JavaScript code:

Well, no. Blocks have to contain valid items of data, or you could never use
functions like FIRST, PICK, NEXT  on them.

>
>>> c: [test (1, 2)]
>== [test (1 2)]
>>> c
>== [test (1 2)]
>
>I wonder where the "," went?

The same place the "." goes:

>> [test (1. 2)]
== [test (1 2)]

If you want to store code from alien languages, maybe you should consider
using strings. ;-)

See you,
Eric

>I've sent this to [EMAIL PROTECTED]
>
>It would be nice if blocks were slightly less processed.
>
>Andrew Martin
>ICQ: 26227169
>[EMAIL PROTECTED]
>http://members.xoom.com/AndrewMartin/
>-><-



[REBOL] Datatype Hierarchy Re:

2000-01-18 Thread KGD03011


Hi Elan,

>I don't really think this qualifies as a puzzle, does it? A similar
>phenomenon was discussed in June 1999, first reported by Gisle. Gabriele
>pointed out at the time (We are speaking REBOL version 2.0 or 2.1):

Guess not, but it's a subject I'm interested in.

Thanks for the quotes - that was about a month before I first joined the
list. I went back to the earliest version I have, and that's how it works
all right. Very interesting.

Anyway, here's how I understand the question I raised.

>>Why does this happen?
>>
 array2: func third :array second :array
 array2 8
>>** Script Error: array2 expected size argument of type: datatype datatype.
>>** Where: array2 8

It happens is that you can specify datatype arguments in the SPEC argument to
FUNC with either words, or datatype samples:

>> source f
f: func [x [integer!]][x * x]
>> f: func [x [6]][x * x]
>> source f
f: func [x [integer!]][x * x]

The result is exactly the same. If you specify the type of X with a word,
REBOL will get the value of the word, and use it only if that value is
a datatype:

>> f: func [x [y]][x * x]
** Script Error: Invalid argument: y.
** Where: func [x [y]] [x * x]
>> y: decimal!
== decimal!
>> f: func [x [y]][x * x]
>> source f
f: func [x [decimal!]][x * x]

Now once you've created a function, the specification of the function can
be accessed with THIRD, and in that "compiled" specification the word or
datatype sample originally used has been replaced with the datatype itself:

>> third :f
== [x [decimal!]]
>> first second third :f
== decimal!
>> type? first second third :f
== datatype!

So if you try to recycle THIRD :F to construct a new function, REBOL will
see a datatype, and use that as a sample in creating a new function:

>> ff: func third :f second :f
>> source ff
ff: func [x [datatype!]][x * x]

Perhaps that should be considered a bug - it would be much more intuitive
for REBOL to simply use the datatype as is, rather than interpreting it
as a datatype sample.

Sorry to go on about such an arcane subject!

Later,
Eric



[REBOL] Re: Parsing "matching brackets" in REBOL

2000-01-17 Thread KGD03011


Hi Antonio,

Here's an adaptation of something I dug up out of some old list messages,
by Stephen Butler:

>> non-brack: complement charset "<>"
== make bitset! #{
FFAF
}
>> bal-brack: ["<" any [non-brack | bal-brack] ">"]
== ["<" any [non-brack | bal-brack] thru ">"]
>> parse text1 [to "<" bal-brack copy b to end (print b)]
 to be copied to rest > this also
== true

Using recursion like this you don't have to try to count the brackets
yourself. What this does is look for the first "<", and stops at the
beginning (using TO not THRU). Then PARSE tries to match a balanced
"<" and ">". In between the "<" and ">" can come any number of characters
which are not "<" or ">", and any number of balanced "<" and ">". When
it comes to the end of the balanced brackets, it just copies to the end of
the string.

Hope it helps,
Eric



[REBOL] Datatype Hierarchy Re:

2000-01-17 Thread KGD03011


Hi Elan,

You asked:

>some time ago you sent a datatype hierarchy to the mailing list. How did
>you assemble that info?

I don't have any way to put together the whole hierarchy in one go,
but this function is fun to use:

>> show-all-types 0
any-type! number! integer!
>> show-all-types "string"
any-type! series! any-string! string!
>> show-all-types first [just/a/path]
any-type! series! any-block! path!
>> show-all-types make error! "We're ed!"
error! any-type!

Speaking of datatypes, here's a puzzle! (If you're sick of puzzles, think
of it as a conundrum ;-)

Why does this happen?

>> array2: func third :array second :array
>> array2 8
** Script Error: array2 expected size argument of type: datatype datatype.
** Where: array2 8

Later,
Eric

--

show-all-types: func [
{print out all relevant datatypes for a value}
value [any-type!]
/local typelist valuelist to-do
][
foreach [type list] reduce [
unset! "unset!"
datatype!  "datatype!"
action!"any-function! action!"
op!"any-function! op!"
][
if type = type? get/any 'value [print ["any-type!" list]  exit]
]
alltypes: []
if tail? alltypes [
foreach word first system/words [
if datatype? get/any word: in system/words word [
append alltypes get word
]
]
]
typelist: copy []
valuelist: head insert/only copy [] :value
foreach type alltypes [
if find valuelist type [
append typelist mold type
]
]
print typelist
]



[REBOL] Real stupid puzzle

2000-01-14 Thread KGD03011


Here is an unedited transcript. What sort of values do A and B reference?

>> a > b
== true
>> b > a
== true
>> a < b
== false
>> b < a
== false
>> a > b
== true
>> a > b
== true
>> a > b
== true
>> a > b
== true
>> a > b
== true
>> a < b
== false

Hint: no self-modifying code is involved!

Cheers,
Eric



[REBOL] bitset shortcut

2000-01-14 Thread KGD03011


Hi,

I really get sick of making bitsets with this kind of statement:

>> non-alpha: complement charset [#"a" - #"z" #"A" - #"Z"]
== make bitset! #{
01F801F8
}

So I'm working on a shortcut, that will process strings with
metacharacters. TO-BITS is what I've come up with so far.

In the first one or two characters:

~ means to get the complement
! means to include both upper and lower case

Thereafter:

a-z means all the characters from A to Z
\ means quote the next character, or include the character
  with the following ascii value

Examples:

>> to-bits "!a-z"
== make bitset! #{
FE07FE07
}
>> to-bits "~!a-z"
== make bitset! #{
01F801F8
}
>> to-bits "\128-\255"
== make bitset! #{

}
>> to-bits "~\128-\255"
== make bitset! #{

}

Any suggestions?  -  Also including a function to examine what's in bitsets:

>> unroll-bitset to-bits "!aeiou"
== "AEIOUaeiou"

These are included in search-text.r, on rebol.org . That's a little out of
date, but I'm still working on some other stuff before I update it again.

Hope it's of some use,
Eric

=

to-bits: func [
{convert a string to a bitset with:
 ~ for complement, ! for upper and lower case, - for character ranges,
 \ as escape character, or to convert following ASCII value}
s [any-string!]  "string to convert"
/local r c comp ignore alpha digit
] compose [
alpha: (make bitset!  [#"A" - #"Z" #"a" - #"z"])
digit: (make bitset!  [#"0" - #"9"])
r: copy []
parse s [
0 2 [#"~" (comp: true) | #"!" (ignore: true)]
some [
#"\" [
copy c some digit (append r to char! to integer! c) |
copy c skip (append r to char! c)
] |
#"-" (append r '-) |
copy c skip (append r to char! c)
]
]
either ignore [
rr: copy []
foreach c r [
append rr  either all [ char? c   find alpha c  ]
[either c > #"_" [c - 32] [c + 32] ]   [c]
]
r: union make bitset! r make bitset! rr
][  r: make bitset! r ]
either comp [complement r][r]
]


unroll-bitset: func [
{return string listing all characters in B}
b [bitset!]
/ul "return B with all characters set for upper and lower case"
/local s i
][
b: copy b
s: copy ""
i: 0
while [ i <= 255 ] [
if find b to char! i [insert tail s to char! i]
i: i + 1
]
s: head s
either ul [
insert b uppercase s
insert b lowercase s
][s]
]



[REBOL] wanna help me "cheat?" Re:

2000-01-14 Thread KGD03011


>Ack.  I just re-read my own post, and it's not all that clear.  sorry.
>anybody feel like giving me some pointers?

Hmm, not sure what you mean by "cheating". I think these programs work in a
way similar to your algorithm.

Since the digits in the string values are characters, there's a bit of
extra fooling around that detracts from the "beauty" of the algorithm.

These functions are useful if you need to do integer arithmetic beyond
the precision REBOL is capable of. There's an extra kludge to allow a
decimal point in the longer argument. Still need to add the ability
to accept "negative" arguments.

Later,
Eric

==

string-add: func [
{add two string representations of integers numerically}
a [string!] b [string!]
/local c d
][
a: copy a   b: copy b
if (length? a) < (length? b) [c: b b: a a: c]
insert/dup b "0" (length? a) - (length? b)
a: tail a  b: tail b
d: 0 while [ not head? b ] [
a: back a  b: back b
if #"." = first a [a: back a]
c: (first a) + (first b) + d - 48
d: either c > #"9" [c: c - 10  1][0]
change a c
]
if d > 0 [insert a "1"]
a
]

string-subtract: func [
{subtract two string representations of integers numerically}
a [string!] b [string!]
/full-length
/local c d neg
][
a: copy a   b: copy b
neg: copy either any [
(length? a) < (length? b)
all [(length? a) = (length? b)  a < b]
][c: b b: a a: c "-"][""]
insert/dup b "0" (length? a) - (length? b)
a: tail a  b: tail b
d: 0 while [ not head? b ] [
a: back a  b: back b
if #"." = first a [a: back a]
c: to char! (first a) - (first b) - d + 48
d: either c < #"0" [c: c + 10   1][0]
change a c
]
if not full-length [
while [all [#"0" = first a  1 < length? a]][remove a]
]
join neg a
]



[REBOL] Evaluation Re:

2000-01-11 Thread KGD03011


Hi,

Gabriele writes:

>Hello [EMAIL PROTECTED]!
>
>On 11-Gen-00, you wrote:
>
> l>>> st/start a: empty-il for i 1 2 1 [a: prepend i a]
> l>>> st/stop
> l> == 0:00:03
> l>>> st/start a: copy [] for i 1 2 1 [insert a i] st/stop
> l> == 0:01:36
>
>You're not fair, Ladislav!
>
>>> t: now/time a: make list! [] for i 1 2000 1 [insert a i] (now/time - t)
>== 0:00:02
>>> t: now/time a: make block! [] for i 1 2000 1 [insert a i] (now/time - t)
>== 0:00:13
>
>Trying to test with your immutable lists made REBOL crash with a
>guru on my Amiga (this is the first time I get a guru from
>REBOL!); I'll have to spend some time on this...
>
>Regards,
>Gabriele.

I crashed too, in windows, trying to do PRINT MOLD A. Still, it seems to
work otherwise.

>> tic a: empty-il for i 1 2 1 [a: prepend i a] toc
elapsed time: 0:00:01
>> a/what
== 2
>> a/nxt/what
== 1
>> a/nxt/nxt/what
== 19998
>> b: a loop 19000 [b: b/nxt] b/what
== 1000

That's fun. Is it fast?

>> tic loop 10 [b: a loop 19000 [b: b/nxt] b/what] toc
elapsed time: 0:00:09

Oooh, that's kinda slow.

>> a: copy [] tic for i 1 2 1 [insert a i] toc
elapsed time: 0:00:51

That was slow all right, but:

>> tic loop 100 [pick a 19000] toc
elapsed time: 0:00:03

is not too shabby.


Gabriele points out that inserting at the head with lists is much faster.
Also appending to blocks is much faster than inserting at the head. The
longer the blocks get, the longer the insertion takes. Appending takes
longer too, but the performance hit isn't nearly so bad.

>> a: copy [] tic loop 10 [for i 1 1000 1 [insert a i] toc]
elapsed time: 0:00
elapsed time: 0:00:01
elapsed time: 0:00:01
elapsed time: 0:00:02
elapsed time: 0:00:03
elapsed time: 0:00:05
elapsed time: 0:00:07
elapsed time: 0:00:09
elapsed time: 0:00:11
elapsed time: 0:00:13
>> a: copy [] tic loop 10 [for i 1 1000 1 [append a i] toc]
elapsed time: 0:00
elapsed time: 0:00
elapsed time: 0:00
elapsed time: 0:00
elapsed time: 0:00
elapsed time: 0:00
elapsed time: 0:00:01
elapsed time: 0:00:01
elapsed time: 0:00:01
elapsed time: 0:00:01

See you,
Eric



[REBOL] About DFAs Re:

2000-01-11 Thread KGD03011


Hi Ole,

Thanks a lot for the information on DFA's. It's very interesting, but I
don't think I'm ready to try to implement a DFA engine in REBOL. Still,
it's given me some new ideas on how to improve the NFA matching algorithm.
Thanks!

See you,
Eric



[REBOL] Regular Expressions Re:

2000-01-09 Thread KGD03011


Ole, thank you for telling me about DFA machines. It's much more than I
knew. I think it might be fun to implement with the model I'm using.

The hardest thing for me was implementing quantifiers. What I'm doing
with search-text.r is "compiling" an expression like

   [bound "t" 3 7 alpha "ing" bound]

to a form like:

   [bound "t" [4 6 3 7] make bitset! #{...} [3] "ing" bound]

in which the blocks are nodes which tell:

one or two elements to jump to
the minimum number of times the first jump must be made
the maximum number of times the first jump can be made

So we have to go through the cycle of elements 3/4/5

 ---
|   |
V   |
"t"(2) ->  node(3) -> bitset(4) -> node(5) -
|
 -> "ing"(6)

three times before we even think about jumping to the "ing" element.
What I'm doing is saving the number of times node(3) has been passed
in another block in a position tied to the "ing" element. When there
is a failure to match somewhere in the cycle, or when the cycle has
been done the maximum number of times, it's important to erase the
information on how many times node(3) has been passed, in case one loop
is nested inside another loop and there's a chance of coming back to
it.

Now with the NFA engine, saving a state means you only have to push
onto a stack the index of a jump you could have taken, plus the current
index of the text string. But with a DFA engine, you wouldn't need the
text string index (because once you deal with a character in the text
stream it's done once and for all) - is that right? On the other hand,
every time you come to a place where two jumps are possible you have
to start another thread so that both possible pattern indexes can be
compared against the next character in the text stream.

What seems especially complicated here is that you have to save the
information on which node has been passed how many times with each
thread. Complicated yes, but once a thread dies, it should be easier
to delete all the information associated with it.

Well, that's the idea anyway. If you would take a look at the code and
tell me any ideas you have, or if you could suggest a reference on
DFA machines, I'd really appreciate it.

Talk to you later,
Eric

Thanks,
Eric



[REBOL] What's next for REBOL... Re:

2000-01-07 Thread KGD03011


I'd love to try the beta REBOL/View too, please.

Thanks,
Eric



[REBOL] Regular Expressions Re:

2000-01-06 Thread KGD03011


Hi Ole, Petr,

Thank you very much for your comments.

Ole, you suggested this to find a word ending in "ing":

>> a: [skip a | "ing"]
== [skip a | "ing"]
>> parse "ringin" a
== false
>> parse "ringing" a
== true

That's fine, except it won't detect a word ending in "ing" in the
middle of the string:

>> parse "ringing bells" a
== false

Actually, I think your suggestion is equivalent to the rule:

b: [to "ing"]

Also, recursion is not so good for very long strings:

>> str: "ringing"
== "ringing"
>> parse str a
== true ; OK
>> insert str "- - - - -"
== "ringing"
>> parse str a
== true ; still OK
>> insert/dup str "- - - - -" 10
== "- - - - -ringing"
>> parse str a
== true ; still OK
>> insert/dup str "- - - - -" 100
== {- - - - -- - - - -- - - - ...
>> parse str a
== false; stops working

I expected a stack overflow error, but it just stopped working. Bug?

Anyway, it's best to use SOME. The way I suggested before, gets
pointers to the beginning of all the words:

pp: copy []
alpha: make bitset!  [#"a" - #"z" #"A" - #"Z" #"_"]
non-alpha: complement alpha

pp: copy []
alpha: make bitset!  [#"a" - #"z" #"A" - #"Z" #"_"]
non-alpha: complement alpha

parse/all string [ some [
p: some [ "ing" [non-alpha | end ] (append pp p) | alpha ] |
some non-alpha
]]

This could have been done with a faster rule:

>> str: "I'm singing in the rain"
== "I'm singing in the rain"
>> rule: [some [ thru "ing" p: [[non-alpha | end ] (append pp p) | none ]]]
== [some [thru "ing" p: [[non-alpha | end] (append pp p) | none]]]
>> parse/all str rule
== false
>> pp
== [" in the rain"]

But it's still not very simple. (Note - PARSE doesn't have to return
TRUE for it to do what you want - and if the location of spaces is
relevant to what you're looking for remember to use the /ALL
refinement - keep forgetting that!)

Here's a way to find "straw" and "camel" not separated by punctuation:

rule: [some [
to "straw" p: "straw" some ["camel" to end (print p) | non-punc]
]]

>> parse "This is the straw that broke the camel's back" rule
straw that broke the camel's back
== true
>> parse "I need some straw, and a camel" rule
== false

This is also very complex with PARSE, but trivial with regular
expressions.

Ole wrote:

>Converting "(string)*" and "(string)+", for example, into this:
>
>some-string: ["string" some-string | "string"]
>any-string: ["string" any-string | none]
>
>should work, shouldn't it? But yes, I must admit, too, that 'any and 'some
>ought to do some backtracking - in fact, I believed they did, so please
>ignore the mail I sent a couple of days ago on how to easily build Parse
>blocks from regular expressions ;-)
>
>Rebol Tech., isn't the lack of backtracking in 'any and 'some a bug?

I'm not sure what the advantage of your suggestion would be over
converting "(string)*" to [any "string"] and "(string)+" to [some
"string"], but at any rate I'm sure the lack of backtracking is not a
bug. (I've corresponded with Bo on this, and he's taught me a lot.)
The trouble is, backtracking can be very hard to control. For
example, if you want to parse out a quoted string, in which the " can
be escaped, but the escape character \ can itself be escaped, it's
hard to write a regex that won't find some way of breaking through
the final " and go right on to the next quoted string. And once you
do get an expression that should work, depending on the type of
engine used it can take a long time to match.

This is relatively straightforward with PARSE:

>> escape: [{\} skip]
== ["\" skip]
>> not-quote: complement make bitset! {"}
== make bitset! #{
FBFF
}
>> quoted-str: [{"} any [escape | not-quote] {"}]
== [{"} any [escape | not-quote] {"}]
>> find-quote: [some [copy p quoted-str (print p) to end | skip]]
== [some [copy p quoted-str (print p) to end | skip]]

>> parse/all {this is a "string with a quote"!} find-quote
"string with a quote"
== true
>> parse/all {this is a "string with an \" escaped quote"!} find-quote
"string with an \" escaped quote"
== true
>> parse/all {this is a "string with an \" escaped quote" and
{"yet another quote"!} find-quote
"string with an \" escaped quote"
== true

The rule QUOTED-STR needs to be adjusted of course, depending on what
you want to do, and there are always problems with how to deal with
illegal strings (should you allow newlines in the middle or not etc).
Still, parse rules make this kind of work easy, and backtracking can
only be a complicating factor.

I've suggested to feedback that there be a backtracking option for
PARSE, or some kind of alternative, but obviously they've got more
important things to do right now. So, to keep myself amused, and
because I do things like searching for patterns of words in long
texts a lot, I wrote a regex simulator in REBOL (search-text.r

[REBOL] Evaluation Re:

2000-01-06 Thread KGD03011


Hi Ladislav,

You can mutate the various paths:

>> b: [some/sort/of/path]
== [some/sort/of/path]
>> change first b 'no
== sort/of/path
>> b
== [no/sort/of/path]
>> insert tail first b 12
==
>> b
== [no/sort/of/path/12]
>> b: ['some/sort/of/lit-path]
== ['some/sort/of/lit-path]
>> change first b 'no
== 'sort/of/lit-path
>> b
== ['no/sort/of/lit-path]
>> b: [some/sort/of/get-path:]
== [some/sort/of/get-path:]
>> change first b 'no
== sort/of/get-path:
>> b
== [no/sort/of/get-path:]

And you can change actions, ops and natives in a limited way:

>> source action?
action?: native ["Returns TRUE for action values." value [any-type!] 6]
>> third :action?
== ["Returns TRUE for action values." value [any-type!] 6]
>> change third :action? "Returns YES for action values."
== [value [any-type!] 6]
>> source action?
action?: native ["Returns YES for action values." value [any-type!] 6]

>> change third :+ "Returns the result of summing two values."
== [
value1 [char! number! money! date! time! tuple!]
value2 [char! number! money! date! time! tuple!]
]
>> source +
+: native ["Returns the result of summing two values."
value1 [char! number! money! date! time! tuple!]
value2 [char! number! money! date! time! tuple!]
]

>> change third :print "Displays a value on the console and starts a new line."
== [
value "The value to print"
]
>> source print
print: native [{Displays a value on the console and starts a new line.}
value "The value to print"
]


Cheers,
Eric



[REBOL] Console Symbols Re:

2000-01-04 Thread KGD03011


Hi Don,

I think this is easier to understand if we keep in mind the difference
between two distinct any-word! datatypes: word! and lit-word!.

s: "some string"
>> type? probe first [s]
s
== word!
>> type? probe first ['s]
's
== lit-word!

Notice that PROBE is really handy here - it prints out the best
representation of the value possible, and passes its argument unchanged.
When PROBE sees a string, what it prints out looks like a string:

>> type? probe first ["s"]
"s"
== string!

So if PROBE shows us the ' it's a lit-word!, and if it just shows us letters,
it's a word! . Now REDUCE doesn't do anything to either:

>> type? probe reduce first [s]
s
== word!
>> type? probe reduce first ['s]
's
== lit-word!

Here FIRST extracted the value from the block unchanged, and passed that
value on to REDUCE, which passes it on unchanged, and PROBE shows us that it
really is unchanged. (Now you have to be careful with NONE, TRUE, FALSE and
datatypes, because PROBE can't show you the difference between the words that
represent those types, and the values they represent - but we'll ignore that
problem here.)

In fact, REDUCE only affects blocks.

>> reduce ['s]
== [s]
>> reduce [s]
== ["some text"]

So, to reiterate, although it looks like REDUCE is returning a different
value here:

>> reduce probe 's
s
== s

it isn't. All REDUCE ever saw was a word!, and that's what it gives back. The
same goes for PRINT:

>> print probe 's
s
s


You can describe what REDUCE does to a block as follows: (This is just a
model, not necessarily what it really does!)

1. makes an empty block
2. evaluates each complete expression in the argument block
3. appends each return value in turn to the new block

[example deleted for clarity!]


So let's see how this explains your original problem:

>   s: "some text"===>'some text"
>   reduce 's   ===> s  ;  (first s )
>   print (reduce 's) ===> s;  (second s)
>   reduce ['s]===>[s] ;  (third s )
>
> These 3 s symbols look the same on the console but are all different.
> So, though  (reduce 's) appears to give s,  it is not the same s
>  which the console will use if we enter:   print s  ===> some text
>   or   do reduce ['s]  ===>  "some text"

First, the symbols'sands   are different - the first is a
lit-word! that evaluates to a word!, the second is a word! that evaluates to
whatever value it refers to.

The   syou get from reduce 's   represents just the word! that   's
evaluated to automatically - the intervening REDUCE is irrelevant.

The   syou get from print (reduce 's)is how PRINT represents the
word!   sthat gets returned from(reduce 's) .  Note that PRINT has no
usable return value - it just displays characters on your console, and PRINT
would have done just the same with the string "s".

Finally, the  [s]  you get from   reduce ['s]   is the result of the
evaluation of the  'swithin the argument block of REDUCE.


As you noted, repeated use of REDUCE on a block can progressively evaluate
the values in the block, and PRINT does one more REDUCE before it shows you
its representation of the block.

How about this:

>> reduce [to-word "to-lit-word" to-string 's]
== [to-lit-word "s"]
>> reduce reduce [to-word "to-lit-word" to-string 's]
== ['s]
>> reduce reduce reduce [to-word "to-lit-word" to-string 's]
== [s]
>> reduce reduce reduce reduce [to-word "to-lit-word" to-string 's]
== ["some string"]


Hope this helps,

Eric




[REBOL] Regular Expressions Re:

2000-01-04 Thread KGD03011


Hi Keith,

Thanks for looking at search-text.r!

You wrote:

>About the backtracking. I'm not sure how essential backtracking is, because
>I think we can simulate a bunch of what backtracking does with things like
>"any" and "some" rules for 'parse. I don't know all that much about
>backtracking though, so maybe it's a lot more essential than I think. The
>thing is that I don't think Perl itself had backtracking until version 5,
>and I think there have been regex libraries which have at least been useful
>which haven't had full support for backtracking.

I think backtracking is an essential part of regular expressions. To quote
from Mastering Regular Expressions by Jeffrey Friedl (O'Reilly, p. 102),

The essence of an NFA engine [the regex matching engine of the kind
that Perl uses] is this: it considers each subexpression or component
in turn, and whenever it needs to decide between two equally viable
options, it selects one and remembers the other to return to later if
need be. 

Suppose you want to find a word ending in "ing". In Perl you could write:

   /\b[a-z_]+ing\b/i

Backtracking is crucial here, because "[a-z_]+" first matches to the end of
the word, and if you didn't backtrack, "ing" would never match. With a parse
rule, you have to do something like this:

pp: copy []
alpha: make bitset!  [#"a" - #"z" #"A" - #"Z" #"_"]
non-alpha: complement alpha

parse/all string [ some [
p: some [ "ing" [non-alpha | end ] (append pp p) | alpha ] |
some non-alpha
]]

This will leave you with the block PP holding pointers to the beginning of
all the words ending in "ing". It isn't quite equivalent to the Perl regex,
but it's close enough. Here backtracking is accomplished in the following
way: Suppose you were scanning through the word "ringing". The string "ing"
would match "ringing" first, and then attempt to match a non-alphabet
  ~~~
character or the string end. That wouldn't work, but the following | says
that we should try to jump back to the second letter of "ringing" and just
match any alphabet character, and keep going through the word. This is the
kind of thing that regexes do for you automatically.

Now for doing things like parsing an HTML file, backtracking is a nuisance.
If you want to match a quoted string, which may have escaped quote characters
in the middle, it's very hard to write regexes that won't find some way of
jumping from one quoted string to another and matching too much. Regexes want
to match as much as possible, so you have to fight with them sometimes to
keep them from matching too much. With parse rules, you can just look up the
grammar of the type of file you're trying to parse, and build up your parse
rules from the simplest units to the most complex structures. This can be
done recursively, which makes matching nested parens and such possible. So
that's definitely the way to go.

But if you want to search for a pattern in text, such as {a word begining
with "t" and ending with "gh"}, or {the words "straw" and "camel" not
separated by any punctuation}, and especially if you want to do that
interactively without stopping to think how you're going to program it, the
parse rules that would be needed are much too complex. This is the problem
I've been trying to tackle with search-text.r.

I really like the grammar of parse rules, so I've tried to keep as much of it
as possible. It's not as compact, but it would be trivial to rewrite the
script to provide abbreviations such as * for ANY. It would be pretty easy
even to provide automatic translation of character classes such as [a-z] into
bitsets.

I'm still thinking about what the best form of the return value should be.
For the time being I'm copying AWK, and returning a block with the equivalent
of RSTART - the index of the beginning of the match - and RLENGTH - the
length of the match. Then I decided just for the hell of it to throw in a
copy of the match to make it easier to see what was going on.

The big problem is speed. When processing the expression given, an optimized
function is created that tries to quickly identify potential matches.
Unfortunately for an expression that begins with ANY there's no simple way to
do this, so the main matching function is called for every character in the
string. Needless to say that is useless for most purposes, but in interactive
searching I don't think most people would use such an expression. Replacing
text is another matter, but then that won't be much use until I get text
capture of portions of the expression implemented.

See you around,
Eric



[REBOL] Evaluation Re:

2000-01-04 Thread KGD03011


If anyone's interested, here's the correct datatype hierarchy again:

any-type
any-function
action
function
native
op
any-word
get-word
lit-word
refinement
set-word
word
bitset
char
date
error
logic
money
none
number
integer
decimal
object
port
series
any-block
block
list
lit-path
hash
paren
path
set-path
any-string
binary
email
file
issue
string
tag
url
symbol
time
tuple
unset


BTW, you can see all the "complex datatypes" from the help to FIRST:

>> ? first
Returns the first value of a series.
Arguments:
series --  (series money date object port time tuple any-function)

Only series! and port! have an index - all other values are only seen from
one perspective. It's impossible to "hide" the first element. This means that
with money! date! object! time! tuple! and any-function!, any function that
returns a value with a different index, such as HEAD, TAIL, NEXT or SKIP is
meaningless. Most of these are "immutable" (in the sense that you can't
change one value by manipulating another one), except any-function!  and
object! which contain blocks. money! contains a string, but that string is
limited to three characters.

Joel wrote:

>[EMAIL PROTECTED] wrote:
>>
>> I agree that TUPLE! is mis-documented as a series datatype. It also
>> fails on INDEX? It's a scalar datatype like DATE! Might be worth
>> reporting to [EMAIL PROTECTED]
>>
>
>I copied them on the message.



[REBOL] Regular Expressions Re:

2000-01-04 Thread KGD03011


(Message previously posted with wrong subject. Sorry! - I'll just edit it a
bit before reposting.)

Hi Keith,

>Hi, just wondering about regular expressions in Rebol.
>
>1. Is there any support for regular expressions planned (or is Rebol only
>going to support 'parse for everything regular expressions might be used for
>that isn't already taken care of by words like 'find.)?

Funny you should ask. I just posted search-text.r to rebol.org, which is an
attempt to simulate regular expressions in REBOL. Please have a look at it
and tell me what you think.

http://www.rebol.org/utility/search-text.r

I use regular expressions in block form, and have tried to make them as
similar as possible to parse rules. Don't have any text capture yet, except
for the whole match. That's definitely needed, but I haven't figured out how
to do it yet. You can capture text in parse rules using 'copy, but this
capture occurs regardless of whether the rule succeeded overall, or whether
the portion of rule capturing the text contributed to the overall match or
not.

I think it would be very very difficult to translate regular expressions that
had complicated combinations of the * and + operators, but a very useful
trick is:

p: copy []
rule: [something like a regex]
parse string [some [p: rule (append pp p) | skip]]

This use of 'parse will always return true (since 'skip will take you to the
end of the string even if 'rule never matches), but 'pp will contain a list
of pointers to all the places that matched rule. Unfortunately, if you want
to have a rule like:

non-space: complement make bitset! " ^/^-"
["t" some non-space "t"]

you'll never match because 'some 'non-space will take you right through the
"t". You need to do something like

["t" some ["t" (append pp p) | non-space]]

Even some rather straightforward regular expressions would require extremely
complex parse rules.

Regexes have automatic backtracking - a regex engine will try any possible
combination of the elements you specify to make a match. Parse rules don't do
that - parse'll just plow through your rule unless you explicitly say, "and
if that didn't work back up to this point and try this." Parse rules are
great when you've got structured data meant to be read by a computer, since
regexes can find devilish ways to match things that shouldn't match.  Regexes
are better and much more concise when you're just looking for combinations of
words in natural languages.

Sorry for all this raving, and twice! Anyway, I'd be happy to exchange more
ideas on what should be done!

See you around,
Eric



[REBOL] Simple textfile handling...?

2000-01-04 Thread KGD03011


Hi Keith,

>Hi, just wondering about regular expressions in Rebol.
>
>1. Is there any support for regular expressions planned (or is Rebol only
>going to support 'parse for everything regular expressions might be used for
>that isn't already taken care of by words like 'find.)?

Funny you should ask. I just posted search-text.r to rebol.org, which is an
attempt to simulate regular expressions in REBOL. Please have a look at it
and tell me what you think.

http://www.rebol.org/utility/search-text.r

I could go on all day about how regular expressions are similar and
dissimilar to parse rules, but I believe you can accomplish anything with a
parse rule that you can with a regex, only it can be a real pain in the butt.

Regexes have automatic backtracking - a regex engine will try any possible
combination of the elements you specify to make a match. Parse rules don't do
that - parse'll just plow through your rule unless you explicitly say, "and
if that didn't work back up to this point and try this." Parse rules are
great when you've got structured data meant to be read by a computer, since
regexes can find devilish ways to match things that shouldn't match.  Regexes
are better and much more concise when you're just looking for combinations of
words in natural languages.

See you around,
Eric



[REBOL] Evaluation Re:

2000-01-04 Thread KGD03011


Hi Ted,

>On 1/4/2000 at 5:37 PM [EMAIL PROTECTED] wrote:
>
>"since all you have to do is compare two pointers to memory and two
>indexes."
>
>Most of us don't have access to the implementation details, so it's
>hard to say what REBOL has to do. All we can see is what it does.

I guess it was really a rhetorical question, but one could speculate, such as
"to make this more efficient this other more important thing would become
less efficient ..." I don't really know enough to even speculate ...

>Cool experiment, though.
>
>Do you get any different results using functions rather than operators?

With something like comparing long strings the difference between functions
and operators isn't going to show up. So with integers:

>> time-it [loop 10'000'000 [1 = 2]]
0:00:11
>> time-it [loop 10'000'000 [equal? 1 2]]
0:00:15
>> time-it [loop 10'000'000 [= 1 2]]
0:00:15

I'd assumed that since operators require special syntactic processing, they'd
be slower, but it seems they're faster when used as infixes, but just the
same as functions when used as prefixes.

>Do you get different results with larger and smaller loops? Larger and
>small strings?

Hmmm...

>> c: copy b: a: head insert/dup "" "a" 100'000 print "done"
done
>> time-it [loop 5000 [a = b]]
0:00:13
>> time-it [loop 1 [a = b]]
0:00:26
>> c: copy b: a: head insert/dup "" "a" 200'000 print "done"
done
>> time-it [loop 5000 [a = b]]
0:00:26
>> c: copy b: a: head insert/dup "" "a" 400'000 print "done"
done
>> time-it [loop 5000 [a = b]]
0:00:50

Looks like the time it takes is pretty much proportional to the length of the
loop and the length of the strings.

>Do you get different results with operations other than comparison?

Hmmm ... I tried copying some long strings 5000 times and it started
thrashing my disk. Let's restart REBOL and let it settle down a bit ...

>> a: head insert/dup "" "a" 100'000 print "done"
done
>> time-it [loop 5'000'000 [length? a]]
0:00:05
>> a: head insert/dup "" "a" 20 print "done"
done
>> time-it [loop 5'000'000 [length? a]]
0:00:06
>> a: head insert/dup "" "a" 400'000 print "done"
done
>> time-it [loop 5'000'000 [length? a]]
0:00:07

Well, LENGTH? is very fast, and the time increases with length, but not
proportionally. Perhaps the loop overhead is a large factor here?

Don't try clocking REBOL operations with FOR loops, cause that'll be almost
pure overhead.

>Do you get different results with greater or fewer words defined?

That's a good question!

Fresh REBOL, no scripts loaded from user.r:

>> a: copy "aa"
== "aa"
>> b: copy a
== "aa"
>> time-it [loop 1000 [a = b]]
0:00:17
>> for x 1 500 1 [set to word! join "a" x copy a]
== "aa"
>> a499
== "aa"
>> time-it [loop 1000 [a = b]]
0:00:17

Doesn't seem to make much difference. BTW, as I posted to the list a couple
of weeks ago, there's a limit of 1,534 definable words, so it's hard to push
it here. I got a message back from Bo saying that the problem had been
noticed before, and that he'd opened an incident on it, so maybe we'll be
able to use more words in the future.

>What's the source of time-it?

>> source time-it
time-it: func [
"time execution of a block"
block [block!]
/local t
][
t: now/time
do block
print now/time - t
]

Larry's the expert on timing things. (He'll also tell you some interesting
stuff about memory usage if you ask.) His TIC and TOC are much cooler than my
TIME-IT. I just got in the habit of using TIME-IT, which isn't as flexible,
but OK for simple things.

>
>-Ted.

Nice talking to you,
Eric

>*** REPLY SEPARATOR  ***
>
>On 1/4/2000 at 5:37 PM [EMAIL PROTECTED] wrote:
>
>Hi there,
>
>One thing I find very puzzling on this subject:
>
>>> c: copy b: a: head insert/dup "" "a" 10 print "done"
>done
>>> time-it [loop 5000 [a = b]] ; 1) should be done very fast
>0:00:15
>>> time-it [loop 5000 [a = c]] ; 2) takes time, of course
>0:00:19
>>> time-it [loop 5000 [a =? b]]; 3) should be done very fast
>0:00:15
>>> time-it [loop 5000 [a =? c]]; 4) should be done very fast
>0:00:18
>
>=? is the operator for SAME?
>
>2) takes time because 100,000 characters have to be compared. But it should
>take almost no time at all to determine if two string values are the "same",
>as in 3) and 4), since all you have to do is compare two pointers to memory
>and two indexes. Likewise, if two values are the "same", they must be equal,
>so ideally 1) should be fast as well. So why doesn't REBOL do this a little
>more efficiently?
>
>See you,
>Eric



[REBOL] Evaluation Re:

2000-01-04 Thread KGD03011


Hi there,

One thing I find very puzzling on this subject:

>> c: copy b: a: head insert/dup "" "a" 10 print "done"
done
>> time-it [loop 5000 [a = b]] ; 1) should be done very fast
0:00:15
>> time-it [loop 5000 [a = c]] ; 2) takes time, of course
0:00:19
>> time-it [loop 5000 [a =? b]]; 3) should be done very fast
0:00:15
>> time-it [loop 5000 [a =? c]]; 4) should be done very fast
0:00:18

=? is the operator for SAME?

2) takes time because 100,000 characters have to be compared. But it should
take almost no time at all to determine if two string values are the "same",
as in 3) and 4), since all you have to do is compare two pointers to memory
and two indexes. Likewise, if two values are the "same", they must be equal,
so ideally 1) should be fast as well. So why doesn't REBOL do this a little
more efficiently?

See you,
Eric



[REBOL] Yet another puzzle Re:

2000-01-04 Thread KGD03011


Hi folks,

>There are all sorts of ways to produce a value for 'e that will show
>the following behavior:
>
>>> print e
>e f
>>> print e
>e g
>>> print e
>e f
>>> print e
>e g

I'm really late with this, but this is an easy way to do it, and it shows yet
another use of modifying "literal" series.

>> e: ['e back reverse "fg"]
== ['e back reverse "fg"]
>> print e
e f
>> print e
e g
>> print e
e f

Cheers,
Eric



[REBOL] Searching in text

2000-01-03 Thread KGD03011


Hi folks,

I've finally got %search-text.r into some sort of useful shape, and I'm
putting it on rebol.org. Check it out. It includes a function KWIC that
prints out a "key-word-in-context" chart:

>> kwic read %manual/valabout.html "BackNext<
878 face="arial,helvetica"> CONTENTSCONTENTS OPERATIONOPERATION EXPRESSIONS
   1003 "expintro.html">EXPRESSIONS SCRIPTS
   1042 REF="scrintro.html">SCRIPTS SERIES<

Hope you like it, and please let me know of any comments or problems you
have.

PS - can't find the script in the recent scripts list, but it's listed in the
utility category, or you can go straight to it:

http://www.rebol.org/utility/search-text.r

See you,
Eric



[REBOL] "How to form a rule? Re:

1999-12-29 Thread KGD03011


Hi Gabriele,

You wrote:

>>> text: "this is a testament to be searched"
>== "this is a testament to be searched"
>>> parse/all text [
>[to "t" mark1: skip
>[any [
>["t" mark2: " " to end |
>[no-space |
>[to "t" mark1: skip
>[]
>[]
>== true
>>> copy/part mark1 mark2
>== "testament"

That's really good - another technique I'll try to absorb. Unfortunately,
though, I wanted the first "t" to be the first character in a word. Your rule
will succeed with strings like "this is a nontext to be searched" - which I
didn't want to match. It also succeeds with the string "splat" (although
mark2 doesn't get set).

The most reliable solution I can find is (using a technique I learned from
you):

rule: [
mark0:
some [
space mark1: "t" some [
"t" mark2: [ space to end | end ] mark0: | no-space
] | skip
]
:mark0
]

I think it's safe to say this is too complex for general use. I shudder to
think what would be involved trying to generate such a rule.

And ...

Hi Cheryl,

You wrote:

>What is SEARCH? Is is available at rebol.org? I looked and did not see it
>there.

Sorry, I haven't put it there. It's more of a proof-of-concept rather than a
practical solution. It's just a simulation of regular expression behavior
(including backtracking) with expressions that look like PARSE rules.

I'll try to make the code a bit more presentable and post it to rebol.org
or the list in a couple of days.

Thanks for asking!

Eric



[REBOL] "logical" value referencing ... Re:

1999-12-29 Thread KGD03011


Hi Elan,

>From one of your latest posts, I've concluded that our differences on what is
and isn't reference are quite minor, after all (except for my woeful lack of
background). I agree on the overall framework you proposed under the terms
"explicit reference" and "automatice reference". I was toying with these
terms, which pretty much parallel yours:

   value reference: The relationship between a word and the value it
references.

  series reference: The relationship between a series value and its
underlying data.

I realize that "series reference" is not a good term, since essentially the
same form of reference also applies to the relationship between any-function!
object! and possibly port! values and their underlying data. (I'm still
groping in the dark regarding how port! values should be pictured.)

I've also learned a lot about contexts from this thread. My hazy notions have
sharpened quite a bit thanks to remarks you and Gabriele have made. Thanks!

TIE, and have a great New Year!

Eric



[REBOL] Evaluation/blocks

1999-12-29 Thread KGD03011


Hi Ladislav,

You wrote:

>1) In the rebol22-draft-manual\expevaluation.html one can read:
>
>{{
>Evaluating Simple Values
>Simple values just evaluate to themselves. Nothing special happens. The
>value is simply returned. For instance, if at the prompt you type:
[snip]
>One is immediately tempted to draw:
>
>(i) Rebol blocks, lists, hashes, strings evaluate to themselves.
[snip]
>4) In the rebol22-draft-manual\expevaluation.html one can read:
>
>{{
>Evaluating Blocks
>Blocks are not normally evaluated. They are normally treated as data.
[snip]


That looks like a problem all right. As a stopgap measure, maybe the wording
of the second quote could be changed to "Blocks are not normally evaluated as
code," or maybe, "The contents of blocks are not normally evaluated."

I think there's also a problem with the implication given that you can simply
"type in" a value at the prompt. Unfortunately, this is really at the
beginning level, and it's important not to put off the reader with a
technical description of REBOL parsing the input. Perhaps something like
this:

   When you type in a simple value at the prompt, REBOL recognizes what
   kind of value it is from the characters that you typed, and returns
   that value.

I tried to word this so that the reader will both get the idea that
communicating with REBOL is easy, but also get a hint that REBOL is doing
something complex, and that the returned value is really something different
from what was actually entered at the prompt.

What do you think?

Eric



[REBOL] "How to form a rule? Re:

1999-12-29 Thread KGD03011


>Hi Petr,
>
>I'm also interested in a good challenge - and I happen to be looking for an
>opportunity to practive parse rules.

Hi Elan,

I wonder if I could butt in here. I responded to Petr's message, but I think
the example I used was so complicated that everyone must have hit the delete
button. Here's the same challenge in a very simple form: Find a word (in the
conversational sense, not in the REBOL sense) beginning with "t" and ending
with "t" in the string:

  "this is a testament to be searched"

with a single call to PARSE. This is trivial to do with a Perl regular
expression:

  "this is a testament to be searched" =~ /\bt[a-z]*t\b/i;
  print $&;

prints out "testament". It's also very easy if you call PARSE twice, but even
then it's not so simple to get an index into the original string. It's pretty
hard to do with a single PARSE rule, and it would be even harder to generate
a PARSE rule given a simple expression structurally equivalent to the Perl
regex (but in an easier-to-read REBOListic form). I had dreams of doing this
- one of my first posts to this list was about this topic - but I decided it
was too difficult for me - especially if I wanted to generate equivalents of
even more complex regexes.


So, what I'd really like to have is a REBOL native that would work this way:

   >> a: "this is a testament to be searched"
   >> alpha: make bitset! [#"a" - #"z" #"A" - #"Z"]
   >> search a [ word-boundary "t" some alpha "t" word-boundary ]
   == [11 9] ; simulated output

returning the index and length of the portion of A that matched. I've got a
function that almost does that, only I don't have 'word-boundary implemented.

>> search a [ "t" any alpha "t" ]
== [11 9]; actual output

This will match even when the "t"s are not at word boundaries, so I really
have to do this:

>> non-alpha: complement alpha
== make bitset! #{
01F801F8
}
>> search a [ [head | non-alpha] "t" any alpha "t" [head | non-alpha] ]
== [10 11]

and here you get problems of extraneous non-alpha characters being included
in the match.


Anyway, if you're in for a real challenge, you could try to make sense out of
the program I wrote, refine it, add extra optimization, since it's very slow
unless the first few characters of the match are fixed. It's got a half-assed
implementation of a finite-state machine, loosely based on Chapter 20 of
Algorithms in C++ by Robert Sedgewick.

Eric


PS - If I might add a couple impressionistic comments on PARSE versus regular
expressions. When I was developing SEARCH I reread Mastering Regular
Expressions by Jeffrey Friedl. I was amazed at how simply many of the
contortions he describes can be done with PARSE. PARSE is wonderful for,
well, parsing data that obeys strict rules about the meaning of characters.
What PARSE is weak at, though, is finding patterns in natural language data.
Ironically, this is what regular expressions are good at.

Well, I believe that the current strengths of PARSE are crucial for REBOL's
immediate survival and success, but I'm hoping that someday we'll have the
best of both worlds.



[REBOL] "logical" value referencing ... Re:

1999-12-28 Thread KGD03011


Hi Elan,

I think you've got us all mystified. You said to Joel:

>You also quote excerpts that demonstrate the use of the verb "to refer" in
>a context where something is being referred to. This class of quotes does
>not make any statement about WHAT IS DOING the referring. What use are
>quotes that demonstrate that values can be referred to, even though they
>are not words? I never claimed that values being referred to must be words.
>I said that only words are references, and only words can be dereferenced:
>>> help get
>Gets the value of a word.
>Arguments:
>word -- Word to get (any-word)
>Refinements:
>/any -- Allows any type of value, even unset.

I can't for the life of me see how the help for GET says anything about the
technical meaning of the word of the term "refer" or "reference", given that
the word isn't used at all. Then when you go on to prove that string values
cannot refer by showing that strings cannot be used as an argument to GET,
my confusion is compounded many-fold. Where does it say that only words can
be dereferenced? I haven't even seen the term "dereference" in the
documentation.


Maybe this will help me understand what you're thinking. How do you explain
what happens here?

>> string: "abcdefghij"
== "abcdefghij"
>> b: [] loop 5 [append b string string: next string]
== "fghij"
>> b
== ["abcdefghij" "bcdefghij" "cdefghij" "defghij" "efghij"]
>> unset 'string
>> remove first b
== "bcdefghij"
>> b
== ["bcdefghij" "cdefghij" "defghij" "efghij" "fghij"]


Here's an interesting use of the term "reference" from the
User's Guide 2.2.0 [DRAFT 2] (sersearch.html)


   Search Constraints

   The /part refinement takes one argument, a range to search.
   This can be a numeric range, or series. When a series is
   used, find/part uses the count of elements between the
   current index of the search series and the current index of
   the series argument as the range to constrain to. The
   series used as the range argument must reference the same
   series that's being searched.

You'll see that a "series" is said to reference a "series" - not terribly
clear wording, but given that they haven't had time to fully consider Joel's
proposals I'd say it's a forgivable lapse.

The behavior described here may be illustrated as follows:

>> a: "this is a string to be searched"
== "this is a string to be searched"
>> find a "string"
== "string to be searched"
>> find a "search"
== "searched"
>> find/part a "string" find a "search"
== "string to be searched"
>> find/part a "search" find a "string"
== none

In the final statement here,

   find a "string"

returns a reference to A which constrains the find/part to a portion of A
which doesn't include the substring "search"

Here's another example, from sercopy.html:

   Copying Embedded Series With the /deep Refinement

   The /deep refinement forces copy to copy all series values
   within a block.

   When copying series values in a block, the reference to the
   series is copied, not the series itself. Modifications to
   series in a copied block will modify the series in the copy.

It implies quite clearly that references can exist within a block.

BTW, you may have spotted Joel's solution to my puzzle, which I confess is a
silly variation of one of Ladislav's puzzles.

See you,
Eric



[REBOL] How to form a rule? Re:

1999-12-27 Thread KGD03011


Hi Petr,

Here's a technique Gabriele taught me:

>> str: "Something to say, some text to parse, something else"
== {Something to say, some text to parse, something else}
>> rule: ["s" "om" skip " " "t" thru "t" " " "to" " " "p" skip skip "se" to end]
== ["s" "om" skip " " "t" thru "t" " " "to" " " "p" skip skip "se" to end]
>> parse/all str [here: some [rule here: | skip] :here]
== true

This allows you to try to match RULE from every position in the string,
because even when RULE doesn't match SKIP will. This has the danger that
you'll return TRUE for all strings, because SKIP will just carry you through
to the end, but by setting HERE to the beginning of the string, then
resetting it once you've matched RULE, and finally setting the current
position to HERE at the end of the parse, you can assure that PARSE won't
return TRUE unless you've actually matched RULE.

The only trouble here is that "t" thru "t" will behave just like t*t - you
could have any amount of data in between. There's no way to keep 'thru from
skipping over non-space characters. Further, if you have an extra "t" in the
middle of the word you're sunk. For example,

>> str2: "Something to say, some testament to parse, something else"
== {Something to say, some testament to parse, something else}
>> parse/all str2 [here: some [rule here: | skip] :here]
== false

To restrict "t" and "t" to the same word, and allow extra "t"s in between,
I think you have to do something like this:

>> letter: make bitset! [#"a" - #"z" #"A" - #"Z"]
== make bitset! #{
FE07FE07
}
>> r2: ["t" " " "to" " " "p" skip skip "se" to end here:]
== ["t" " " "to" " " "p" skip skip "se" to end here:]
>> r1: ["s" "om" skip " " "t" some [r2 | letter] ]
== ["s" "om" skip " " "t" some [r2 | letter]]
>> parse/all str [here: some [r1 | skip] :here]
== true

But I think this technique is too complex to be really practical.

I've been lobbying for more regular-expression-like parsing, to overcome the
problem you mention of parsing rules failing when one part matches too early.
I've also written a series of functions that use matching rules that behave
more like regular expressions:

>> r2: ["s" "om" skip " " "t" some letter "t" " " "to" " " "p" skip skip "se"]
== ["s" "om" skip " " "t" some letter "t" " " "to" " " "p" skip skip "se"]
>> result: search str r2
== [19 18]
>> copy/part at str first result second result
== "some text to parse"

The "regular-expression-like" matching here is that with a parse rule SOME
LETTER will normally match up through the end of the word "text", leaving
nothing for the following "t" to match. SEARCH will backtrack to see if
there's some other way to match. SEARCH also overcomes the problem of the
middle "t" in testament.

If anyone's interested, I could post a copy of the script. (Unfortunately
it's too slow for most practical uses, but someone might find it amusing.)

See you,
Eric



[REBOL] "logical" value referencing ... Re:

1999-12-27 Thread KGD03011


Hi Elan,

I've read your 1400+ line refutation of Joel's explanation of a function. I
agree with much of what you say, but there is one point I don't think is
quite right:

>2.3 Conclusion:
>2.3.1 An empty literal string does not reference "the empty string" because
>a string! value does not have the capability to reference something. That
>capability is reserved for values of type word!

(I think Joel may have used the phrase "the empty string" as a concept rather
than meaning "the unique empty string in the example".)

You "prove" this with the following demonstration:

>2.2 Each of the two literal strings is an independent entity. Since you
>speak of "the empty string" and you say " as is the fifth element", your
>formulation suggests that the two literal strings are identical, since they
>are both references to "the empty string". If they are identical, the
>function same? should return true. However, same? returns false:
>
>>> same? "" ""
>== false

In the case of the "the two literal strings" in the function F being
described it's true, and it's true with your illustration

>>> same? "" ""
>== false

In this latter illustration both literal strings are independent entities,
because REBOL creates both of them when it parses the string {same? "" ""}
typed in at the console. That still is no guarantee that all "literal
strings" are mutually independent entities.

What about this case:

>> a: [""]
== [""]
>> insert a first a
== [""]
>> a
== ["" ""]
>> same? first a second a
== true

The block referenced by (bound to) 'a now contains two string values, both of
which reference the same empty string.

This is one of the major points that Joel was trying to make in his series
essay, and one that deserves careful attention. Even series values that look
literal (that are not directly bound to a word) have a relationship of
reference to the underlying data which they represent.


Another point where I think you go slightly wrong is further down:

>>
>>The subtle point over which so many of us have tripped (judging by
>>the discussions on the mailing list) is that the the adjacent
>>quotation marks in the text entered to define 'trick serve simply
>>as the INITIAL VALUE of the second element of 'trick, and that
>>subsequent modifications (via any reference) to that second element
>>will persist as long as 'trick does.  That is the only point where
>>the concept of "global" appears, as far as I can tell.  Values are
>>not subject to garbage collection as long as there is any reference
>>(or chain of references) to them from the global context.  "Local"
>>doesn't enter into it at all.
>
>Wrong.
>
>>> false-abstraction-2: [append ""  "X" ]
>== [append "" "X"]
>>> do false-abstraction-2
>== "X"
>>> do false-abstraction-2
>== "XX"
>>> do false-abstraction-2
>== "XXX"
>>> do false-abstraction-2
>== ""
>>> do false-abstraction-2
>== "X"
>>> false-abstraction-2
>== [append "X" "X"]
>
>Here the literal string in false-abstraction-2 was modified, even though it
>wasn't being referenced by anything global.

It's true that much of what Joel said about contexts being destroyed and
local values being thereafter subject to garbage collection was mistaken.
(BTW, I've noticed that in 2.2 the behavior of local values assigned to words
local to a function is more predictable now.)

Still, I think that the important point Joel makes here is basically right.
Notice he said a "chain of references". For example, in your example the ""
in:

>> false-abstraction-2: [append ""  "X" ]

does serve "as the initial value" of the second element of the block
referenced by 'false-abstraction-2. That's because REBOL created a string
based on its parsing of the characters "" in the string
{false-abstraction-2: [append ""  "X" ]} , which was typed in at the console.
Thereafter the second element of the block serves as a reference to the data
underlying that value. The value persists, and the data to which it refers
persists (in the sense that the garbage collector doesn't gobble it up),
because it's contained in a block referred to by a word. That is indeed a
"chain of references".

I don't even think it's quite right to call the second element of the block
referenced by 'false-abstraction-2 a literal string. I think you could say it
was initialized from a literal string, but as it exists within the block
itself, it is a string value, no different in quality from one directly
referenced by a word.


In conclusion, here's a puzzle, easily solved: how did I make this function?

>> source f
f: func [x /local a b][a: "" b: copy "" append a x print b]
>> f "I'm a geek"

>> f ", not!"
I'm a geek
>> f " OK?"
I'm a geek, not!

See you,
Eric



[REBOL] Self modifying code Re:

1999-12-24 Thread KGD03011


Rob writes:

>Any thought on the matter of Object!s potentially being self modifying???

This happens all the time. I don't think it's controversial, is it?
One nice thing that objects do is allow you to use a lot of persistent local
variables.

Here's an implementation I did of an algorithm from Numerical Recipes in C.
Don't ask me how the algorithm works - it's too complicated for me!

There are two functions in this object, DECOMP and BACKSUB. The purpose is
to find solutions for various values of B for the equation A * X = B, where
A is a square matrix, and X and B are vectors. DECOMP has to be run once
for every value of A, and then BACKSUB needs to be run to solve for X given B.

lu: make object! [
indx:   ; holds info on permutations
lu: ; holds LU decomposed matrix produced by DECOMP
x:  ; holds solution to  A * X = B  given by BACKSUB
d:  ; holds permutation parity
n:  ; holds size of square matrix
none

decomp: func [
{do an LU decomposition of square matrix A - from NR in C p. 46-7}
a [block!]
/local i imax j k big dum sum vv
][
lu: copy/deep a
n: length? a
vv: head insert/dup copy [] none n
indx: copy vv
d: 1 ; ends up -1 for odd number of row changes
i: 1 while [ i <= n ] [  ; loop over rows to get implicit scaling
big: 0
j: 1 while [ j <= n ] [
big: max abs lu/:i/:j big
j: j + 1
]
if zero? big [make error! "singular matrix in LU-DECOMP"]
poke vv i 1.0 / big  ; save scaling
i: i + 1
]
j: 1 while [ j <= n ] [  ; go column by column
i: 1 while [ i < j ] [   ; do rows above the diagonal
sum: lu/:i/:j
k: 1 while [ k < i ] [
sum: sum - (lu/:i/:k * lu/:k/:j)
k: k + 1
]
poke lu/:i j sum
i: i + 1
]
big: 0
i: j while [ i <= n ] [  ; find largest pivot on or below diagonal
sum: lu/:i/:j
k: 1 while [ k < j ] [
sum: sum - (lu/:i/:k * lu/:k/:j)
k: k + 1
]
poke lu/:i j sum
if big <=  dum: vv/:i * abs sum [
 big: dum  ; set big to largest pivot relative to its row
 imax: i
]
i: i + 1
]
if j <> imax [
swap-items lu imax j   ; swap rows
d: (- d)
poke vv imax vv/:j ; swap scaling factors
]
poke indx j imax   ; save swap info for BACKSUB
if zero? lu/:j/:j [ poke lu/:j j 1e-20 ]
if j <> n [
dum: 1.0 / lu/:j/:j; divide by pivot element
i: j + 1  while [ i <= n ] [
poke lu/:i j  lu/:i/:j * dum
i: i + 1
]
]
j: j + 1
]
lu
]

backsub: func [
{perform back substution on LU to solve for X given B}
b [block!] "vector to solve"
/local a i ii ip j sum
][
if any [not lu  not indx] [make error! "no LU yet to solve with"]
x: copy b
ii: 0
i: 1 while [ i <= n ] [
ip: indx/:i
sum: x/:ip
poke x ip  x/:i
either zero? ii [
if not zero? sum [ii: i]
][
j: ii  while [ j <= (i - 1) ] [
sum: sum - (lu/:i/:j * x/:j)
j: j + 1
]
]
poke x i  sum
i: i + 1
]
i: n  while [ i >= 1 ] [
sum: x/:i
j: i + 1  while [ j <= n ] [
sum: sum - (lu/:i/:j * x/:j)
j: j + 1
]
poke x i  sum / lu/:i/:i
i: i - 1
]
x
]
]


So, the object LU starts out life like this:

>> source lu
lu:
make object! [
indx: none
lu: none
x: none
d: none
n: none
   ; function code snipped
]

Now let's:

>> a: [[1 2 3] [4 5 6] [3 6 6]]
== [[1 2 3] [4 5 6] [3 6 6]]
>> lu/decomp a
== [[4 5 6] [0.75 2.25 1.5] [0.25 0.333 1]]

and take a look at LU again:

>> source lu
lu:
make object! [
indx: [2 3 3]
lu: [[4 5 6] [0.75 2.25 1.5] [0.25 0.333 1]]
x: none
d: 1
n: 3

]

In a sense LU has modified itself. LU/LU, LU/INDX and LU/N are all used by
LU/BACKSUB in its calculations. Now let's:

>> lu/backsub [7 6 3]
== [-1.67 -4.67 6]

Hmmm, did that work?

>> lu/x
== [-1.67 -4.67 6]
>> multiply-matrices a lu/x
== [[7] [6] [3]]

Guess so. All this is still really rough around the edges, though.

Anyway, what I'm trying to illustrate here, is that objects can be used as a
ki

[REBOL] Series essay Re:

1999-12-24 Thread KGD03011


Hello Joel (part 2),

Okay, now for a lot of picky little comments.

 essay/1

1.

>This model uses the non-REBOL term "entity" to refer to a specific
>data structure that represents a particular REBOL value. This was

I understand your use of the term entity to include all REBOL values. I'm not
sure if there's any advantage to using "entity" instead of just "value". To
me that is a distinction that could be relegated to a discussion of the
implementation of REBOL.

I'm wondering if you mean by "entity" an instance of a value that exists
somewhere in memory? I think that is an important distinction, but I prefer
"instance" for this meaning.

2.

>One of the most important pseudotypes in REBOL is "series",
>which comprises any datatype that can be understood as a sequence
>of values.  The series pseudotype is subdivided into the
>"any-string" and "any-block" pseudotypes; the first for any value
>that can be understood as *** a sequence of characters *** (such as
>"string") and the second for sequences of REBOL values of any type.

This is a really minor error, and one that I made in an early response to
(I think) your first post on series. There's just one exception I know of:

>> type? #{FF}
== binary!
>> any-string? #{FF}
== true
>> length? #{FF}
== 1
>> type? first #{FF}
== integer!

Each element of binary! values has only a character's worth of data, but
they're typed as integers. The basic idea of any-string! values is, of course
unaffected.

3.

>The underlying sequence may also be modeled as a compound entity;
>it contains the actual data values and two additional attributes:
>an *** "end" position (last position in use), *** and an "allocation size"
>(last position which could be used without requiring additional
>memory management activity).
[snip]
>The REBOL documentation refers to *** "the end of a series" *** (e.g. in the
>description of 'tail).  For this model, that phrase is viewed as
>verbal shorthand for "the end position of the sequence referrenced
>by the series".  This is a reasonable abbreviation, as a series is
>refers to only one sequence, which has only one end position.

Should we say that the "end" position is the last position <>?

Does a zero-length string sequence have a position in use? My preference
would be to say not. But of course it has an end position. I would prefer to
describe the end position as the one <> the last position in use,
or (better) as the position following the last element of the sequence. That
would make the following easier to understand:

>> a: "1234"
== "1234"
>> length? a
== 4
>> index? tail a
== 5
>> last a
== #"4"
>> last tail a
** Script Error: Out of range or past end.
** Where: last tail a

 essay/2

4.

>A word (variable) can be "set" to any REBOL value.  This simply
>means that the word *** is associated with *** the value in a way that
>allows it to be retrieved as needed.  The effect of evaluating
>the REBOL expression:

The concept of binding is so fundamental to REBOL, and the way REBOL is
described, that it really should be introduced right here.

 essay/3

>The 'next function produces a series entity referrings to the same
>sequence as the argument series, with the index increased by one
>(unless the index is already *** past the end of the sequence ***, in which
>case the result's index is the same as the argument's index.)

Your wording here seems to suggest that you can have an index to some
arbitrary position past the end of a sequence. I would prefer "at the end of
the sequence" or "at the tail of the sequence".

 essay/4

5.

I think you probably chose to describe APPEND before INSERT because the
behavior of APPEND seems less complex. Unfortunately for the learning curve
(but fortunately, I believe, for programming convenience), the behavior of
INSERT is much more typical of the built-in functions that manipulate
sequences. Also, APPEND is as you know just a simple mezzanine function, a
shortcut for HEAD INSERT TAIL. I think it would be more useful in the long
term to tackle INSERT first, and then explain how APPEND modifies the
behavior of INSERT.

6.

>The last position is now occupied by an *** anonymous block *** with an
>index of 2.

For me, the word anonymous is so strongly associated with Perl in this sort
of usage, that I would prefer to avoid it altogether. How about: "a block
value not directly bound to any word". Anonymity is really a non-issue in
REBOL. For example:

>> b: [1 2 3 [4 5 6] 7 8 9]
== [1 2 3 [4 5 6] 7 8 9]
>> a: fourth b
== [4 5 6]

Did the block value in the fourth position of the outer sequence suddenly
stop being anonymous when we bound it to 'a ? 'a of course is now bound to a
different (but identical) value instance. So, if we're going to talk about
anonymous blocks, we might as well talk about anonymous integers as well, or
any other value that can be contained within a sequence.

(I kind of get the feeling that you may be mixing up "block as sequence" and
"block as series" - perhaps y

[REBOL] Series essay Re:

1999-12-24 Thread KGD03011


Hello Joel,

Hope you're over your flu by now. I am truly amazed that anyone can write
such a coherent and ground-breaking essay under such conditions!

I've read your essay, and think the model will be very useful. Overall I
believe it is accurate, and it is also reasonably easy to understand.

I have a lot of comments to make, so I think I'll split them up into two
messages. In the first post (this one) I'll comment on the diagrams, and in
the second one I'll make some miscellaneous comments on your explanations.

I'll try to copy your usage of series and sequence, although it's likely that
I'll fall out of it somewhere along the line. Please forgive me if I do. I
still prefer to use the term series in an ambiguous sense, with disambiguation
wherever necessary through such expressions as "series value" to mean series
in your strict sense, and "series itself" or "underlying series" to mean
what you call a sequence. However, in describing series with the detail and
rigor you are attempting, I recognise that your unambiguous terms can be very
useful.

1. We need to stress the uniqueness of series values more.

>From essay/2

>The translation of the REBOL expression:
>
>[10 "1234" 11]
>
>could be described by the picture (not REBOL notation!):
>
>{{block! 1 *}}
>   |
>   V
>   <<10 * 12>>
>|
>V
>{{string! 1 *}}
>|
>V
><<#"1" #"2" #"3" #"4">>

You say that asterisks plus arrows denote references. I wonder if it might
not be more accurate to say:

{{block! 1 *}}
   |
   V
   <<10 {{string! 1 *}} 12>>
|
V
<<#"1" #"2" #"3" #"4">>

At least in my mental picture of blocks, series values are directly embedded
within blocks, rather than being referenced. That might well be inaccurate
somewhere within the implementation level, but on the model level I think
your picture may be confusing. For example, in your next diagram:

>a -> {{string! 1 *}}
> ^   |
> |   V
>b ---+   <<#"1" #"2" #"3" #"4">>

I think there's an error. 'a and 'b are bound to different (but identical)
series values, although the underlying sequence is of course the same. I
think it would be better to represent this situation as:

a -> {{string! 1 *}}
 |
 V
 <<#"1" #"2" #"3" #"4">>
 ^
 |
b -> {{string! 1 *}}

This revised diagram is very similar to one in essay/3:

>a -> {{string! 1 *}}
> |
> V
> <<#"1" #"2" #"3" #"4">>
> ^
> |
>b -> {{string! 2 *}}

Also, in essay/4 you have:

>After the last diagram above, evaluating:
>
>r: append b "X"
>
>produces the following state:
>
>a ---> {{string! 1 *}}
>   |
>   V
>   <<#"1" #"2" #"3" #"4">>
>   ^
>  / \
> /   \
>b -> {{string! 2 *}}  \
>   \
>r ---> {{string! 1 *}}

which I wouldn't quarrel with. Just as I've said before, the value of 'r is
a different but identical instance of the value of 'a.

(I assume you meant to represent the sequence as <<#"1" #"2" #"3" #"4" #"X">>)

To flog this idea a little more, what would you do with a simple case of
integers:

a: 5
b: a

? Does this give you:

 a -> 5
  ^
  |
 b ---+

or:

 a -> 5
 b -> 5

? Obviously the latter picture is more accurate, since there's nothing you
can do to 'b now to change the value that 'a is bound to. Further there is no
way you can ask 'a or 'b whether there is another word bound to the same
value.

So, in the same way, after:

a: "1234"
b: a

the only way to change the value 'a is bound to is by changing the underlying
sequence - you cannot change the basic information in the value of 'a -
neither __which__ sequence is referenced, nor the index. Your diagrams seem
to leave that possibility open.

NOTE: Please see my PS on lists.


2. We should graphically show the difference between binding and reference.

As I understand it, the relationship between words and the values they are
bound to, and the relationship between series values and the sequences they
refer to are entirely different. One really should use a different form of
arrow for these two, although that would be difficult with the ASCII lower
128!


3. Sequences are typed, too.

Your diagrams seem to leave open the possibility of this kind of situation:

a -> {{string! 1 *}}
 |
 V
 <<#"1" #"2" #"3" #"4">>
 ^
   

[REBOL] finding, then using it.. Re:

1999-12-22 Thread KGD03011


Hi -t,

I'm not sure what you're trying to do, but here are some ideas.

First, remember to put the data where you want it. FIND takes two arguments,
the first of which is the text you want to search through, and the second is
the string you want to search for. Here's an example:

>> z: copy find/last read %test.txt "main"
== "main ingredient.^/"

READ takes %test.txt as an argument, and READ's return value, plus "main"
make the two arguments for FIND. FIND's return value is copied, and assigned
to the word 'z. (If I didn't use COPY, the entire text of %test.txt would
exist as a string in the memory, and 'z would hold a pointer to the beginning
of the last occurrence of "main" within that string. With COPY, you only get
the last bit of the text of %test.txt in memory.)

Eric

--

>hey guys,
>
>I have trouble with the simplest stuff.
>
>How can I find the last occurance of a word in a file, then give that as
>a value of a word? like,
>
>read %file find/last "fred"
>caveman: fred
>
>what I've tried has not worked for me.
>
>thanks!
>--
>
>
>-t



[REBOL] Limit on number of usable words

1999-12-22 Thread KGD03011


Hello REBOLs,

I wanted to know how many words REBOL is capable of using, so I did a little
experiment:

>> system/version
== 2.2.0.3.1
>> length? first system/words
== 1178
>> for x 1 1000 1 [to word! join "word" x]
** Internal Error: No more global variable space.
** Where: to word! join "word" x
>> length? first system/words
== 1534

If I don't run any scripts from %user.r I get:

>> length? first system/words
== 950
>> for x 1 1000 1 [to word! join "word" x]
** Internal Error: No more global variable space.
** Where: to word! join "word" x
>> length? first system/words
== 1534

As you may know, once a word is created as data, it gets stored in
system/words, and never goes away, whether it is ever bound to anything or
not. Recycling seems to have no effect.

I'm not in any immediate danger of running out of words, but clearly if you
do a lot of different things in one instance of REBOL, it would be a good
idea to store as little data as possible in global words, and to try to use
standardized words with local bindings within objects or functions so that
many data structures can share the total supply of words.

Also, I've written several functions with a ' on their argument sepcifications
to allow the arguments to be entered as words rather than bothering to
enclose them with " ". For example the header of HUH looks like:

huh: func [
{Print a list of globally defined words classified by datatype}
'pattern [word! string! unset!]  "matching pattern (. and * wild)"
'type[word! unset!]  "datatype test function (eg series?)"
/any {displays words containing any type of value, even unset}
/wc  {use ? and + for wild cards}
/local tester words word-array this-type
][ ... ]

I often search for a function name like this:

>> huh *split*

@@ function!
split-block  split-path

which means the word '*split* is now using up valuable real estate.

Of course that is just a problem of my own making, but still, given that
"dialecting" is advertised as one of the major selling-points of REBOL, it's
too bad the number of usable words in REBOL is so low.

Any comments?

Eric



[REBOL] Parsing Paragraphs Re:

1999-12-21 Thread KGD03011


Hi Bernie,

I think your new version will append NONE to A if the file ends with
"^/^/", and if the file ends with "^/", only the last paragraph in A
will end with "^/".

How about:

parse read b [
  some [copy c to "^/^/" (append a c) any "^/"]
  [
end  |
[copy c to "^/" | copy c to end ](append a c)
  ]
]

Lot of bother for the last paragraph!

Eric

-

>Hi,
>
>Whoops! Just noticed that the "works like a charm" parse statement misses
>the last paragraph sometimes.
>
>I modified this:
>
>parse read b [some [copy c to "^/^/" (append a c) any "^/"] to end ]
>
>to this:
>
>parse read b [some [copy c to "^/^/" (append a c) any "^/"] copy c to
>end (append a c)]
>
>and it seems to work. I'm still trying to understand this type of parse
>statement better, so until I do, I may still have to tweak it a little.
>
>Regards,
>
>
>Bernie Schneider
>Systems Analyst
>CIBER, Inc.
>303-224-4159
>[EMAIL PROTECTED]



[REBOL] Self modifying code Re:

1999-12-21 Thread KGD03011


Here is a useful example of self-modifying code. This function will hold
a list of links to be retrieved, and retain it even if an error occurs.
To resume processing all you need to do is run the function again. If you
want to see how many links are left to be processed it's easy, just type
source get-linked-pages. The self-modification is really quite trivial, and
easily read by humans.

get-linked-pages: func [
{retrieve information from the web}
/local links link
][
links: []
if tail? links [
parse read join some-url-path some-file-name [
some [ thru {


[REBOL] Difference in "/ local" between versions ?? Re:

1999-12-21 Thread KGD03011


Hi Stephen,

The latest version of REBOL is a little stricter about not allowing duplicate
values in the function's argument block. You only need to use /local once -
all the words after that will be local to the function.

Eric



[REBOL] datatype!s (was: "logical" value referencing)

1999-12-20 Thread KGD03011


Hi Elan,

Thank you for your comments on my posting. I'm sorry, I got so involved in
trying to explain how MAKE works, that it must have seemed I thought MAKE's
behavior was reasonable.

You wrote:

>Then let make complain that it cannot process any-string! because
>any-string! is not a "fundamental datatype"! At this point in time make
>reports that it cannot process datatypes, even though it can process
>datatypes, provided they are not pseudotypes.

I agree with you entirely that MAKE gives a misleading error message in many
cases. (BTW, exactly the same problem occurs with the new function TO.) The
proposal you have made would fix most of those cases, but it wouldn't fix
this one:

>> make op! ">>"
** Script Error: Cannot use make on datatype! value.
** Where: make op! ">>"

since op! is in no way a pseudotype. I also feel that introducing pseudotype!
as yet another datatype would complicate other aspects of describing REBOL.
You'd also need to have a new pseudotype covering both fundamental datatypes
and pseudotypes.

The trouble with MAKE here is that its behavior is so complex (that's no
news, right?). Since it interprets the TYPE argument in two ways, it would
really have to give an error message explaining that neither interpretation
was allowable. In the example above, it could say:

** Script Error: Cannot use make on op! or datatype! values.

or:

** Script Error: Cannot make op! or datatype! values.

With this error:

>> make any-string! "abcde"
** Script Error: Cannot use make on datatype! value.
** Where: make any-string! "abcde"

it could say:

** Script Error: Cannot make any-string! or datatype! values.

Many users would still be wondering why MAKE even mentioned datatype! values,
but at least they'd have a bit more of a clue as to what went wrong. Also,
one interpretation of this message would be that if you can't make any-string!
values, you can't make any of the any-string! values, such as strings, issues,
email, etc. It would probably be better if MAKE just ignored the
possibility that any-string! was intended as an example value, leaving us
with:

** Script Error: Cannot use any-string! as a datatype value with make.

Of course users still wouldn't learn why any-string! wasn't make-able,
whereas with your suggestion, given that they had the initiative to learn
what a pseudotype is, they would also get this important information.

Hmmm, what do you think?

Eric



[REBOL] datatype!s (was: "logical" value referencing)

1999-12-20 Thread KGD03011


Note: This message contains a lot of tedious observations on how MAKE works,
but there are some items of more general interest following.

Hi Elan,

Sorry I've had to delay responding. You wrote:

>That's the problem. type? any-string! indeed returns datatype! However,
>any-string! is not a datatype!. As you point out later, it's a
>pseudo-type!. Therefore, it's a mistake when type? returns datatype! as
>any-string's type. Type? should report that any-string! is a pseudotype!,
>right?
>
>>
>>I <> what happens here is that any-type! is not a fundamental
>>datatype,
>
>never heard of a fundamental datatype. According to make's help text it
>doesn't require a FUNDAMENTAL datatype, but a datatype. Perhaps make's
>attempt to use any-string! as a datatype! fails, and therefore ...
>eventually, REBOL reports the error.

I got the term fundamental datatype from the REBOL help file valabout.html:

Fundamental Datatypes
  Following are the fundamental datatypes of REBOL. These are the scalar,
  and constructed values. These datatypes are divided into scalars and
  series.

The next section in this file begins:

Datatype Classifications
  In addition to the types listed above, some REBOL datatypes are
  pseudotypes. Pseudotypes identify a subset of datatypes. For example,
  the number!  pseudotype identifies the integer! and decimal! datatypes:

I think it's clear here that pseudotypes are treated as a kind of datatype.
Unfortunately there seems to be no provision as yet in REBOL's built-in
metalanguage for pseudotype.

Also, MAKE, in its interface, does not require any particular datatype; both
arguments are specified as any-type!, which means that any errors will occur
internally, during whatever processing MAKE performs.

>> ? make
Constructs and returns a new value.
Arguments:
type -- The datatype or example value. (any-type)
spec -- The attributes of the new value. (any-type)

Here's an example of (what I'd call) an interface function error:

>> length? 3
** Script Error: length? expected series argument of type: series port tuple.
** Where: length? 3

Note the word "expected" - this error happens, I take it, before LENGTH? ever
gets called.

Here's the error message from MAKE:

>> make any-string! "any-strings, anyone?"
** Script Error: Cannot use make on datatype! value.
** Where: make any-string! "any-strings, anyone?"

This seems to be an error message peculiar to MAKE, and I interpret it to
mean that MAKE "attempted" to make a new datatype, and failed. As I pointed
out before, MAKE will accept a TYPE argument of any type. I speculated in my
previous message that if the TYPE argument is a fundamental datatype! (as
explained in the REBOL documentation) it will attempt to make a data instance
of that type. If that argument is not a fundamental datatype!, it will
attempt to make a data instance of the same type. Here are some more amusing
examples:

>> make false true
== true
>> make false 0
== false
>> make false 1
== true

I have to revise my speculation. It appears that MAKE has a list of datatype!s
that it will use as datatype!s, and if the TYPE argument is not in that list,
it will attempt to use the TYPE argument as an example value. Notice:

>> make op! ">>"
** Script Error: Cannot use make on datatype! value.
** Where: make op! ">>"

Here op! wasn't in MAKE's list of make-able types (although it is a
fundamental datatype!), so it tried to use op! as an example value, and op!
is, of course, a datatype!.

>> make :+ ">>"
** Script Error: Cannot use make on op! value.
** Where: make :+ ">>"

Here MAKE attempted to use the + operator as an example value, and since its
datatype, op!, is non-make-able, an error occurs.


There are a couple of other reasons for regarding pseudotypes as datatype!s.
Pseudotypes work just the same with as other datatype!s in function
specifications, and they also work the same with FIND:

>> find [21 "string" 22] string!
== ["string" 22]
>> find [21 "string" 22] any-string!
== ["string" 22]
>> find [21 "string" 22] series!
== ["string" 22]


Hope this clears up a little of the datatype!s mystery.

Conclusion: pseudotypes are datatype!s, they just aren't make-able.


  * SPECIAL BONUS FOR DATATYPE ENTHUSIASTS *

The datatype hierarchy in the documentation is a bit off. Here is my
corrected version.

any-type
any-function
action
function
native
op
any-word
get-word
lit-word
refinement
set-word
word
bitset
char
date
error
logic
money
none
number
integer
decimal
object
port
series
any-block
block
list
lit-path
hash
paren
path
set-path
any-string
binary
email
file
issue
string
tag
url
symbol
time
tuple
unset

If you d

[REBOL] "logical" value referencing ... Re:

1999-12-16 Thread KGD03011


Elan writes:

>Regarding the any-string! problem: REBOL's error message is incorrect,
>since make does support datatypes. Any-type! should not be categorized by
>type? as being of type datatype! (which is the reason for the erroneous
>error message):
>
>>> type? string!
>== datatype!
>>> s: make string! ""
>== ""
>>> type? any-string!
>== datatype!
>>> s: make any-string! ""
>** Script Error: Cannot use make on datatype! value.
>** Where: s: make any-string! ""
>
>Sure you can use make on datatype! values. It's just any-string! is not a
>datatype! value.

If you ask REBOL, any-string! is a datatype! value.

>> datatype? any-type!
== true

I <> what happens here is that any-type! is not a fundamental
datatype, but a pseudotype. MAKE <> checks to see if the first
argument is a fundamental datatype, and when that check fails, decides the
first argument must be intended as an "example value", as noted in the
documentation:

>> ? make
Constructs and returns a new value.
Arguments:
type -- The datatype or example value. (any-type)
spec -- The attributes of the new value. (any-type)

An example of using an example value:

>> make 1 "2"
== 2

So REBOL thinks we're trying to make a new datatype, which is impossible to
do, and it winds up giving us a rather misleading error message.

This is just a guess, of course.

Eric



[REBOL] "logical" value referencing ... Re:

1999-12-14 Thread KGD03011


Hi Joel!

You wrote:

>Perhaps I should have addressed my comments to the documentation
>team, rather than the general mailing list.  However, it seemed (and
>still seems) to me that some confusion arises from lumping all of
>these operators together as operating on series values, when they
>are really working at two different levels.  I believe the extra
>level in this model makes it more immediately obvious why
>
>seriesreference1: next seriesreference1
>
>is "safe" and has no side effects on any other references to the same
>underlying data, while

I think the built-in help is usually pretty clear on this issue:

>> ? next
Returns the series at its next position.
[...]
>> ? insert
Inserts a value into a series and returns the series after the insert.
[...]

There's nothing in the description of NEXT to make you think it modifies the
series, and the description of INSERT makes it clear that the series will be
modified. Also, one section of the draft documentation, sermodify.html, gives
a list of most of the functions that modify series:

>>Modification Functions
>>REBOL offers a number of powerful functions to modify series. Some of these
>>functions described below are:
>>
>>change -- change elements
>>insert -- add elements
>>remove -- remove elements
>>clear -- clear to end
>>reverse -- reverse the order of elements in a series
>>poke -- change element by index position
>>append -- append elements to end
>>replace -- replaces one or all occurrences of element

As far as I know, only SORT is missing from this list, since it has a special
section. So I don't think it's quite fair to say that series operators are
all lumped together.

To tell you the truth, I found your model too abstract to be easily understood
(but then I've never studied the theory of computer languages). Except for
contexts and binding, REBOL is a language that's easily understood at a very
concrete level.

Perhaps what you were saying could be described this way:

Series values have two aspects: a sequence of data, and an index to a
position within that sequence. Any number of indexes may refer to a single
series. When you construct a series, you will get an index to the first
element in the series. An index defines a position within a series from which
you may read data (as with COPY or PICK), or at which you may make a
modification to the series itself (as with INSERT or POKE). You can also use
an index as a point of reference for defining a new index (as with NEXT, AT
or SKIP).

As for "superclasses" like ANY-STRING! (they're called pseudotypes in REBOL),
I was also seriously puzzled, until I began to use them myself. These are
mainly useful as a shorthand for specifying the kind of data a function will
accept. ANY-STRING! is useful, because this covers all series values that are
guaranteed to be composed of character values.

>> type? #issue
== issue!
>> type? first #issue
== char!

So if you write a function that will do something useful with that type of
data and only that type of data, you can do:

any-string-func: func [string [any-string!]][  ]

which will guarantee that your function code will only see the right kind of
data, and anyone who attempts to misuse your function will see a useful error
message courtesy of REBOL itself - no extra work on your part!

HTH,
Eric



[REBOL] saving stuff Re:

1999-12-14 Thread KGD03011


t wrote:
> Well,  I get this error
>
> Script Error: read expected source argument of type: file url object block.
>
> when I do
>
> write %file read word
>
> when I simply print word, (from the console) what I want to read pops
> right out.

Maybe you just want to do

write %file word

Eric



[REBOL] RFF: empty? for blocks Re:

1999-12-12 Thread KGD03011


Russell writes:

>> REBOL's clear doesn't clear the stored data, it "disconnects" 'list ...
from it and eventually the garbage collector reclaims the unused memory where
the data is stored.

I don't think so. REBOL's CLEAR directly affects the data that 'list is
"connected" to, and doesn't directly affect the reference of 'list itself.

>> list: [1 2 3 4 5 6 7 8 9]
== [1 2 3 4 5 6 7 8 9]
>> clear at list 6
== []
>> list
== [1 2 3 4 5]

Here's another interesting wrinkle:

>> list: [1 2 3 4 5 6 7 8 9]
== [1 2 3 4 5 6 7 8 9]
>> list2: at list 8
== [8 9]
>> clear at list 6
== []
>> list2
== [8 9]
>> head list2
== [1 2 3 4 5]

'list2 can still find the head of the data it references correctly.

Basically I agree with Russell that:

>> If one insists on establishing two words referring to the same data, then
before one clears one he should 'unset the other.

Except, usually when I have two words referring to the same series, one is at
the head of the data as a reserve, while the second is used to traverse the
data. In this case, of course, the second can be used as a point from which
to clear the data with no danger of corrupting the reference of the first.
Clearing from the head of the data while you've got other pointers farther
along in the series doesn't make sense, which is no doubt why this bug has
taken so long to be discovered.

Eric



[REBOL] RFF: empty? for blocks Re:

1999-12-11 Thread KGD03011


Hi Rachid,

EMPTY? and TAIL? really are the same:

>> same? :empty? :tail?
== true

I think you may be confusing TAIL, which returns a pointer to just past the
last element of a series, and TAIL? and EMPTY? which return true if a pointer
to a series is past the last element. My example was weird because I just
wanted to construct a series and set a pointer to its tail in one step - of
course I don't normally do that. It's easy enough to set TEST-BLOCK back to
its head with:

>> test-block: tail [1 2 3 4 5]
== []
>> test-block: head test-block
== [1 2 3 4 5]
>> index? test-block
== 1

So, while TEST-BLOCK might not be in the best of health, it isn't all that
sick either.

But, if you use FORALL or traverse a series in some other way, it often
happens that you'll end up with words bound to pointers to the ends of
series. Sometimes I use a construct like:

while [not tail? pointer][
either [] [pointer: remove pointer][pointer: next pointer]
]

where I delete elements I don't want and skip elements I want to keep. At the
end of this loop, if I want to find out if I have any elements left I have to
do,

if empty? head pointer []

where, as Robert said, it would be nicer to just get by with,

if empty? pointer []

See you,
Eric

 Original message

Hi Eric,

Empty? isn't a synonym for tail?, as far as I know. Your example is a weird
construction, because if I try to test empty? with tail I do this:

>> test: [1 2 3]
== [1 2 3]
>> tail test
== []
>> empty? test
== false

Why do you do:

> >> test-block: tail [1 2 3 4 5]

It strikes me strange to define 'test-block with the index at the tail. It
influences 'test-block from the get-go:

>> test-block: tail [1 2 3 4 5]
== []
>> index? test-block
== 6
>> head test-block
== [1 2 3 4 5]
>> index? test-block
== 6

While:

>> test: [1 2 3]
== [1 2 3]
>> index? test
== 1
>> tail test
== []
>> index? test
== 1

The index is set to 6 no matter what, and I don't think that's "healthy" for
a block. =)

Regards,
Rachid



[REBOL] RFF: empty? for blocks Re:

1999-12-08 Thread KGD03011


Robert,

empty? is kind of confusing, since it's just a synonym for tail? and doesn't
really tell you if there are no elements in the block, as there might be some
before the index point:

>> test-block: tail [1 2 3 4 5]
== []
>> empty? test-block
== true
>> head test-block
== [1 2 3 4 5]

You can always use:

>> empty? head test-block
== false

to find out if test-block is really empty.

See you,
Eric



[REBOL] What is an action? Re:

1999-12-08 Thread KGD03011


Larry,

Actions are a type of "function" (in its broader Rebol sense of any-function!)
that can't be created using Rebol itself. Actions are for all practical
purposes the same as natives (unless you're a Rebol Creator), but there is
some mysterious difference I've never seen explained. Anyone know what the
difference is?

For example:

>> type? :not
== native!
>> type? :none?
== action!
>> type? :ask
== function!

What you see here is the message that Rebol gives you when a datatype return
value is left over after a console command expression is evaluated. When you
do:

>> type? function!
== datatype!

what Rebol sees is the word 'function! , and when it evaluates that word the
result is the function! datatype, and when type? gets that as an argument it
returns the datatype! datatype. Now for some reason there are two datatypes
that are not assigned to a corresponding word: action! and unset! This
oversight can be remedied easily:

>> action!: type? :none?
== action!
>> unset!: (type?)
== unset!

I've complained about this out to feedback, twice, to no avail.

By the way, there's a function on rebol.org you can use to print out all the
words defined in Rebol categorized by their datatype - this will allow you
to see which "functions" are actions, functions, natives and ops.

http://www.rebol.org/utility/huh.r

See you,
Eric



  1   2   >