Functions

Built-in functions

Rye comes with many built-in functions, which are functions defined in a host language (Go). While solving a problem, you can build your own functions in Rye.

Rye functions

Functions are like any other Rye values. You create them by calling a function. The most common is the builitn function fn. It takes two arguments, a block of arguments and a block of code.

It returns a function value which we assign to a word using a set-word, like any other value.

say-hi: fn { name } { print join { "Hi " name } }

double: fn { x } { x * x }

is-positive: fn { n } { if n > 0 { return 1 } 0 }

The value of the last expression is returned from function calls. You don’t need to use return statements (there is a return function, for when you want to return in the middle of code).

We call them like we call built-in functions, by naming them and providing the arguments.

say-hi "Jane"
; prints: "Hi Jane"

double 5
; returns: 25

is-positive -100
; returns 0

Pure functions

If you probe built-in functions in shell you will see that most of them show something like [Pure BFunction ...]. A function being pure means that it has no side effects and that it has referential transparency. This means that with the same inputs it will always produce same output.

Above join is a pure built-in function, while print has a side effect, and function like now is not referentially transparent. It will return a different result each time you call it.

probe ?join
; prints: [Pure BFunction(1): Joins Block or list of values together]

probe ?print
; prints: [BFunction(1): Prints a value and adds a newline.]

probe ?now
; prints: [BFunction(0): Returns current Time.]

The way to create a pure function is by using pfn (function). Pure functions can only call other pure functions (built-in or normal). Pure functions are bound to a context with just pure functions so they have no access to any non-pure function or a word (variable) outside its scope (like global).

x: 101

add5: pfn { x } { x + 5 }
add5 10
; returns: 15

addx: pfn { x } { x + a }
addx 10
; Error: word a not found

say-hi: pfn { name } { print "Hi" + name }
say-hi "Anne"
; Error: word print not found

BTW: + * > we used above are also pure functions. One or two letter operator characters are op-words by default. More on this later.

Functions with no arguments

Continuing REBOL’s convention function that accept no arguments can be created with does function.

say-hi: does { print "Hi!" }

say-hi
; prinsts: Hi!

Since there is no special keyword like: func, def, function, ..., but functions are like other Rye values constructed with functions (and you can load these as a library or make your own), we tend to use more words for specific cases of constructing functions than just one keyword.

Closure

It turns out closures are just a simpler variant of this. Closure is a function that’s executed in the context it was defined in.

me: context { 
	name: "Jim" 
	intro: closure { } { print { "I'm" name } 
}

name: "Joe"

me/intro
; prints: I'm Jim

; also i we take closure out it's context and assign it locally
me -> 'intro :my-intro

my-intro
; prints: I'm Jim

A more typical use of closures is that they are returned from functions while enclosing on function’s context. Each function runs in its own context, so it’s not that different than the example above.

make-adder: fn { a } { closure { b } { a + b } }

add5: make-adder 5 
add10: make-adder 10

a: 30

add5 5
; returns: 10

add10 5
; returns: 15