Rye is dynamic, homoiconic language inspired by Rebol, Factor, Shell and Go.
It’s main claim is that you can have a flexible syntax while being strict about state. Rye has no Null, is constant by default, treats everything as an expression, has no keywords, and every active element is a function. Words are evaluated in a hierarchy of contexts, … more about its principles
But all this was already described in multiple places. Here we try to teach quickly by showing compact, practical code with minimal commentary. So let’s dive in …
; # 80% of Rye in 20% Time [1/3]
; _inspired by Learn X in Y minutes_
; This is a comment
;
; Heads-up: Every Rye token must be separated by space
; ## The Values
; These are some literal values
1 ; integer
3.14 ; decimal
"hello" ; string
{ 1 2 "three" } ; block
; there is no nil
; These are constructed values (they use a constructor function)
true ; function that returns a boolean value
dict { "name" "Jim" "age" 32 }
table { "planet" "diameter" } { "Earth" 12756 "Mars" 6779 }
fn { a b } { a + b }
context { name: "Jim" age: 32 }
; There are multiple word value types (word types encode *evaluation behavior*)
a-word ; evaluates to bound value
set-word: ; creates a constant binding (right to left)
mod-word:: ; creates/modifies a variable (right to left)
?get-word ; returns value without calling if function
:lset-word ; creates constant (left to right)
::lmod-word ; modifies variable (left to right)
'lit-word ; evaluates to the word itself
.op-word ; takes left value as first argument
|pipe-word ; pipes left value into function
; Rye has 49 value types. The list above is not exhaustive
; ## The Rye Code
; Rye data are blocks of Rye values
{ "some" 'data }
{ { some } { 'more } ?data |or .code }
{ print "Hello world" }
{ if hot { open 'main-window } }
; ## The Evaluator
; Rye has multiple evaluators, but the main evaluator does this:
"literal values" ; evaluate to themselves
123.45
303
{ "blocks" don-t .eval } ; and so do blocks
'lit-words ; and lit-words (evaluate to a word)
; Word behavior is determined by their type
word ; evaluates to the value its bound to
; or produces an error
print "Yello" ; if value is a function it calls a function
set-word: "value" ; creates a constant word and binds a value to it
mod-word:: 1 ; modifies or creates a variable of type integer
"there you are" :msg ; lset-word takes value from the left
2 ::mod-word ; same for lmod-word
?print ; get-word returns the value, even if function
; Evaluator has more behavior, but we must first meet more value types
; ## The built-in functions
; Evaluator has clear rules to evaluate blocks of Rye values and that is it.
; It has no keywords or special forms beyond that. So to do anything we need
; a function, built-in function for starters.
; We can build a minimal Rye runtime with all of the above and just 4 built-in functions.
; true - accepts no arguments and returns a boolean true
; print - accepts any Rye value and prints it
; if - accepts a boolean and a block of code
; loop - accepts an integer and a block of code
; We can now write our first program
if true { print "Hello world" }
; and a second one
loop 3 { print "Wah" }
; prints: Wah
; Wah
; Wah
; Let's register more built-ins to our runtime: prns, range, for, either and is-multiple-of
for\ range 1 3 'i { print either is-multiple-of i 2 { "Tik" } { "Tok" } }
; prints: Tik Tok Tik
; Let `for\` not scare you, it's just a variant of `for` that accepts a word to set each iteration
; regular for doesn't need that
; Everything above is just application of (built-in) function. Let's dissect:
for\ ; - takes a block, a word (i) and a block of code to evaluate
range ; - takes two integers and produces a block { 1 2 3 }
print ; - prints the argument
either ; - takes a boolean and two blocks of code, returns result of block evaluation
is-multiple-of ; takes two integers and returns a boolean
; ## More built-ins
; Rye has many built-in functions, here are few more often used
_+ 101 10 ; 111
_< 101 10 ; false
; _+ _< are also functions, we usually use them as op-words (later)
and true false ; false
any { false "Jim" 101 } ; Jim
all { true _> 10 5 "Bob" } ; Bob
_++ to-upper "ban" "ana" ; BANana
index? "Joey" "e" ; 2 [convention: noun? means get-noun]
join\with { "uncle" "bob" } "," ; uncle,bob
head { 11 22 33 } 2 ; { 11 22 }
max { 48 256 127 } ; 256
length? union { 1 2 } { 2 3 } ; 3
transpose { { 1 2 } { "a" "b" } } ; { { 1 "a" } { 2 "b" } }
; Here we will use op-words, which we will fully introduce later
sort\by { "abc" "cd" "e" } { .length? } ; { "e" "cd" "abc" }
map { 1 2 3 } { * 10 } ; { 10 20 30 }
reduce range 10 20 'acc { * acc } ; 6704425728000
for { 11 12 13 } { .prns } ; prints: 11 12 13
var 'i 0 ; function var creates a variable
type? 123.4 ; decimal
to-integer "404" ; 404
now .year? ; 2026
"[ 1, 2, 3 ]" |parse-json ; list { 1 2 3 }
match-block { 1 2 3 } { a b c } , a + c ; 4
match { 7 5 3 } { { a : bb } { a - avg bb } } ; 3.0
; To see many more built-in function visit the Function reference:
;
; https://ryelang.org/info/base.html
;
This should be the first third of the document. This post shows the basics, next two should be more interesting, but probably also a little harder to explain. Stay tuned!
Visit the main page or our github.