# Higher Order Functions

I had the opportunity to listen to Professor Antonio Leitao's presentation at the recent CAADRIA conference. I have been following his work with interest since meeting him at ACADIA in 2011. At that time, Professor Leitao and Jose Lopes presented Rosetta - a multi-language (Racket, Javascript, Python) programming environment that targets different CAD platforms (AutoCAD, Rhino). Rosetta's appeal lay in its 'write once run everywhere' potential. However the topic of Professor Leitao's recent talk wasn't about Rosetta. Instead he was advocating the use of higher order programming for generative design.

For example, we can use functions that accept and return other functions. These are known as higher-order functions. In their paper 'Programming Languages for Generative Design: A Comparative Study' [1] Professor Leitao, Luis Santos and Jose Lopes provide an example that generates a spiral tower. Though written in VisualScheme for AutoCAD, we can recreate the program in Python for Grasshopper. As always, the definition can be downloaded at the bottom of this post.

```
"""
This is based on the spiral tower example by Antonio Leitao, Luis Santos and Jose Lopes
"""
from math import sin, pi,cos
from Rhino.Geometry import Point3d
from Rhino.Geometry.Curve import CreateInterpolatedCurve
from Rhino.Geometry.Brep import CreatePipe
from itertools import chain
def linear(a,b):
return lambda t: (a + (t* (b - a)))
def sinusoidal(a, b, d, f):
return lambda t: (a + (t * ( b - a)) + (d * sin ( 2 * pi * t * f)))
def variation (f,n):
return map(f, [_n/n for _n in range(n)])
def cylindrical(r, phi, z):
return (r*cos(phi), r*sin(phi), z)
def spiral_points(r0, r1, phi0, phi1, h, n, a, f):
return map(cylindrical,
variation(sinusoidal(r0, r1, a, f),n),
variation(linear(phi0,phi1), n),
variation(linear(0,h), n))
def spirals_points(r0, r1, h, amp, freq, spirals, turns, points):
return map(lambda phi: spiral_points(r0, r1, phi,(phi + 2*pi*turns)), h, points, amp, freq),
variation (linear (0, 2*pi), spirals))
def spiral_mesh(r0, r1, h, amp, freq, spirals, turns, points):
return (spirals_points(r0, r1, h, amp, freq, spirals, turns, points) +
spirals_points(r0, r1, h, amp, freq, spirals, -turns, points))
def pipe_from_points(radius, coords, blend = True, cap = 0):
vertices = [Point3d(*c) for c in coords]
crv = CreateInterpolatedCurve(vertices, 3)
return CreatePipe(crv, radius, blend, cap, True, 0.001, 0.001)
def spiral_mesh_pipe(r0, r1, h, amp, freq, spirals, turns, points, pipe_radius):
return map(lambda coords: pipe_from_points(pipe_radius, coords),
spiral_mesh(r0, r1, h, amp, freq, spirals, turns, points))
pipes = spiral_mesh_pipe(base_radius, top_radius, height, amplitude, frequency, num_spirals, num_turns, num_points, tube_radius)
a = list(chain(*pipes))
```

Let's look at the code inside the Python component.

**variation **is a higher order function. In this example it takes **sinusoidal** or** linear** as inputs. Note that we use the Python built-in function** map** to apply the input function to every item in the desired domain. We get a list of computed values as a result.

**spiral_points** is an important function that returns a list of (x,y,z) coordinates for a spiral. It does this by mapping the **cylindrical** function over three variations (sinusoidal, linear, linear). Think of each variation as supplying the inputs radius, phi and z height to **cylindrical**, which is analogous to the 'cylindrical coordinates' component in Grasshopper. Note the** lambda** keyword used, this means that we are using an anonymous function (not bound to a name).

After this, **spirals_points** just creates all the coordinates for multiple spirals, while **spiral_mesh** creates another set of spirals that turn in the opposite direction. The last important function is **spiral_mesh_pipe** which is responsible for creating the previewed geometry. It applies/maps **pipe_from_points** to the list of coordinates returned by a call to **spiral_mesh**. Of the functions, only** pipe_from_points** uses the Rhino.Geometry library. This can theoretically be substituted with other libraries' geometry methods (assuming we want to make this non Rhino-specific). Finally, we just use **chain** from itertools to flatten the nested list so that the Python component previews the piped breps. Phew.

I just want to mention again that this example was provided by Antonio Leitao, Luis Santos and Jose Lopes who did all the intellectual heavy lifting. I have always been using Python in an imperative style so this was a good first experience with a functional approach. I am surprised how concise the code is at the end (<50 lines) though it is probably debatable whether this impacts its readability.

Oh before I forget here's the grasshopper file.

**Reference**

- Leitao, Antonio, Luis Santos and Jose Lopes (2012) 'Programming Languages For Generative Design: A Comparative Study',
*International Journal of Architectural Computing,*10(1): 139-162.