242 lines
6.1 KiB
Text
242 lines
6.1 KiB
Text
|
#lang scribble/manual
|
||
|
@(require (for-label racket))
|
||
|
|
||
|
@title{Functions}
|
||
|
lambda expressions@section{categories}
|
||
|
Language
|
||
|
@section{related}
|
||
|
Classes/Function, Classes/AbstractFunction, Classes/FunctionDef
|
||
|
|
||
|
@section{section}
|
||
|
Introduction
|
||
|
|
||
|
A link::Classes/Function:: is an expression which defines operations to be performed when it is sent the
|
||
|
@racketblock[value:: message. In functional languages, a function would be known as a lambda expression.
|
||
|
Function definitions are enclosed in curly brackets ]
|
||
|
|
||
|
@racketblock[{}::. Argument declarations, if any, follow the open bracket. Variable declarations follow argument declarations. An expression follows the declarations.
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
{ arg a, b, c; var d; d = a * b; c + d }
|
||
|
::
|
||
|
|
||
|
Functions are not evaluated immediately when they occur in code, but are passed as values just like integers or strings.
|
||
|
|
||
|
A function may be evaluated by passing it the ]
|
||
|
|
||
|
@racketblock[value:: message and a list of arguments.
|
||
|
|
||
|
When evaluated, the function returns the value of its expression.
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
f = { arg a, b; a + b };
|
||
|
f.value(4, 5).postln;
|
||
|
f.value(10, 200).postln;
|
||
|
::
|
||
|
|
||
|
An empty function returns the value nil when evaluated.
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
{}.value.postln;
|
||
|
::
|
||
|
|
||
|
A function can be thought as a machine able to perform a task on demand, e.g. a calculator. The calculator can receive input (args) and can output a value, the result of the performed operations. The function definition can then be thought as the building of the calculator: once built, the calculator does nothing until it is requested to work (by passing the value method to a function).
|
||
|
The following figure depicts an empty function, input without output, output without input, and the general case with input and output.
|
||
|
|
||
|
]
|
||
|
@section{image}
|
||
|
functions.png#Functions::
|
||
|
|
||
|
@section{section}
|
||
|
Arguments
|
||
|
|
||
|
An argument list immediately follows the open curly bracket of a function definition. An argument list either begins with the reserved word
|
||
|
@racketblock[arg::, or is contained between two vertical bars. If a function takes no arguments, then the argument list may be omitted.
|
||
|
|
||
|
Names of arguments in the list may be initialized to a default value using the following syntax forms. Arguments which are not explicitly initialized will be set to nil if no value is passed for them.
|
||
|
|
||
|
"arg" style, default value is a literal:
|
||
|
]
|
||
|
|
||
|
@racketblock[{ arg x = 1; .... } :: link::#[1]::
|
||
|
|
||
|
"arg" style, default value is an expression:
|
||
|
]
|
||
|
|
||
|
@racketblock[{ arg x = 10.rand; ... } :: link::#[2]::
|
||
|
|
||
|
"arg" style, default value is a literal but you want to treat it like an expression:
|
||
|
]
|
||
|
|
||
|
@racketblock[{ arg x = (2); ... } :: link::#[2]::
|
||
|
|
||
|
Pipe style, default value is a literal:
|
||
|
]
|
||
|
|
||
|
@racketblock[{ |x = 1| ... } :: link::#[1]::
|
||
|
|
||
|
Pipe style, default value is an expression:
|
||
|
]
|
||
|
|
||
|
@racketblock[{ |x = (10.rand)| ... } :: link::#[2]::
|
||
|
|
||
|
If the last argument in the list is preceded by three dots (an ellipsis), then all the remaining arguments that were passed will be assigned to that variable as an link::Classes/Array::. Arguments must be separated by commas.
|
||
|
|
||
|
examples:
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
{ arg a, b, c=3; } // is equivalent to:
|
||
|
|
||
|
{ |a, b, c=3| }
|
||
|
|
||
|
{ arg x='stop', y, z=0; } // these args are initialised
|
||
|
|
||
|
{ arg a, b, c ... d; } // any arguments after the first 3 will be assigned to d as an Array
|
||
|
::
|
||
|
|
||
|
If you want all the arguments put in an Array
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
arg ... z;
|
||
|
::
|
||
|
|
||
|
In general arguments may be initialized to literals or expressions, but in the case of Function:play or SynthDef:play, they may only be initialized to literals.
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
// this is okay:
|
||
|
|
||
|
{ arg a = Array.geom(4, 100, 3); a * 4 }.value;
|
||
|
|
||
|
// this is not:
|
||
|
|
||
|
{ arg freq = Array.geom(4, 100, 3); Mix(SinOsc.ar(freq, 0, 0.1)) }.play; // silence
|
||
|
|
||
|
// but this is:
|
||
|
{ arg freq = #[ 100, 300, 900, 2700 ]; Mix(SinOsc.ar(freq, 0, 0.1)) }.play; // silence
|
||
|
::
|
||
|
|
||
|
See link::Reference/Literals:: for more information.
|
||
|
|
||
|
]
|
||
|
@section{anchor}
|
||
|
[1]::
|
||
|
@section{subsection}
|
||
|
[1] Literal argument defaults
|
||
|
|
||
|
Argument defaults that are literals are stored as part of the link::Classes/FunctionDef::. Arguments passed at runtime -- including nil -- always override the defaults:
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
f = { arg x = 1; x };
|
||
|
f.value(2); // prints 2
|
||
|
|
||
|
f.value; // prints 1
|
||
|
|
||
|
f.value(nil); // prints nil
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{anchor}
|
||
|
[2]::
|
||
|
@section{subsection}
|
||
|
[2] Expression argument defaults
|
||
|
|
||
|
Since expressions are evaluated when the function is called, they cannot be stored in the link::Classes/FunctionDef::. They are executed only if the passed-in value is nil.
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
f = { arg x = 10.rand; x };
|
||
|
f.value(100); // prints 100
|
||
|
|
||
|
f.value; // prints a number 0-9
|
||
|
|
||
|
f.value(nil); // prints a number 0-9!
|
||
|
::
|
||
|
|
||
|
This means you can use expression-style to define a default that cannot be overridden by nil.
|
||
|
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
f = { arg x = (3); x };
|
||
|
f.value(nil); // prints 3
|
||
|
::
|
||
|
|
||
|
Note: Parentheses are required when initializing an argument to an expression, if the argument list is written inside ]
|
||
|
|
||
|
@racketblock[||:: pipes.
|
||
|
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
(
|
||
|
var abc = 2;
|
||
|
{ arg x = abc+1; x } // OK
|
||
|
)
|
||
|
|
||
|
(
|
||
|
var abc = 2;
|
||
|
{ |x = abc+1| x }
|
||
|
)
|
||
|
ERROR: Parse error
|
||
|
in file 'selected text'
|
||
|
line 1 char 10:
|
||
|
{ |x = abc•+1| x }
|
||
|
-----------------------------------
|
||
|
ERROR: Command line parse failed
|
||
|
|
||
|
(
|
||
|
var abc = 2;
|
||
|
{ |x = (abc+1)| x } // OK
|
||
|
)
|
||
|
|
||
|
(
|
||
|
var abc = 2;
|
||
|
{ |x (abc+1)| x } // In ||, the = may be omitted if () are there
|
||
|
)
|
||
|
::
|
||
|
|
||
|
This is because the pipe character also serves as a binary operator. Without parentheses, expressions such as the following are ambiguous:
|
||
|
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
{ |a, b, c = a | b | c }
|
||
|
::
|
||
|
|
||
|
The following produce identical function definitions. Expression-style defaults are simply a shortcut syntax for the latter.
|
||
|
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
{ arg x = 10.rand; x };
|
||
|
|
||
|
{ arg x;
|
||
|
x ?? { x = 10.rand };
|
||
|
x
|
||
|
};
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{section}
|
||
|
Variables
|
||
|
|
||
|
Following the argument declarations are the variable declarations. These may be declared in any order. Variable lists are preceded by the reserved word
|
||
|
@racketblock[var::. There can be multiple var declaration lists if necessary. Variables may be initialized to default values in the same way as arguments. Variable declarations lists may not contain an ellipsis.
|
||
|
|
||
|
]
|
||
|
|
||
|
@racketblock[
|
||
|
var level=0, slope=1, curve=1;
|
||
|
::
|
||
|
|
||
|
]
|
||
|
|
||
|
|