# Fractals in Elm

Elm is a purely functional language, similar to Haskell. What makes it interesting is that it is built to compile to JavaScript. It also comes with libraries for generating HTML and SVG using ordinary functions. The architecture of Elm applications is also very simple and easy to reason about.

## Elm MVC Architecture

An Elm application defines a `Model`

type, an `update`

function, and `view`

function. The signatures of these two functions are instructive:

```
update : Msg -> Model -> (Model, Cmd Msg)
view : Model -> Html msg
```

A `Model`

is a value, and the particular value at a moment in time is the “state” of the whole application. When `update`

is called with a `Msg`

and a `Model`

, it outputs a new `Model`

value, along with a `Cmd Msg`

.

And finally, to render the `Model`

to HTML, you just feed it into the `view`

function.

That’s the whole application, here’s an example I wrote that generates the Koch snowflake fractal:

This fractal is generated by taking a line segment, making 4 copies, then rotating the inner two copies so they meet at 60 degrees to one another. Then recursively apply this to all the four copies, ad infinitum.

Below I use a subscription to the clock to trigger the update function every 2 seconds:

```
import Html exposing (..)
import Svg exposing (..)
import Svg.Attributes exposing (..)
import List.FlatMap exposing (..)
import Time exposing (Time, second)
-- The model is a list of lines. This works for our fractals of topological dimension at most 1
type alias Model = List Line
init : (Model, Cmd Msg)
init = let
a = (Point 0 0)
b = (Point 1 0)
interval = (Line a b)
in
((kochStep interval), Cmd.none)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick newTime ->
(flatMap kochStep model, Cmd.none)
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every (second*2) Tick
type alias Point = { x: Float, y: Float }
type alias Line = { a: Point, b: Point}
type Msg = Tick Time
-- the Cantor dust is a 0.63-dimensional fractal, it is is compact, totally disconnected and has Lebesgue measure 0
cantorStep : Line -> Model
cantorStep ln =
let
scaleFactor = 0.33333
shiftFactor = 2 * scaleFactor
left = (scale scaleFactor ln)
right = (shift (Point shiftFactor 0) left)
in
[left, right]
-- the Koch Snowflake
kochStep : Line -> Model
kochStep ln =
let
scaleFactor = 0.33333
shiftFactor = 2 * scaleFactor
s = scale scaleFactor
m = shift (Point scaleFactor 0)
n = shift (Point -scaleFactor 0)
r = shift (Point shiftFactor 0)
left = s ln
innerLeft = m (rotate (-pi/3) left)
innerRight = r (rotate (pi/3) (n left))
right = r left
in
[left, innerLeft, innerRight, right]
rotate : Float -> Line -> Line
rotate angle ln =
let
r = rotateP angle
in
{ a = r ln.a, b = r ln.b }
-- rotateP treats Point as a vector from (0,0)
rotateP : Float -> Point -> Point
rotateP angle p =
{ x = p.x * cos(angle) - p.y * sin(angle),
y = p.x * sin(angle) + p.y * cos(angle) }
transform : Line -> Line
transform ln = (shift (Point 50 250) (scale 640 ln))
view : Model -> Html msg
view model =
svg [ width "640", height "640", viewBox "0 0 640 700", fill "#DCB35C" ]
(List.map renderLine model)
renderLine : Line -> Html msg
renderLine ln =
let
lnr = transform ln
(a,b) = (lnr.a, lnr.b)
x1s = toString( a.x )
y1s = toString( a.y )
x2s = toString( b.x )
y2s = toString( b.y )
in
(line [x1 x1s, y1 y1s, x2 x2s, y2 y2s, strokeWidth "1", stroke "black"]) []
scalePoint : Point -> Float -> Point
scalePoint pt factor =
{ pt | x = pt.x * factor, y = pt.y * factor }
scale : Float -> Line -> Line
scale factor ln =
{ ln | a = (scalePoint ln.a factor),
b = (scalePoint ln.b factor)}
addp : Point -> Point -> Point
addp p q =
{ p | x = p.x + q.x,
y = p.y + q.y }
shift : Point -> Line -> Line
shift p ln =
{ ln | a = addp ln.a p,
b = addp ln.b p }
main =
program
{
init = init
, view = view
, update = update
, subscriptions = subscriptions
}
```

One thing I really enjoy about working with Elm is that the compiler checks so many things automatically for you. The compiler errors are very helpful. Many of the things I use unit tests for in Python or Ruby happen for free in a language with a type system as rich as Elm’s.