Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Module 3: Functions

elixir-intro/module3.livemd

Module 3: Functions

Mix.install([
  {:vega_lite, "~> 0.1.10"},
  {:kino_vega_lite, "~> 0.1.13"}
])

Preparation

In this notebook we are going to work with anoymous functions. A function is a piece of code that takes zero or more inputs and produces an output.

The following function takes exactly one input and delivers this as its output:

fn input -> input end

Note: Elixir tells us that this one line evaluates to a function. Lets try to assign it to a variable:

pipethrough = fn input -> input end

This allows us to call it with a concrete value using the . operator and at set of parentheses:

pipethrough.(42)

And yes: Input became output!

We can also define a function that represents the mathematical function $f(x) = 1.2x^2-1.3x+0.9$:

f = fn x -> 1.2*x*x - 1.3*x + 0.9 end

With this definition in place, we can calculate $f(10)$:

f.(10)

Now, we can take a sequence of $x$-values, calculate the matching $f(x)$-values, and then convert each matching combination to a map (I do not expect you to understand this code):

data =
  -10..10
  |> Enum.map(fn x -> %{"x" => x, "f(x)" => f.(x)} end)

We can use the VegaLite package to plot these data. For convenience reasons we start by creating an Vl alias. That way, we don’t have to write VegaLite all the time:

alias VegaLite, as: Vl

Now we can perform the plotting:

Vl.new(width: 400, height: 300)
|> Vl.data_from_values(data)
|> Vl.mark(:point)
|> Vl.encode_field(:x, "x", type: :quantitative)
|> Vl.encode_field(:y, "f(x)", type: :quantitative)

Exercise

Implement a circumference function that given a radius of a circle calculates the circumference of that circle:

circumference = fn r -> r*:math.pi*2 end

Pick a smallest and a largest interesting radius, and produce a dataset in the variable data_circumference which is in a format that allows it to be plotted:

data_circumference = 
  1..10
  |> Enum.map(fn x -> %{"x" => x, "f(x)" => circumference.(x)} end)

Now plot these data:

Vl.new(width: 400, height: 300)
|> Vl.data_from_values(data_circumference)
|> Vl.mark(:point)
|> Vl.encode_field(:x, "x", type: :quantitative)
|> Vl.encode_field(:y, "f(x)", type: :quantitative)

Hover the mouse over the last Vl.encode_field line until you see a popup. In this popup you will find a View on Hexdocs link. Open this link in a new tab. Look through the documentation and figure out how to define a title for an axis.

Make a copy of the previous cell in the cell below, and update it with names for the two axes:

Vl.new(width: 400, height: 300)
|> Vl.data_from_values(data_circumference)
|> Vl.mark(:point)
|> Vl.encode_field(:x, "x", type: :quantitative, title: "Hi")
|> Vl.encode_field(:y, "f(x)", type: :quantitative, title: "fuck u")

Next step …

One of the above cells looked like this:

data =
  -10..10
  |> Enum.map(fn x -> %{"x" => x, "f(x)" => f.(x)} end)

What does that even mean? We will figure out here.