Functions

Builtin functions

Rye comes with many builtin functions. Functions that are defined in a host language (Go). While solving a problem you build functions of your own in Rye.

Rye functions

Functions are like any other Rye values. You create them by calling a function. The most common is 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 }

Value of the last expression is retuned from function call. You don’t need to use return statement (there is return function, for when you want to return in the middle of code).

We call them like we call builtin 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 builtin 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 builtin functions, 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.]

Function for creating pure function is fnp. Pure functions can only call other pure functions (builtin or normal). Pure functions are bound to a context with just pure functions so they have no access to any unpure function or a word (variable) outside it’s scome (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.

Fnc

Rye has a function fnc. With it you can define a custom context in which you want function to be executed.

me: context { name: "Jim" }

introduce: fnc { to } me { print { "Hi" to ", I'm" name } }

introduce "Jane"
; prints: Hi Jane , I'm Jim

introduce "Bob"
; prints: Hi Bob , I'm Jim

This function enables many interesting things, some are still being explored.

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