TP

# Composing Chrismas with F#

This blog post is a part of the awesome F# Advent Calendar (see the previous entry about writing algorithms in F# from Rick Minerich), so it inevitably needs a Christmassy theme. However, there is also going to be a serious theme for the blog post, which is domain-specific languages.

One of my favorite examples of Domain-Specific Languages is a simple OpenGL library that I wrote some time ago for composing 3D graphics in F#. You can see it in my NDC 2014 talk Domain Specific Languages, the functional way and I also used it for Solving Puzzles with F# earlier on this blog.

The nice thing about the library is that it is very simple, but is rich enough to demonstrate all the important concepts. In fact, the library is so easy to use that even 8 years old can do a talk about it. So, if you're spending Christmas with your family, perhaps you can go through this article with your children!

On the more serious note, I also want to show two important programming concepts:

• Composability is perhaps the most fundamental principle of functional programming. The idea is that we can build complex things by (correctly) composing smaller (correct) building blocks. This applies to computations, user interfaces as well as 3D objects.

• Layers of abstraction is another key theme. The idea is that you can build higher-level APIs on top of lower-level ones. For example, you can process F# lists using recursion (low-level), or using functions like filter and map built on top of that (high-level). You'll see the same thing with 3D objects.

Now, let's get started and build some 3D Christmas with F#!

## Getting started with 3D

The first thing you'll need is to download the library and load it into F# Interactive. You could also create an application, but playing with the library interactively is more fun:

 1: 2: 3: 4: 5: 6: 7:  // Reference OpenTK library & functional DSL #r "OpenTK.dll" #r "OpenTK.GLControl.dll" #load "functional3d.fs" open System open System.Drawing open Functional3D 

The library exposes a single module named Fun, so the best way to start exploring it is to type Fun. and see what your editor suggests. You can start, for example, with Fun.cone to create a cone. Then, select the expression and send it to F# Interactive to see the object.

Aside from primitive objects (Fun.cone, Fun.cube, Fun.sphere, etc.), the library gives us a couple of functions that transform an object - that is, they take a 3D object, apply some transformation and return a new one. We can, use them to take a cone, make it more spiky and move it (so that the base is in the center of the coordinates):

 1: 2: 3:  Fun.cone |> Fun.scale (0.5, 0.5, 2.0) |> Fun.translate (0.0, 0.0, -1.0) 

Once the object appears, you can use the Q, W and A, S and Z, X keys to rotate the view.

## Composing stars

The first thing we'll do in this blog post is that we'll create a (very Christmassy) star. To do that, we extend our language and add a new primitive that creates a spike. In a more techincal terms, we just write a function called spike:

 1: 2: 3: 4: 5: 6: 7:  /// Creates a single spike, starting from the /// center of the world, rotated by r degrees let spike r = Fun.cone |> Fun.scale (0.5, 0.5, 2.0) |> Fun.translate (0.0, 0.0, -1.0) |> Fun.rotate (r, 0.0, 0.0) 

The spike function wraps the code that we wrote in the previous snippet. It adds one more transformation, which rotates the spike using the specified number of degrees. Now, if we want to create a star with 4 spikes, we can just write:

 1: 2: 3:  ( spike 0.0 $spike 90.0$ spike 180.0 $spike 270.0 ) |> Fun.color Color.Gold  Here, we're using the $ operator, which comes from the functional 3D DSL to put multiple objects together - it simply renders multiple 3D objects in their original location (which is why we had to move the spikes earlier on).

Now, going back to the key concepts - what we are doing here is that we are composing a more complex primitive called spike from a simpler primitives. Also, we are rising the level of abstraction, because we can now create stars in terms of spikes, rather than just cones. You can easily change the code to create other stars by adding more spike calls.

So far, we also did not need almost any F# knowledge. We just used the |> operator and function calls. If we want to be more clever about creating stars, we can generate one using list comprehensions:

 1: 2: 3: 4:  /// Represents a star with 12 spikes let star = [ for r in 0.0 .. 30.0 .. 330.0 -> spike r ] |> List.reduce ($)  This snippet generates 12 spikes and then composes all of them into a single 3D object using the List.reduce function and the $ operator (which joins two 3D objects). The last step is to add some animation. The easiest way to do this is to write a function that takes the current time and returns an object. The following snippet changes the color and scaling of the star based on time:

  1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:  /// Creates a glowing star with changing color let glowingStar time = // Values varying between -96 .. +96 and 0.7 .. 1.3 let phase = sin (time / 20.0) * 96.0 let size = 1.0 + (0.3 * sin (time / 20.0)) let clr = Color.FromArgb(255, 159+int phase, 64) // Change the color and scaling of a star star |> Fun.color clr |> Fun.scale (1.0, size, size) |> Fun.rotate (90.0, 90.0, 90.0) 

The library provides a primitive Fun.animate that takes a time-varying function and runs it. That is, the argument is a function float -> Drawing3D and the runner will call it repeatedly, incrementing the time at each step:

 1: 2: 3: 4:  // Run this line to start the animation let gs = Fun.animate glowingStar // Run this line to stop the animation gs.Cancel() 

Stars are a good start, but we obviously need more than that to compose Christmas...

## Composing Christmas trees

What we really need is a Christmas tree, decorated with a glowing star! We already have the star ready, so let's look at trees. To make our tree nicer, we're going to generate it using a variation of green shades, so let's start with a helper to get a random shade of green color:

 1: 2: 3: 4: 5: 6: 7: 8:  let rnd = Random() /// Returns a random shade of /// green color for the tree let nextGreen() = Color.FromArgb ( rnd.Next(96), rnd.Next(96, 168), rnd.Next(64) ) 

To build a Christmas tree, we're going to simply add a number of cones on top of each other (to represent different levels of the tree). This is pretty much the same as composing stars from spikes. Create a list of cones, move and scale them appropriately and then put all of them together:

 1: 2: 3: 4: 5: 6: 7: 8:  let tree = [ for i in 0.0 .. 6.0 -> let w = 0.5 + i * 0.2 Fun.cone |> Fun.color (nextGreen()) |> Fun.scale (w, w, 0.4) |> Fun.translate (0.0, 0.0, 0.30*i) ] |> List.reduce ($)  The only difficult thing about the above example is getting the constants right. Feel free to fiddle with the numbers to create different trees! Here, we're creating 7 levels and we are making them wider as we go. We also make each cone 0.4 high and move them so that they overlap by one quarter of a cone. The other part of the tree that we need is a trunk. To build one, we're simply going to create a brown cylinder, make it narrow and longer and then move it to the bottom of the tree:  1: 2: 3: 4: 5:  let trunk = Fun.cylinder |> Fun.scale (0.2, 0.2, 1.0) |> Fun.color Color.Brown |> Fun.translate (0.0, 0.0, 1.9)  Now we are pretty much done with the tree! We can write just trunk$ tree, or we can also specify rotation and move it, so that it appears in the center of the window. If the rotation of the view (using keyboard keys) got out of control, you can call Fun.resetRotation():

## Summary

As I mentioned in the introduction, the library that I used in this blog post is easy enough that an 8 year old can use it. So, if you're spending some time over Christmas with kids, you can get the library and have some fun! The source code of this blog post is available on GitHub, including the text.

On the more serious note, I wanted to show you two important ideas. First, how composability makes it possible to easily build more complex things from simple ones (this is where the F# motto "simple code to solve complex problems" comes from). The other part is levels of abstraction - at the beginning, we only had low-level abstractions such as cones and cylinders. However, as we solved our specific problem, we ended up defining reusable, higher-level DSL primitives such as tree, star and trunk. These are not single-purpose - you can reuse the code for other problems that fall into the same Christmassy domain!

namespace System
namespace System.Drawing
module Functional3D
module Fun

from Functional3D
val cone : Drawing3D

Full name: Functional3D.Fun.cone

Generate the sphere
Generates a 3D cylinder object of a unit size
val scale : x:float * y:float * z:float -> Drawing3D -> Drawing3D

Full name: Functional3D.Fun.scale

Scale the specified 3D object by the specified scales along the 3 axes
val translate : x:float * y:float * z:float -> Drawing3D -> Drawing3D

Full name: Functional3D.Fun.translate

Move the specified object by the provided offsets
val spike : r:float -> Drawing3D

Full name: Composing-christmas.spike

Creates a single spike, starting from the
center of the world, rotated by r degrees
val r : float
val rotate : x:float * y:float * z:float -> Drawing3D -> Drawing3D

Full name: Functional3D.Fun.rotate

Scale the specified 3D object by the specified scales along the 3 axes
val color : clr:Color -> Drawing3D -> Drawing3D

Full name: Functional3D.Fun.color

Set color to be used when drawing the specified 3D objects
type Color =
struct
member A : byte
member B : byte
member Equals : obj:obj -> bool
member G : byte
member GetBrightness : unit -> float32
member GetHashCode : unit -> int
member GetHue : unit -> float32
member GetSaturation : unit -> float32
member IsEmpty : bool
member IsKnownColor : bool
...
end

Full name: System.Drawing.Color
property Color.Gold: Color
val star : Drawing3D

Full name: Composing-christmas.star

Represents a star with 12 spikes
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member GetSlice : startIndex:int option * endIndex:int option -> 'T list
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

Full name: Microsoft.FSharp.Collections.List.reduce
val glowingStar : time:float -> Drawing3D

Full name: Composing-christmas.glowingStar

Creates a glowing star with changing color
val time : float
val phase : float
val sin : value:'T -> 'T (requires member Sin)

Full name: Microsoft.FSharp.Core.Operators.sin
val size : float
val clr : Color
Color.FromArgb(argb: int) : Color
Color.FromArgb(alpha: int, baseColor: Color) : Color
Color.FromArgb(red: int, green: int, blue: int) : Color
Color.FromArgb(alpha: int, red: int, green: int, blue: int) : Color
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>

Full name: Composing-christmas.gs
val animate : f:(float -> Drawing3D) -> Threading.CancellationTokenSource

Full name: Functional3D.Fun.animate
val rnd : Random

Full name: Composing-christmas.rnd
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit
member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
val nextGreen : unit -> Color

Full name: Composing-christmas.nextGreen

green color for the tree
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val tree : Drawing3D

Full name: Composing-christmas.tree
val i : float
val w : float
val trunk : Drawing3D

Full name: Composing-christmas.trunk
val cylinder : Drawing3D

Full name: Functional3D.Fun.cylinder

Generates a 3D cylinder object of a unit size
property Color.Brown: Color
val treeWithStar : time:float -> Drawing3D

Full name: Composing-christmas.treeWithStar

Tree with a glowing star on top