If one asks you what “computing” means to you, a natural answer would be anything that a computer can do for you. So what is a computer? Perhaps a device you carry with you that can run apps, browse the net, and communicate with people? This would include your laptop, smartphones, etc. It could also be something just as simple as a calculator - a device that does arithmetic for you. Or it could be even simpler, like a clock - a device that can measure time.

To be concrete, we can ask for a computer to be a device that can perform some “computation”.
A *computation* is some task that given some input, produces some relevant outputs based on it.
This disqualifies the clock as a computer, as it cannot behave differently based on some input (or can it?)

To push our imaginative boundaries on what is the bare minimum to qualify as a computer, let us try a thought experiment.

Say you are in a multi-storey building where each floor is exactly $1$ meter high, so the $n$-th floor is at $n$ meters from the ground.
You have two things: a *stopwatch* and a small *stone*.
**What happens if you drop the stone from the $n$-th floor and measure the time it takes to hit the ground?** (for simplicity, assume $g = 10$ and negligible air resistance)

From elementary kinematics, we know that $h = \frac12 g t^2$, and therefore $t = \sqrt{\frac{n}{5}}$. Now if I was given an integer $x$, and wanted to find its square root, I could go to the $5x$-th floor, and measure the time for the stone to fall.

Therefore this box above is actually a computer! Just you, a stopwatch, a stone, and a multi-storey building.

In the above setting, who actually performed the computation?

- Was it you? You just pressed start and stop, but could not control the actual behaviour of the objects.
- Was it the stopwatch? It only measured time.
- Was it the stone? It alone could not have done anything useful.
- Was it the building? It just provided a way for you to run the computation but did not “perform” the computation.

The actual hero here is hidden in the details, $h = \frac12gt^2$!
*Gravity* is the actual driving force (pun intended) for the computation here.
We were able to harness the laws of nature with gadgets we had (stopwatch, stone, building) to be able to perform a computation and extract useful information.

This is precisely what computing is as well! We harness the nature of systems that behave according to the laws of quantum mechanics. We “rephrase” the computation we are interested in into the equations that describe the dynamics of these systems, and let them “run” to perform the computation.

Can you think of other cool examples of a computer?

]]>- For frequently used symbols, declare aliases in your preamble: e.g.
`\newcommand{\cO}{\mathcal O}`

`$$ ... $$`

is deprecated, use`\[ ... \]`

instead.- Always write
`the variable~$x$`

instead of`the variable $x$`

, so that latex will try to keep “variable” and “x” on the same line.

- One sentence per line makes for happy diffs.
- Use some demarcators to make the file more readable, like:

```
%==============================================================================
\section{Section Name} \label{sec:one}
%==============================================================================
Some text here...
%------------------------------------------------------------------------------
\subsection{Subsection} \label{sec:oneone}
%------------------------------------------------------------------------------
Some text here...
```

- Use
`\cref`

instead of`\ref`

for smarter ref. names. (import with`\usepackage{cleveref}`

) - Use
`\Cref`

at the beginning of sentences and`\cref`

in the middle.- Do this even if you pass “capitalise” to the cleveref package, because
`\Cref`

forces things to be unabbreviated (eg. “Equation” instead of “Eq.”)

- Do this even if you pass “capitalise” to the cleveref package, because
- Stick to some labelling convention, like
`\label{sec:some-section} \label{subsec:some-subsection} \label{eq:some-equation} \label{tab:some-table} \label{fig:some-figure}`

Overleaf has some great tutorials for latex.

Most of these tips are taken from my advisor Michael Walter. I also want to thank Harold for explaining some of these.

]]>Lean 4 has very nice constructs for writing “imperative” looking code. This was presented in a functional pearl by Seb Ullrich et. al. in ‘do’ unchained: embracing local imperativity in a purely functional language.

Here are a few random highlights:

The `do`

notation allows for imperative code, like `while`

and `for`

-loops. And lean’s compiler does reuse analysis to optimize mutation of objects by doing them in-place when possible. Especially useful when mutating lists or arrays. And this is surprisingly good! With no effort, I managed to write very efficient code with “mutation”.

Here is a BFS code from day 12:

```
def bfs (grid : Grid) (s e : Pos) : Nat := Option.get! do
let n := grid.length
let m := grid.head!.length
let neigh : Pos → List Pos
| u@(x, y) => Id.run do
let mut res := []
if x > 0 then res := (x - 1, y) :: res
if y > 0 then res := (x, y - 1) :: res
if x + 1 < n then res := (x + 1, y) :: res
if y + 1 < m then res := (x, y + 1) :: res
res.filter (grid.at · <= grid.at u + 1)
let mut q := Queue.empty.enqueue (s, 0)
let mut seen := [s]
while not q.isEmpty do
let ((u, d), q') := q.dequeue?.get!
q := q'
if u == e then return d
for v in neigh u do
if not $ seen.elem v then
q := q.enqueue (v, d + 1)
seen := v :: seen
none
```

Lean’s macro system makes it very nice to extend the syntax, like this one in day 22:

```
-- ...
macro_rules | `($x ∈ [ $l ... $r ]) => `($l ≤ $x && $x ≤ $r)
def Grid.next₂ (g : Grid) : Pos → Pos | p@(x, y, d) => Id.run do
if let .Up := d then
if x == 1 && y ∈ [ 51 ... 100] then return (y + 100, 1, .Rt) -- A → F
-- ...
```

One issue I ran into was with defining recursive functions over a nested type. Somehow lean is unable to figure out the function terminates. Here is an example from day 7:

Consider a tree type, where the children are stored in a list.

```
inductive FSTree :=
| Node (name : String) (size : Nat) (children : List FSTree)
| Leaf (name : String) (size : Nat)
```

Here is a simple recursive function that computes the subtree size.

```
partial def FSTree.part1 : FSTree → Nat
| Node _ sz sub => (if sz <= 100000 then sz else 0) + (sub.map part1).foldl Nat.add 0
| _ => 0
```

I have to mark it `partial`

because lean is unable to prove termination - the indirection `FSTree → List → FSTree`

confuses it.
My understanding is that it is impossible to create a cyclic data structure, so lean should accept this function. Perhaps there is some simple proof to convince it, but for now I don’t know how to do this.

Given $n (1 \le n \le 20)$, and a sequence $a = (a_0, \ldots, a_{2^n - 1})$ of length $2^n$, compute the following sequence:

\begin{equation} b_i = \sum_{j = 0}^{2^n - 1} (B(i \land j) \mod 2) a_j \end{equation}

where $B(x)$ is the number of $1$s in the binary representation of $x$.

Let’s define $\langle i, j \rangle = B(i \land j) \mod 2$ (bonus: This is in fact an inner product for the space $\mathbb{F}_2^n$).

Now the problem reduces to $b_i = \sum_j \langle i,j \rangle a_j$.

Notice that $\langle i,j \rangle \in \{ 0, 1 \}$. Let us convert it to $\{-1, 1\}$ by using $f(x) = (-1)^x = 1 - 2x$.

\begin{align}
c_i &= \sum_{j=0}^{2^n-1} (-1)^{\langle i,j \rangle} a_j\\

&= \sum_{j=0}^{2^n-1} (1 - 2\langle i,j \rangle) a_j\\

&= S - 2 b_i
\end{align}

where $S = \sum_j a_j$.

Does $c$ look familiar? Yes, it is the output of the Hadamard transform! This has been well studied as the Walsh-Hadamard Transform, but I shall use the quantum version to solve this problem.

Let $\ket{a} = \sum_i a_i \ket{i}$ and $\ket{c} = \sum_i c_i \ket{i}$. Remember that $H^{\otimes n} \ket{i} = \sum_j (-1)^{\langle i,j \rangle} \ket{j}$. On applying the Hadamard transform on $\ket{a}$, we have

\begin{align}
H^{\otimes n} \ket{a} &= H^{\otimes n} \sum_i a_i \ket{i}\\

&= \sum_i a_i (H^{\otimes n} \ket{i})\\

&= \sum_i a_i \left(\sum_j (-1)^{\langle i,j \rangle} \ket{j}\right)\\

&= \sum_j \left(\sum_i (-1)^{\langle i,j \rangle} a_i \right)\ket{j}\\

&= \sum_j c_j \ket{j}\\

&= \ket{c}\\

\end{align}

$c$ is just the Hadamard transform of $a$! We can now compute $b$ using $b = S - 2c$.

**Caveat**: The vectors $\ket{a}, \ket{c}$ are not normalized. This would be a problem if we wanted to actually use this in a quantum algorithm, but I am just using the braket notation to do linear algebra. So the math is still correct.

This blog on CSAcademy explains FFT and FWHT quite nicely. Quoting the implementation from there:

```
using poly = vector<int>;
int degree(const poly& p) { return p.size(); }
poly FWHT(poly P, bool inverse) {
for (int len = 1; 2 * len <= degree(P); len <<= 1) {
for (int i = 0; i < degree(P); i += 2 * len) {
for (int j = 0; j < len; j++) {
u = P[i + j];
v = P[i + len + j];
P[i + j] = u + v;
P[i + len + j] = u - v;
}
}
}
if (inverse) {
for (int i = 0; i < degree(P); i++)
P[i] = P[i] / degree(P);
}
return P;
}
```

This can be computed in time $\mathcal{O}(N \log N)$, where $N$ is the length of the sequence. (In our case, $\mathcal{O}(n 2^n)$).

But what if we wanted to solve this purely using a quantum algorithm?

Given an input quantum state $\ket{\psi}$ proportional to $\sum_i a_i \ket{i}$, prepare a quantum state $\ket{\phi}$ proportional to $\sum_i b_i \ket{i}$.

Notice that the value of $a_0$ does not affect any $b_i$, because $\langle 0,i\rangle = 0$. So WLOG, we can choose $a_0$ in the problem, before preparing the state.

**WLOG** let $a_0 = -\sum_{i = 1}^{2^n - 1} a_i$ (i.e. sum of all $a_i$ becomes zero).

Now we get $b = -2c$, which means if $\ket\phi$ is proportional to $b$, it is proportional to $c$ as well. And we can prepare $c$ by $H^{\otimes n}\ket\psi$. Therefore, $\ket\phi = H^{\otimes n} \ket\psi$

Just $n$ gates and $n$ qubits, so we have a quantum log-time algorithm! (*caveat:* state preparation cost not accounted for, and we cannot extract the exact values of $b$ without some amplitude estimation/tomography procedure.)

**Bonus**: Assume we are given an quantum state ($\ket\psi$) for arbitrary $a$ (i.e. we cannot pick $a_0$ anymore), how would you modify the $\ket 0$ component of $\ket\psi$ to fit the above procedure?

`R`

to implement the solutions.
Essentially, you are given $N$ data points $X = \langle x_i \rangle$ (could contain duplicates). You have to find an integer point $y$ minimizing the sum of distances - $\sum_i d(y, x_i)$. Each part has a different distance function:

- Part 1: $d_1(a, b) = |a - b|$
- Part 2: $d_2(a, b) = \frac{g(g + 1)}{2}$ where $g = d_1(a, b)$

Let’s optimize the expression with the distance function $d_1$. This is a very standard problem - the optimal point is the median. When there are two medians, any value between those two is optimal.

Proof (informal): Say you pick a $y$ which is not between the medians. This means that there are more points on one side of it. WLOG say that it’s the right side. Now if we consider $y’ = y + 1$. For each point on the right, the total cost would decrease by $1$ each. And for each on the left it would increase by $1$. So the total cost would decrease, contradicting that $y$ was optimal.

```
sum(abs(X - median(X)))
```

First a simpler distance function: $d_s(a, b) = (a - b)^2$. So the total cost would be $C(y) = \sum_i d_s(y, x_i) = \sum_i (y - x_i)^2$

Now notice that $C(y)$ is a quadratic equation in $y$. It has only one minimum, at the point where the derivative is zero. $C’(y) = \sum_i 2(y - x_i) = 0 \implies y = \frac{\sum_i x_i}{N} = \overline{X}$

For optimal integer points, we just round $\overline{X}$. As it is a quadratic, the closer integer will have lower cost.

```
sum((X - round(mean(X)))^2)
```

Now we’ll use the actual distance function for part 2 - $d_c(a,b) = g(g + 1) = 2 d_2(a, b)$ where $g = |a - b|$. They both will have the same optimal $y$.

\[\begin{eqnarray} C(y) &=& \sum_i d_c(y, x_i) \\ &=& \sum_i \bigg((y - x_i)^2 + |y - x_i|\bigg) \\ &=& \sum_i (y - x_i)^2 + \sum_i |y - x_i| \end{eqnarray}\]As this function is not differentiable, let us consider separate ranges for $y$. For each $1 \le j < N$, let $C_j(y)$ be the cost function when $x_j \le y < x_{j+1}$ (WLOG assume $X$ is sorted in ascending order).

\[\begin{eqnarray} C_j(y) &=& \sum_i (y - x_i)^2 + \sum_i |y - x_i| \\ &=& \sum_i (y - x_i)^2 + \sum_{i = 1}^{j} (y - x_j) + \sum_{i = j + 1}^{N} (x_j - y) \\ &=& \sum_i (y - x_i)^2 + jy - \sum_{i = 1}^{j} x_j - (N - j)y + \sum_{i = j + 1}^{N} x_j \\ &=& \sum_i (y - x_i)^2 + (2j - N)y - \sum_{i = 1}^{j} x_j + \sum_{i = j + 1}^{N} x_j \end{eqnarray}\]And it’s derivative would be:

\[\begin{eqnarray} C_j'(y) &=& \sum_i 2(y - x_i) + (2j - N) \\ &=& 2Ny - 2N\overline{X} + (2j - N) \\ &=& 2N\bigg(y - \overline{X} + \frac{j}{N} - \frac{1}{2} \bigg) \\ &=& 0 \\ \implies y_j &=& \overline{X} + \frac{1}{2} - \frac{j}{N} \end{eqnarray}\]This gives us $N$ candidates $y_j$ for the optimal positon. Now we can compute the cost for each of these values, and pick the best one.

```
min(sapply(round(mean(X) + 0.5 - seq(1, N)/N),
function(y) { sum((X - y)^2 + abs(X - y))}))
```

This has complexity $O(N^2)$, which is quite slow. Let us optimize that. Instead of taking every value, we’ll only consider the unique values. As we are rounding off $y_j$, and $\overline{X} - \frac{1}{2} \le y_j < \overline{X} + \frac{1}{2}$, we will have at most two interesting integer values.

```
min(sapply(unique(round(mean(X) + 0.5 - seq(1, N)/N)),
function(y) { sum((X - y)^2 + abs(X - y))}))
```

This would run in $O(N)$, which is as fast as it gets.

]]>There is also a short video editorial from ICPCNews, with Borys Minaiev explaining the solution.

(Link) You have $n$ ($n \le 100$) monuments/points on a rectangular grid, and want to take a photo. Given some ordering of the monuments, find the are of the region, from which it is possible to take a photo, s.t. the monuments listed from left to right are in the given order.

First we try to look for a trivial solution. We could consider all possible points, and test each one.

- One way to do this is by discretizing the grid. This is unfortunately too slow.
- Another is to randomly sample points, and take the ratio of valid samples to total samples. This unfortunately does not give enough precision.

But in both these approaches, we need a way to test if a point is valid or not. So let’s first figure that out.

Say we have selected a point $p$. Can we take a photo from $p$?

Let us consider just two monuments, $A$ and $B$. Say $A$ should be to the left of $B$, when you take a photo from $p$. How do we check this?

We can pick any point in the shaded region, and it is valid! That is, on the “right” or clockwise side of the line $AB$. This can be checked in $O(1)$ for a single point.

To check for all points, we just take each pair and check the above constraint, whether $p$ lies in the corresponding shaded region. Totally $O(n^2)$ to check against all pairs.

This observation got us really close to the solution. All we need to do is take the common shaded region, over all the constraints. We need some primitive to implement half-plane intersection, and we are done.

This is a fairly straight-forward concept. After considering some constraints, we will have an open polygon. When cutting with a new line, it will remove some vertices and edges, and potentially add two more vertices, and an edge. So processing a constraint will be $O(n)$, and totally $O(n^3)$ for the entire solution.

First, let us pull out our `Point`

template.

```
template <class T>
bool isZero(T x) { return x == 0; }
const double EPS = 1e-9;
template <>
bool isZero(double x) { return fabs(x) < EPS; }
template <class T> struct Point {
typedef Point P;
T x, y;
explicit Point(T x = 0, T y = 0) : x(x), y(y) {}
bool operator<(P p) const { return tie(x, y) < tie(p.x, p.y); }
bool operator==(P p) const { return isZero(x - p.x) && isZero(y - p.y); }
P operator+(P p) const { return P(x + p.x, y + p.y); }
P operator-(P p) const { return P(x - p.x, y - p.y); }
P operator*(T d) const { return P(x * d, y * d); }
P operator/(T d) const { return P(x / d, y / d); }
T dot(P p) const { return x * p.x + y * p.y; }
T cross(P p) const { return x * p.y - y * p.x; }
T cross(P a, P b) const { return (a - *this).cross(b - *this); }
};
```

Now, for the solution, we need two primitives: Polygon Cut and Polygon Area.

```
// Line Intersection
template <class P>
pair<int, P> lineInter(P s1, P e1, P s2, P e2) {
auto d = (e1 - s1).cross(e2 - s2);
if (isZero(d)) // if parallel
return {-(s1.cross(e1, s2) == 0), P(0, 0)};
auto p = s2.cross(e1, e2), q = s2.cross(e2, s1);
return {1, (s1 * p + e1 * q) / d};
}
// Polygon Cut
typedef Point<double> P;
vector<P> polygonCut(const vector<P> &poly, P s, P e) {
if (poly.size() <= 2) return {};
vector<P> res;
for (size_t i = 0; i < poly.size(); i++) {
P cur = poly[i], prev = i ? poly[i - 1] : poly.back();
if (isZero(s.cross(e, cur))) {
res.push_back(cur);
continue;
}
bool side = s.cross(e, cur) < 0;
if (side != (s.cross(e, prev) < 0))
res.push_back(lineInter(s, e, cur, prev).second);
if (side)
res.push_back(cur);
}
return res;
}
// Polygon Area, returns twice the actual area, signed.
template <class T>
T polygonArea2(const vector<Point<T>> &v) {
T a = v.back().cross(v[0]);
for (size_t i = 0; i + 1 < v.size(); i++)
a += v[i].cross(v[i + 1]);
return a;
}
```

Once we have these, the solution is super simple!

```
int main() {
// input boundary dimensions and no. of monuments.
int dx, dy, n;
cin >> dx >> dy >> n;
// locations of monuments
vector<P> pts(n);
for (P &p : pts) cin >> p.x >> p.y;
// required permutation from left to right
VI perm(n);
for (int &x : perm) cin >> x, x--;
// the valid region polygon, initially the entire rectangle.
vector<P> poly;
poly.emplace_back(0, 0);
poly.emplace_back(0, dy);
poly.emplace_back(dx, dy);
poly.emplace_back(dx, 0);
// process all pairs, and cut off the left side of i->j
for (int i = 0; i + 1 < n; i++)
for (int j = i + 1; j < n; j++)
poly = polygonCut(poly, pts[perm[i]], pts[perm[j]]);
// final area
cout << setprecision(10) << fixed << fabs(polygonArea2(poly) / 2) << endl;
}
```

There is also a short video editorial from ICPCNews, with Yakov Dlougach explaining the solution.

(Link) You have $n$ ($3 \le n \le 3000$) points and a pencil of thickness $t$. Find the maximum number of points you can cover with a single stroke.

You can just draw over the line joining them. So now the non-trivial problem is, are there 3 or more points you can cover?

**Incomplete**

First, let us pull out our `Point`

template.

```
using dbl = long double;
const dbl PI = acos(-1);
const dbl EPS = 1e-18;
inline bool zero(dbl a) { return fabs(a) < EPS; }
template <class T>
struct Point {
using P = Point<T>;
T x, y;
Point(T x, T y) : x(x), y(y) {}
explicit Point() : x(0), y(0) {}
bool operator==(const P &p) const { return zero(x - p.x) && zero(y - p.y); }
P operator-(const P &p) const { return P(x - p.x, y - p.y); }
P operator+(const P &p) const { return P(x + p.x, y + p.y); }
P operator*(T s) const { return P(x * s, y * s); }
P operator/(T s) const { return P(x / s, y / s); }
T cross(const P &p) const { return x * p.y - y * p.x; }
T dot(const P &p) const { return x * p.x + y * p.y; }
T norm2() const { return dot(*this); }
dbl norm() const { return sqrt(norm2()); }
dbl angle() const { return atan2(y, x); }
P rot90() const { return P(-y, x); }
P unit() const { return P(x / norm(), y / norm()); }
};
using P = Point<dbl>;
```

Now we need to compute the slopes of the tangents

```
pair<dbl, dbl> tangents(const P &p, dbl r) {
const dbl alpha2 = 1 - (r * r) / p.norm2();
const P v = p.unit() * sqrt(alpha2);
const P vp = p.unit().rot90() * sqrt(1 - alpha2);
return {(v - vp).angle(), (v + vp).angle()};
}
```

Now, the full solution:

```
// faster to read as ints instead of floats
inline int read() { int v; cin >> v; return v; }
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
const int n = read(); // number of points
const dbl t = read(); // thickness of the pencil
vector<P> pts(n); // the points
for (auto &p : pts) {
p.x = read();
p.y = read();
}
// the event list, pair of angle and entry/exit flag.
vector<pair<dbl, bool>> ev;
auto add_event = [&](dbl s, dbl e) { // enter at angle `s`, exit at `e`.
while (e < s)
e += 2 * PI;
for (dbl off : {0.0l, 2 * PI}) {
ev.emplace_back(s + off, true);
ev.emplace_back(e + off, false);
}
};
int ans = 2; // two points always possible
for (auto p : pts) { // pick the first point on the boundary, as origin.
ev.clear();
for (auto q : pts) {
if (p == q) continue;
q = q - p; // translate the point
if (q.norm() <= t) { // case 1
dbl a = q.angle();
add_event(a, a + PI);
} else { // case 2
auto [a, b] = tangents(q, t);
auto c = q.angle();
add_event(c, b);
add_event(a + PI, c + PI);
}
}
// sort by angle, and for equal angle, prefer entry events
sort(ev.begin(), ev.end(), [&](auto l, auto r) {
if (zero(l.fst - r.fst)) return l.snd && !r.snd;
return l.fst < r.fst;
});
// angle sweep to process the rotation of the stroke.
int cur = 1, best = 1;
for (const auto &[_, e] : ev) {
cur += (e ? 1 : -1);
best = max(best, cur);
}
ans = max(ans, best);
}
cout << ans << endl;
return 0;
}
```

At first sight, computational geometry might seem very hard and intimidating. But once you familiarize yourself with some basic tools and tricks, you’ll become a geometry expert! Let’s break the myth “geometry is hard” together!

It is very important to have a clean, well-tested geometry library/template. It is very easy to make minor errors when coding up geometry solutions - precision issues, edge cases, division by zero etc. So a easy-to-use, modular library helps a lot in writing quick and painless solutions.

You do not have to make your own library from scratch. You can just use an existing one (I just use KACTL, with few tweaks), or you can modify them to adapt to your style, add more primitives etc.

Also, using vector geometry makes life a lot simpler, compared to co-ordinate geometry. Dot and cross products etc. make your derivations super simple and clean.

- KACTL - easy to use, well documented, well tested geometry library.
- CF Blog by Al.Cash - A very nice tutorial on getting started with geometry problems.

- Consider transforming the input
- moving the origin
- rotating the axes (change of basis)
- scaling (be careful of changes to distances!)
- circles to points (and vice-versa)

- Look for invariants and properties
- like the shoelace formula

- Standard techniques
- sweep lines
- convex hull
- angle sweep

- Utilize existing primitives in your library
- circle-circle intersection?
- line-circle intersection?
- polygon-line intersection?

- Outline a slow/brute force solution, and look for optimizations.

**Warning:** These are from team contests. If you plan to practice them virtually later, avoid opening the problem/solution links.

Problem: ICPC WF 2020, Problem C. Domes

Solution: My Blog

Problem: ICPC WF 2020, Problem F. Ley Lines

Solution: My Blog

Problem: 2020-2021 ICPC Latin American Regional Programming Contest, Problem I. Impenetrable Wall

(full contest)

Solution: Editorial Blog, Full Solution

Problem: ICPC WF 2020, Problem N. What’s Our Vector, Victor?

Solution: Blog by Franklin_W

]]>Disclaimer: This is my understanding of these concepts. There could be some technical inaccuracies, but the overall idea would still hold.

In very simple terms, `f :: IO a`

is a computational recipe, which when executed produces a value of type `a`

. In Haskell, we can construct a huge complex object of type `IO ()`

and call it `main`

. Because you can only associate one monadic object with `main`

, to do multiple input/output operations - one must somehow compose the different `IO _`

recipes (correctly) into a single master recipe.

To make things simpler and cleaner, I will use `std::function`

to wrap and store the functions.

```
-- haskell
-- :k IO
-- IO :: * -> *
run :: IO a -> a
```

```
// c++
template <class A> struct IO {
function<A()> recipe;
IO(function<A()> r) : recipe(r) {}
A run() { return recipe(); }
};
```

Note: The `run`

function isn’t directly available in haskell, it’s just for showing the type. (Technically you can use `unsafePerformIO`

, but it is not pure).

First, I define the neccessary typeclass instances for `IO`

.

`fmap`

takes an IO action and a mapping function, and creates a new IO action - which when executed executes the input action, applies the mapping and returns the value.

```
instance Functor IO where
fmap :: (a -> b) -> IO a -> IO b
```

```
template <typename A, typename B>
IO<B> fmap(function<B(A)> fn, IO<A> io_a) {
return IO<B>([=]() { return fn(io_a.run()); });
}
```

Similarly I define the `Applicative`

instance.

```
instance Applicative IO where
pure :: a -> IO a
-- I will call this `fappl` in c++
(<*>) :: IO (a -> b) -> IO a -> IO b
```

```
template <typename A>
IO<A> pure(A val) {
return IO<A>([=]() { return val; });
}
template <typename A, typename B>
IO<B> fappl(IO<function<B(A)>> io_a__b, IO<A> io_a) { // (<*>)
return IO<B>([=]() {
function<B(A)> f = io_a__b.run();
A a = io_a.run();
return f(a);
});
}
```

And finally `Monad`

. As `return`

is a keyword in c++, I will use `Return`

instead. Remember that it is the same as `pure`

.

```
instance Monad IO where
return :: a -> IO a
(>>=) :: IO a -> (a -> IO b) -> IO b
(>>=) = bind
(>>) :: IO a -> IO b -> IO b
(>>) = seq
```

```
#define Return pure
// bind :: IO a -> (a -> IO b) -> IO b
template <typename A, typename B>
IO<B> bind(IO<A> io_a, function<IO<B>(A)> fn) {
return IO<B>([=]() {
A a = io_a.run();
IO<B> io_b = fn(a);
return io_b.run();
});
}
// (>>=) = bind
template <typename A, typename B>
IO<B> operator>>=(IO<A> io_a, function<IO<B>(A)> fn) {
return bind(io_a, fn);
}
// seq :: IO a -> IO b -> IO b
template <typename A, typename B>
IO<B> seq(IO<A> io_a, IO<B> io_b) {
return IO<B>([=]() {
io_a.run();
return io_b.run();
});
}
// (>>) = seq
template <typename A, typename B>
IO<B> operator>>(IO<A> io_a, IO<B> io_b) {
return seq(io_a, io_b);
}
```

Now to define some IO primitives provided by `System.IO`

.

First, the `Unit`

type. There is a conceptual difference between the `Void`

in Haskell and `void`

in C++. In Hask (or in type theory), the `Void`

type has no constructors, so a function returning `Void`

is an impossible function!

`Void`

in haskell is equivalent to something like `llvm_unreachable`

. And `()`

or the unit type in haskell is equivalent to `void`

in c++. But to avoid this name confusion, I’ll explicitly use a `Unit`

type.

```
// type () = ()
struct Unit {} unit;
```

Now, some output primitives:

```
// putChar :: Char -> IO ()
function<IO<Unit>(char)> putChar = [](char c) {
return IO<Unit>([=]() {
std::cout << c;
return unit;
});
};
// putStr :: String -> IO ()
function<IO<Unit>(string)> putStr = [](string s) {
return IO<Unit>([=]() {
std::cout << s;
return unit;
});
};
// putStrLn :: String -> IO ()
function<IO<Unit>(string)> putStrLn = [](string s) { return putStr(s + "\n"); };
```

And some input primitives:

```
// getChar :: IO Char
IO<char> getChar([]() {
char c;
std::cin >> c;
return c;
});
// getLine :: IO String
IO<string> getLine([]() {
string s;
getline(std::cin, s);
return s;
});
```

We can now define a haskell-ey main function, right in c++!

```
main :: IO ()
main = putStrLn "Hello World!"
```

```
IO<Unit> Main = putStrLn("Hello World!");
// the actual c/c++ main. Run the hask `Main` function.
int main() { Main.run(); }
```

And that’s our hello world program, folks!

Also thanks to overloading `>>`

and `>>=`

, we can write very haskell-ey code!

```
main :: IO ()
main = putStr "Name: " >>
fmap (\s -> "Hello " ++ s ++ "!") getLine
>>= putStrLn
```

```
IO<Unit> Main =
putStr("Name: ") >>
fmap<string, string>([](string s) { return "Hello " + s + "!"; }, getLine)
>>= putStrLn;
```

**Note:** I had to specify the template arguments for `fmap`

because c++ could not deduce it.

Here is the full code used in the post. (preview on github gist)

- One can try to implement more complex main functions, and add other primitives from Haskell.
- Think about the call trace when you call
`Main.run`

, and how the`IO`

monad construction actually works. - What about laziness? Right now the code is pretty eager (though not fully). Can you see how to translate laziness into c++?

Hope you enjoyed it!

]]>It turns out there are only three such tilings! With triangles $(n = 3)$ or squares $(n = 4)$ or hexagons $(n = 6)$.

Why is this so? I did some very minimal searching and did not find a proof, so here is my proof.

The internal angle has to be a multiple of $2\pi$. We know that the internal angle is $\theta = \frac{(n - 2)\pi}{n}$.

\[\theta \mid 2\pi \implies \frac{(n - 2)\pi}{n} \mid 2\pi \implies n - 2 \mid 2n \implies n - 2 \mid 2(n - 2) + 4 \implies n - 2 \mid 4\] \[\implies n - 2 \in \{1, 2, 4\} \implies n \in \{3, 4, 6\}\]Which proves that the only possible titlings are the ones listed above. To prove they actually exist, we just need a construction, which was done above.

What are all the regular tilings of a 3D euclidean space? How do you about proving it?

]]>