In [1]:
using Symata # load Symata and enter Symata mode
There are (more or less) three ways to define functions in Symata.
Function
In [2]:
f(x_) := x^2
f(2)
Out[2]:
Note the trailing underscore in x_
. This function is implemented via a rule for rewriting expressions.
The argument to f
can be any expression:
In [3]:
[f(x+y), f("dog"), f(2.0)]
Out[3]:
In [4]:
ClearAll(f) # remove the definition for `f`
This computes the n
th Fibonacci number.
In [5]:
fib(1) := 1
fib(2) := 1
fib(n_) := fib(n-1) + fib(n-2)
fib(10)
Out[5]:
A compound statement can be written like this.
In [6]:
addone(x_) := (a = 1, x + a)
addone(y)
Out[6]:
But, the variable a
is not local to the function. The global value of a is set.
In [7]:
a
Out[7]:
To make variables local to a function, use Module
In [8]:
g(x_) := Module([c,d],(c=1,d=3,a+d+x)) # local variables are lexically scoped.
In [9]:
g(z)
Out[9]:
The global values of c
and d
are not affected.
In [10]:
[c,d]
Out[10]:
The argument to the function f
in In(2)
can be any expression. You can also make multiple definitions that apply only when the argument satisfies some requirements. For example, the following makes a definition for g
that only applies for floating point arguments greater than 5
.
In [11]:
gt5(x_) := x > 5
g(x_Float`gt5`) := 1
In [12]:
g(10.0) # The conditions in the new definition are satisfied by 10.0
Out[12]:
In [13]:
[g(4.0), g(10), g(q + r)] # The definition using `Module` applies here
Out[13]:
You can do structural matching on the argument. This matches anything that has the form of a square.
In [14]:
h(x_^2) := x
In [15]:
[h(r^2), h(r^3), h((r+q)^2), h(Expand((r+q)^2)), 4 , 2]
Out[15]:
Although 4
is the square of 2
, 2
is the square of Sqrt(2)
, and q^2 +2*q*r + r^2
is the square of r+q
, none of these match. Only expressions of the form Power(expr,2)
match. We see why h(r^2)
matches by looking at the full form of r^2
.
In [16]:
FullForm(r^2)
Out[16]:
In [17]:
ClearAll(f,h,a)
Use two trailing underscores to match one or more elements
In [18]:
g(x_Symbol, p__Integer) := Apply(Plus, x^[p])
In [19]:
g(y,1,4,7,10)
Out[19]:
In [20]:
Apply(ClearAll, UserSyms())
In [21]:
f(x_) := x^2
g(x_) = x^2
x = 3
h(x_) = x^2
j(x_) := x^2
[f(a), g(a), h(a), j(a)]
Out[21]:
In the definition of h
, x
is not a dummy variable. If you are beginning with Symata it is enough to know that :=
should be preferred and you can skip the following.
What does f(x_) := x^2
do ? When Symata evaluates this expression, it does not evaluate the right hand side, but rather holds it in its unevaluated form. When the rule is applied, say by evaluating f(a+b)
, the value that matches x_
, in this case a+b
, is substituted for x
in the right hand side and the result is evaluated with the result (a+b)^2
. Note that the value of x
at the time the definition is first evaluated has no affect on this result: The right hand side is never evaluated before subsituting for x
.
The definition g(x_) = x^2
differs in that the right hand side is evaluated when the definition is made. After this, everything is the same as for :=
. The value that matches x_
is substituted in the right hand side and the result is evaluated. If x
was unbound when the definition was made, the results are identical, because the substituion will be made before evaluating the right hand side again, so assignments to x
in the mean time will have no effect. However if x
is bound at the time of the definition, then the value of x^2
at the time of defnition is stored and the match of x_
is substituted into this expression. If x
had a value of 3
, then a+b
is substituted into 3
, which just results in 3
.
These "function" definitions actually define DownValues
. We can see that the definitions of f
,g
, and j
are the same, no matter what the future values of x
.
In [22]:
Map(DownValues, [f,g,h,j])
Out[22]:
In [23]:
ClearAll(f,g,h,j,x) # clear the symbols used in this example
In [24]:
1;
In [25]:
ClearAll(g,h,a,b)
# J(expr) interprets expr as Julia code
f = J((x) -> x^2 ) ;
In [26]:
f(3)
Out[26]:
In [27]:
f("dog") # This calls the Julia function, so we get what "dog"^2 means in Julia
Out[27]:
Note that we did not use :=
in the definition of f
. That is, f := :((x) -> x^2 )
. This would create a new anonymous function everytime f
is called, which would be very slow.
In [28]:
f(a+b)
Out[28]:
The last example works because ^
has been "overloaded" in Julia to operate on Symata expressions. (Symata expressions are objects of type Symata.Mxpr
in Julia.)
Anonymous or pure functions are used like this:
In [29]:
Function(x, x^2)(a)
Out[29]:
The infix operator ->
is equivalent to Function
. Note that this is not a Julia function.
In [30]:
(x -> x^2)(a)
Out[30]:
A function of two variables is defined like this:
In [31]:
([x,y] -> x^2 + y^2)(3,4)
Out[31]:
In [32]:
VersionInfo()
In [33]:
InputForm(Now())
Out[33]: