<< Prev | - Up - | Next >> |
Oz provides functional notation as syntactic convenience. We have seen that a procedure call:
{P X1 ... Xn R}
could be used in a nested expression as a function call:
{P X1 ... Xn}
Oz also allows functional abstractions directly as syntactic notation for procedures. Therefore, the following function definition:
fun {F X1 ... Xn}
SE
end
where S is a statement and E is an expression corresponds to the following procedure definition:
proc {F X1 ... Xn R}
SR=
Eend
Warning:The exact syntax for functions as well as their transformation into procedure definitions is defined in the The Oz Notation Reference Manual.
Here we rely on the reader's intuition. Roughly speaking, the general rule for syntax formation of functions looks very similar to how procedures are formed. With the exception that, whenever a thread of control in a procedure ends in a statement, the corresponding function ends in an expression.
The program shown in Figure 6.1 is the functional equivalent to the program shown in Figure 5.7. Notice how the function AndThen/2
is unfolded into the procedure AndThen/3
. Below we show a number of steps that give some intuition of the transformation process. All the intermediate forms are legal Oz programs.
fun {AndThen BP1 BP2}
if {BP1} then {BP2}
else false end
end
Make a procedure by introducing a result variable B
:
proc {AndThen BP1 BP2 B}
B = if {BP1} then {BP2}
else false end
end
Move the result variable into the outer if-expression to make it an if-statement:
proc {AndThen BP1 BP2 B}
if {BP1} then B = {BP2}
else B = false end
end
% Syntax Convenience: functional notation
local
fun {AndThen BP1 BP2}
if {BP1} then {BP2}
else false end
end
fun {BinaryTree T}
case T
of nil then true
[] tree(K V T1 T2) then
{AndThen
fun {$} {BinaryTree T1} end
fun {$} {BinaryTree T2} end}
else false end
end
end
If you are a functional programmer, you can cheer up! You have your functions, including higher-order ones, and similar to lazy functional languages Oz allows certain forms of tail-recursion optimizations that are not found in certain strict functional languages 1 including Standard ML, Scheme, and the concurrent functional language Erlang. However, standard function definitions in Oz are not lazy. Lazy functions are also supported in Oz2.
Here is an example of the well-known higher order function Map/2
. It is tail recursive in Oz but not in Standard ML or in Scheme.
fun {Map Xs F}
case Xs
of nil then nil
[] X|Xr then {F X}|{Map Xr F}
end
end
{Browse {Map [1 2 3 4] fun {$ X} X*X end}}
andthen
and orelse
After all, we have been doing a lot of work for nothing! Oz already provides the Boolean lazy (non-strict) versions of the functions And/2
and Or/2
as the Boolean operators andthen
and orelse
respectively. The former behaves like the function AndThen/2
, and the latter evaluates its second argument only if the first argument evaluates to false
. As usual, these operators are not primitives, they are defined in Oz. Figure 6.2 defines the final version of the function BinaryTree
.
fun {BinaryTree T}
case T of nil then true
[] tree(K V T1 T2) then
{BinaryTree T1} andthen {BinaryTree T2}
else false end
end
Since now, in principal, we have some syntactic redundancy by either using procedures or functions, the question is when to use functional notation, and when not. The honest answer is that it is up to you! I will tell you my personal opinion. Here are some rules of thumb:
First, what I do not like. Given that you defined a procedure P
do not call it as a function, i.e. do not use functional nesting for procedures. Use instead procedural nesting, with nesting marker, as in the SMerge
example. Moreover, given that you defined a function, call it as function.
I tend to use function definitions when things are really functional, i.e. there is one output and, possibly many inputs, and the output is a mathematical function of the input arguments.
I tend to use procedures in most of the other cases, i.e. multiple outputs or nonfunctional definition due to stateful data types or nondeterministic definitions3.
One may relax the previous rule and use functions when there is a clear direction of information-flow although the definition is not strictly functional. After all functions are concise.
<< Prev | - Up - | Next >> |