Rye evaluator

We have seen in the previous chapter that Blocks of Rye values can be used to represent many different things. REBOL showed how they can also represent a programming language.

A programming language

We want to have simple, uniform and consistent rules of evaluation. These are the rules of Rye1 evaluator:

Rye code scheme

Evaluation rules in action

Let’s start a Rye shell and see the evaluation rules from the scheme above in action.

Direct values

Direct values evaluate to themselves:

Direct values


Words are usually bound to a value. Value can be a direct value or a function. Direct values evaluate to themselves, functions take arguments, if needed, run and return the result or failure.


Special word types

For now we need just 3 special word types.

Lit-word (literal word) evaluates to the word itself. Word is an indexed entity and can be used in similar way as enums would be.

Set-words bind values to words. Code on the right of them get’s evaluated, if needed, to get the value. The value is returned from such expression.

Get-words always gets the value they are bound to. We need them because if word is bound to a function, with normal word we run the function and get the result, but sometimes we need the function itself.

Special words types

Factorial example

Let’s use the evaluation rules we just learned and write a recursive factorial function.


So what are the parts that make the example work? We already saw, by using get-words in the shell, that is-equal, mul and dec are functions and what they do.

fac is a word we bind our factorial function to.

fn is a function that creates functions (yeah really!). It takes two arguments, both blocks. First is the argument list, second it the body of the function.

either is a function that works like if-else statement in other languages. It takes 3 arguments, a boolean and two blocks (of code), one for true, another for false case. Either returns the last value of the block it runs.

fn either

BFunction means a Builtin Function, a function defined in Rye’s host language Go, versus a Function defined in Rye itself.

Because Rye interpreter doesn’t evaluate blocks on it’s own, it doesn’t need any special forms for control flow, for function definition, etc … so it also doesn’t need keywords or macros. All these things are ordinary functions. Meaning you can have more of them, you can make your own, you can load them or not load them on a “library” level.