# Functions in Symata



In [1]:

using Symata # load Symata and enter Symata mode



There are (more or less) three ways to define functions in Symata.

• via rules
• via the host language (Julia)
• via the pure function expression head Function

## Basics of defining and using functions

This is how you define a function using rules



In [2]:

f(x_) := x^2

f(2)




Out[2]:

$$4$$



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]:

$$\left[ \left( x + y \right) ^{2},\text{"dog"}^{2},4.0 \right]$$




In [4]:

ClearAll(f)   # remove the definition for f



This computes the nth Fibonacci number.



In [5]:

fib(1) := 1
fib(2) := 1
fib(n_) := fib(n-1) + fib(n-2)

fib(10)




Out[5]:

$$55$$



A compound statement can be written like this.



In [6]:

addone(x_) := (a = 1,  x + a)




Out[6]:

$$1 + y$$



But, the variable a is not local to the function. The global value of a is set.



In [7]:

a




Out[7]:

$$1$$



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]:

$$4 + z$$



The global values of c and d are not affected.



In [10]:

[c,d]




Out[10]:

$$\left[ c,d \right]$$



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_Floatgt5) := 1




In [12]:

g(10.0)   # The conditions in the new definition are satisfied by 10.0




Out[12]:

$$1$$




In [13]:

[g(4.0), g(10), g(q + r)] # The definition using Module applies here




Out[13]:

$$\left[ 8.0,14,4 + q + r \right]$$



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]:

$$\left[ r,h \! \left( r^{3} \right) ,q + r,h \! \left( q^{2} + 2 \ q \ r + r^{2} \right) ,4,2 \right]$$



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]:

Power(r,2)




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]:

$$y + y^{4} + y^{7} + y^{10}$$




In [20]:

Apply(ClearAll, UserSyms())



## Set and SetDelayed

Why did we use := rather than = above ? One reason is that it is safer. The following example shows why.



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]:

$$\left[ a^{2},a^{2},9,a^{2} \right]$$



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]:

$$\left[ \left[ \text{HoldPattern} \! \left( f \! \left( x\text{_} \right) \right) \text{:>}x^{2} \right] , \left[ \text{HoldPattern} \! \left( g \! \left( x\text{_} \right) \right) \text{:>}x^{2} \right] , \left[ \text{HoldPattern} \! \left( h \! \left( x\text{_} \right) \right) \text{:>}9 \right] , \left[ \text{HoldPattern} \! \left( j \! \left( x\text{_} \right) \right) \text{:>}x^{2} \right] \right]$$




In [23]:

ClearAll(f,g,h,j,x)  # clear the symbols used in this example



## Julia functions

We mentioned above that these defintions define Rules. You can also use compiled functions in Symata. One way is to code such a function directly in the host language, Julia.



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]:

$$9$$




In [27]:

f("dog")  # This calls the Julia function, so we get what "dog"^2 means in Julia




Out[27]:

$$\text{"dogdog"}$$



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]:

$$\left( a + b \right) ^{2}$$



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.)

## Pure (anonymous) functions

Anonymous or pure functions are used like this:



In [29]:

Function(x, x^2)(a)




Out[29]:

$$a^{2}$$



The infix operator -> is equivalent to Function. Note that this is not a Julia function.



In [30]:

(x -> x^2)(a)




Out[30]:

$$a^{2}$$



A function of two variables is defined like this:



In [31]:

([x,y] -> x^2 + y^2)(3,4)




Out[31]:

$$25$$



### Version and date



In [32]:

VersionInfo()




Symata version     0.4.1-dev.3
Julia version      0.7.0-beta2.1
Python version     2.7.14+
SymPy version      1.0




In [33]:

InputForm(Now())




Out[33]:

2018-07-20T13:18:33.604