[Tutorial] REBOL Values
Author |
Message |
btiffin
|
Posted: Fri Apr 11, 2008 3:49 pm Post subject: [Tutorial] REBOL Values |
|
|
REBOL values
By Brian Tiffin
April 2008
By the way ... the designer pronounces REBOL as rebel.
values
REBOL, the Relative Expression Based Object Language is like a shiny lake, hard to tell how deep it is from the surface. REBOL is deep. Like chess, simple rules lead to endless levels of mastery. Getting the hang of values is one of those levels.
expressions
REBOL evaluates expressions. The expressions may return values. Expressions may need values from other expressions as arguments. This is done mainly through a very simple left to right evaluation, using whitespace (and markers such as quotes) as the delimiter.
No newlines required
REBOL scripts to not require newlines in the source text unless double quoting strings or using semi colon to end of line comments. Quoting can seem a little strange if you are used to other environments. code: | >> string: "abcdefghij" ; this is different, but the same as
>> string: {abcdefghij} ; Brace quotes allow embedded newlines
>> long: {abc
{ def
{ ghi
{ j}
== {abc
def
ghi
j}
>> long: "abc
** Syntax Error: Missing " at long: "abc
>> |
Value slots
One of the main features of REBOL that set it apart from many other programming environments is that REBOL is a value centric engine. Please excuse the reuse of the word value in this paragraph, but I lack better vernacular. All REBOL values are saved in slots, these structures have a data type, a spelling, a value and some internal binding context.
So, in REBOL, the variable a is internally stored the same way as the number 10 or the string "abc". It took me a while to get used to this. Where a C compiler will replace an expression such as into object code that uses an external symbol table that informs a linker that there is an integer 10, stashed in memory somewhere and referenced by i. If you reverse engineer an executable C program, it will not mention i anywhere (assuming runtime debugging information is not included) but will instead be an address within the executable. At runtime, C does not need to lookup i, the code has been compiled and then linked to an address.
In REBOL, creates two slots. One a set-word! with the spelling a:, a type of set-word!, no value and binding to the global context. There is also a slot created for the 10. When the set-word! is evaluated another slot is allocated, it will have a spelling a a type of word!, a value reference (pointing to the 10), and binding to the global context. And just to make it more complicated, the value will be a reference to the 10 that has already been made and loaded when the code was lexically analyzed. I don't want to make it sound like REBOL is inefficient, it is not. The 10 is slotted as type integer!, no spelling, a value 10, and as there is no spelling, there is no need for a binding context.
A side trip for op! and action!
There are not many op! values in REBOL, but they make for human readable arithmetic. code: | >> help op!
Found these words:
* op! Returns the first value multiplied by the second.
** op! Returns the first number raised to the second numb...
+ op! Returns the result of adding two values.
- op! Returns the second value subtracted from the first...
/ op! Returns the first value divided by the second.
// op! Returns the remainder of first value divided by se...
< op! Returns TRUE if the first value is less than the s...
<= op! Returns TRUE if the first value is less than or eq...
<> op! Returns TRUE if the values are not equal.
= op! Returns TRUE if the values are equal.
== op! Returns TRUE if the values are equal and of the sa...
=? op! Returns TRUE if the values are identical.
> op! Returns TRUE if the first value is greater than th...
>= op! Returns TRUE if the first value is greater than or...
and op! Returns the first value ANDed with the second.
or op! Returns the first value ORed with the second.
xor op! Returns the first value exclusive ORed with the se...
| but there are lots of action! values. code: | >> help action!
Found these words:
abs action! Returns the absolute value.
absolute action! Returns the absolute value.
action? action! Returns TRUE for action values.
add action! Returns the result of adding two values.
and~ action! Returns the first value ANDed with the second.
any-block? action! Returns TRUE for any-block values.
any-function? action! Returns TRUE for any-function values.
any-string? action! Returns TRUE for any-string values.
any-type? action! Returns TRUE for any-type values.
any-word? action! Returns TRUE for any-word values.
at action! Returns the series at the specified index.
back action! Returns the series at its previous position.
binary? action! Returns TRUE for binary values.
bitset? action! Returns TRUE for bitset values.
block? action! Returns TRUE for block values.
change action! Changes a value in a series and returns the series...
char? action! Returns TRUE for char values.
clear action! Removes all values from the current index to the t...
complement action! Returns the one's complement value.
copy action! Returns a copy of a value.
copy* action! Returns a copy of a value.
cp action! Returns a copy of a value.
datatype? action! Returns TRUE for datatype values.
date? action! Returns TRUE for date values.
decimal? action! Returns TRUE for decimal values.
divide action! Returns the first value divided by the second.
eighth action! Returns the eighth value of a series.
email? action! Returns TRUE for email values.
empty? action! Returns TRUE if a series is at its tail.
equal? action! Returns TRUE if the values are equal.
error? action! Returns TRUE for error values.
even? action! Returns TRUE if the number is even.
event? action! Returns TRUE for event values.
fifth action! Returns the fifth value of a series.
file? action! Returns TRUE for file values.
find action! Finds a value in a series and returns the series a...
first action! Returns the first value of a series.
fourth action! Returns the fourth value of a series.
function? action! Returns TRUE for function values.
get-word? action! Returns TRUE for get-word values.
greater-or-equal? action! Returns TRUE if the first value is greater than or...
greater? action! Returns TRUE if the first value is greater than th...
hash? action! Returns TRUE for hash values.
head action! Returns the series at its head.
head? action! Returns TRUE if a series is at its head.
image? action! Returns TRUE for image values.
index? action! Returns the index number of the current position i...
insert action! Inserts a value into a series and returns the seri...
integer? action! Returns TRUE for integer values.
issue? action! Returns TRUE for issue values.
last action! Returns the last value of a series.
length? action! Returns the length of the series from the current ...
lesser-or-equal? action! Returns TRUE if the first value is less than or eq...
lesser? action! Returns TRUE if the first value is less than the s...
library? action! Returns TRUE for library values.
list? action! Returns TRUE for list values.
lit-path? action! Returns TRUE for lit-path values.
lit-word? action! Returns TRUE for lit-word values.
logic? action! Returns TRUE for logic values.
make action! Constructs and returns a new value.
max action! Returns the greater of the two values.
maximum action! Returns the greater of the two values.
min action! Returns the lesser of the two values.
minimum action! Returns the lesser of the two values.
money? action! Returns TRUE for money values.
multiply action! Returns the first value multiplied by the second.
native? action! Returns TRUE for native values.
negate action! Changes the sign of a number.
negative? action! Returns TRUE if the number is negative.
next action! Returns the series at its next position.
ninth action! Returns the ninth value of a series.
none? action! Returns TRUE for none values.
not-equal? action! Returns TRUE if the values are not equal.
number? action! Returns TRUE for number values.
object? action! Returns TRUE for object values.
odd? action! Returns TRUE if the number is odd.
op? action! Returns TRUE for op values.
or~ action! Returns the first value ORed with the second.
pair? action! Returns TRUE for pair values.
paren? action! Returns TRUE for paren values.
path action! Path selection.
path? action! Returns TRUE for path values.
pick action! Returns the value at the specified position in a s...
poke action! Changes a value at the given index. (See manual)
port? action! Returns TRUE for port values.
positive? action! Returns TRUE if the value is positive.
power action! Returns the first number raised to the second numb...
random action! Returns a random value of the same datatype.
refinement? action! Returns TRUE for refinement values.
remainder action! Returns the remainder of first value divided by se...
remove action! Removes value(s) from a series and returns after t...
routine? action! Returns TRUE for routine values.
same? action! Returns TRUE if the values are identical.
second action! Returns the second value of a series.
select action! Finds a value in the series and returns the value ...
series? action! Returns TRUE for series values.
set-path? action! Returns TRUE for set-path values.
set-word? action! Returns TRUE for set-word values.
seventh action! Returns the seventh value of a series.
sixth action! Returns the sixth value of a series.
skip action! Returns the series forward or backward from the cu...
sort action! Sorts a series.
strict-equal? action! Returns TRUE if the values are equal and of the sa...
strict-not-equal? action! Returns TRUE if the values are not equal and not o...
string? action! Returns TRUE for string values.
struct? action! Returns TRUE for struct values.
subtract action! Returns the second value subtracted from the first...
tag? action! Returns TRUE for tag values.
tail action! Returns the series at the position after the last ...
tail? action! Returns TRUE if a series is at its tail.
tenth action! Returns the tenth value of a series.
third action! Returns the third value of a series.
time? action! Returns TRUE for time values.
to action! Constructs and returns a new value after conversio...
trim action! Removes whitespace from a string. Default removes ...
tuple? action! Returns TRUE for tuple values.
unset? action! Returns TRUE for unset values.
url? action! Returns TRUE for url values.
word? action! Returns TRUE for word values.
xor~ action! Returns the first value exclusive ORed with the se...
zero? action! Returns TRUE if the number is zero. |
Parenthesis do not modify the lexical scan order of evaluation
Well, they do, but not in a way that you may think. paren! is a REBOL datatype. It is a special form of block!, an immediate block!. REBOL will replace expressions inside parenthesis during the make, load steps an implied evaluate. So code: | >> trace on
Result: (unset)
>> 2 * 3 + 3
Trace: 2 (integer)
Infix: op (multiply)
Trace: 3 (integer)
Infix: op (add)
Trace: 3 (integer)
== 9
>> 2 * (3 + 3)
Trace: 2 (integer)
Infix: op (multiply)
Trace: (3 + 3) (paren)
Trace: 3 (integer)
Infix: op (add)
Trace: 3 (integer)
== 12 |
REBOL treated the (3 + 3) not as a lexical convention, but as a data item of type paren! and evaluated it before giving it to * as an argument. And you may have noticed, that the op! types, end up calling the action! words.
Various types of word!
Along with word!, there is set-word!, get-word! and lit-word! types. code: | >> a: ['x y z]
== ['x y z]
>> :a
== ['x y z]
>> a
== ['x y z]
>> 'a
== a
>> |
Whoosy whatsy? The first expression is a set-word! a: which is assigned the block! ['x y z]. The next expression :a is a get-word!, and as it turns out, for block! values, getting is the same as evaluating. more on this in a second, but it's a powerful feature, once understood. The next expression is simply a a word!, which REBOL evaluates and returns the result. The last expression is a lit-word!. A literal word. The result of a lit-word! is the word! itself. Another powerful feature, once understood.
get-word!
get-word! values are most useful for (but not limited to) passing function references. A get-word! is defined as get the unevaluated value. Unevaluated being key. code: | >> print 123
123
>> say: print
** Script Error: print is missing its value argument
** Near: say: print
>> say: :print
>> say 123
123
>> type? :say
== native!
>> type? say
** Script Error: say is missing its value argument
** Near: type? say
>> | This example demonstrates getting the value of a function print in this case, without REBOL evaluating the actual print function. print is actually a native! function in REBOL. There is no REBOL source code, it is compiled into /Core. Our first attempt at setting say as a new way of calling print failed. print, when evaluated, wants something to print. The get-word! :print, says give me the value of print, but don't evaluate. get-word! can be applied to any word! and will return reasonable results, as the above example with :a simply returned the block! of data.
lit-word!
Ok, now things get a little bit weird. REBOL, by default evaluates words as they are encountered. But sometimes, you want the literal word, not the contents or the evaluated value. A single apostrophe specifies a lit-word! type. REBOL is also very much code is data and data is code.Sets a to a block!. By default, inner blocks are NOT evaluated. They stay as data until told otherwise. code: | >> do a
** Script Error: y has no value
** Near: y z
>> type? first a
== lit-word!
>> type? second a
== word!
>> | So evaluating the block! in a handled the 'x part, as a literal word returning x, but y has no value, so evaluation of the word! y fails. z would fail too. Lets set y and z. code: | >> y: 1 z: [this is a block of words]
== [this is a block of words]
>> do a
== [this is a block of words]
>> reduce a
== [x 1 [this is a block of words]]
>> | Is it all starting to become as clear as mud? do evaluates all the expressions and returns the last result. reduce reduces all the expressions and returns the block! or other data, depending on type. For now, look at the reduced a. A block! of x, 'x reduced to the word! x, a 1, the value of y and then the block! that is z. The word! values in z were not reduced, there were left as word! information. This opens up the door for REBOL's code is data and data is code, but requires some care when learning. Inner blocks are not reduced. And to add one more layer to the onion; code: | >> y: 1 z: (this is a block of words)
** Script Error: this has no value
** Near: this is a block of
>> | The paren! expressions are evaluated. this has no value, and the expression fails. code: | >> print 'print
== print | The lit-word! returned print which was printed. print does it's best to give meaningful data, the word! print comes out looking exactly like a string! would. REBOL does try and keep a sense of common sense.
word!
Did that sound all street?
Word! And with that sad sad old-guy quip, I'll end this tutorial.
As always, for more information, please visit rebol.com.
What amazes me every day, all this functionality sits in a 300K REBOL/Core program. 600K for REBOL/View but then you get a GUI builder as well as an Internet Viewtop
Cheers |
|
|
|
|
|
Sponsor Sponsor
|
|
|
|
|