You have source code with various in-line comments, comment blocks, and accompanying forms of documentation.
Make the documentation first class alongside the source code by restructuring them as a unified product.
Literate programming is not strictly a functional pattern. In practice it has been popularized by Haskell, so we'll let it slide and call it functionally-inspired.
Consider an imaginary article about approaches to approximating Pi using recursive summation in Scala:
# Approximating Pi through recursive summation
## Abstract
This is an imaginary article about approaches to estimating Pi using
recursive summation in Scala.
## Background
Pi can be represented as the sum of an infinite series:
```
k
∞ (-1)
π = 4 ∑ ------
k=0 2k + 1
```
## Initial implementation
Let's write a recursive function that can be used to estimate this sum.
First, we need a way to compute each kth term:
```scala
def term(k: Int): Double = {
val n = 4 * math.pow(-1, k)
val d = 2 * k + 1
n / d.toDouble
}
```
Next, we need a way to sum them:
```scala
def pi(k: Int): Double =
if (k < 0) 0
else term(k) + pi(k - 1)
```
Let's try it out:
```scala
println(pi(1)) // 2.666666666666667
println(pi(10)) // 3.232315809405594
println(pi(100)) // 3.1514934010709914
println(pi(1000)) // 3.1425916543395442
```
That's close, but not close enough. Unfortunately, this implementation
can't do much better:
```
println(pi(10000)) // Throws java.lang.StackOverflowError
```
Attempting to run merely ten thousand iterations overflows the stack!
## Improved implementation
To avoid blowing the stack, we need a tail-recursive version of this
function:
```scala
@scala.annotation.tailrec
def piTR(k: Int, acc: Double = 0): Double =
if (k < 0) acc
else piTR(k - 1, term(k) + acc)
```
Let's put it to the test:
```scala
println(piTR(100000000)) // 3.141592663589793
```
Computing one hundred million terms may take a while, but it since`piTR` is tail-recursive, it does eventually finish.
Using literate programming tools such as Codedown and sbt-lit, we can treat this not as an article but as our source code, and keep code and documentation inextricably linked.
This file is literate Scala, and can be run using Codedown.
For presentation purposes, the source uses Scala code blocks wrapped
in Markdown code blocks. To get to the Scala, we first need to first
extract the Markdown with an extra codedown markdown
invocation:
$ curl https://earldouglas.com/posts/itof/code-to-doc.md |
codedown markdown |
codedown scala |
xargs -0 scala -nc -e
2.666666666666667
3.232315809405594
3.1514934010709914
3.1425916543395442
3.141592663589793