diff --git a/.github/workflows/build-pdf.yml b/.github/workflows/build-pdf.yml
index 3ceae47ed..bafc05951 100644
--- a/.github/workflows/build-pdf.yml
+++ b/.github/workflows/build-pdf.yml
@@ -26,11 +26,11 @@ jobs:
with:
fetch-depth: 1
- - name: Build PDF using make_sofp_pdf.sh
+ - name: Build PDF using make_all.sh
id: full-pdf
uses: docker://winitzki/sofp-docker-build:latest
with:
- args: "LYXDIR=/root/.lyx bash sofp-src/make_sofp_pdf.sh"
+ args: "LYXDIR=/root/.lyx bash sofp-src/make_all.sh"
- name: Upload built PDF
id: upload-pdf
@@ -99,7 +99,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
- asset_path: ./sofp-src/book_cover/sofp-3page-cover.pdf
+ asset_path: ./sofp-src/cover/sofp-3page-cover.pdf
asset_name: sofp-3page-cover.pdf
asset_content_type: application/pdf
diff --git a/README.md b/README.md
index 337758e17..d4e171819 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
This is the official source repository for the new book _The Science of Functional Programming: A tutorial, with examples in Scala_.
-
+
The book is a tutorial exposition of the theoretical knowledge that functional programmers need. The material is developed from first principles and contains complete explanations, derivations, and proofs of almost all required results.
@@ -86,35 +86,3 @@ or if they wish to make comments or suggestions regarding the contents of the bo
- Milestone 4 (achieved in 2021): chapters 1-12 and 14 are completed.
- Milestone 5 (ETA: June 2023): the book is finished and available for
on-demand printing at lulu.com or elsewhere.
-
-# Building a PDF version of the book from LyX sources
-
-If you want to build from source, currently you need `LyX` 2.3.x and `pdftk` installed.
-
-Change to the directory `sofp-src`.
-
-The command `bash make_sofp_pdf.sh` builds PDF files `sofp.pdf` and `sofp-draft.pdf`.
-The first file is a full draft with some unfinished chapters,
-the second file contains only finished and proofread chapters.
-
-If this does not work, you can build manually with a simple command such as `lyx --export pdf sofp.lyx`,
-but the resulting PDF version will lack certain cosmetic features such as special colors and formatting.
-
-If you do not have `LyX`, you can simply build from the provided LaTeX sources using commands such as
-
-```bash
-pdflatex --interaction=batchmode sofp.tex
-makeindex sofp.idx
-pdflatex --interaction=batchmode sofp.tex
-```
-
-# Docker image for PDF builds
-
-A Docker image (containing a compatible version of LyX and LaTeX) is configured by the repository https://github.com/winitzki/sofp-docker-build
-and is automatically uploaded to Docker Hub at https://hub.docker.com/repository/docker/winitzki/sofp-docker-build/builds
-
-This Docker image is loaded by the file [build-pdf.yml](.github/workflows/build-pdf.yml#L31) in order to build the PDF version of the book.
-
-The latest build is uploaded to Github when a new git tag is pushed.
-This happens with each new release.
-Also, a PDF build is performed on every commit to master.
diff --git a/cover/cover-no-lulu.pdf b/cover/cover-no-lulu.pdf
deleted file mode 100644
index 74acb4b40..000000000
Binary files a/cover/cover-no-lulu.pdf and /dev/null differ
diff --git a/sofp-src/old_slides/01-values-types-expressions.lyx b/old_slides/01-values-types-expressions.lyx
similarity index 100%
rename from sofp-src/old_slides/01-values-types-expressions.lyx
rename to old_slides/01-values-types-expressions.lyx
diff --git a/sofp-src/old_slides/01-values-types-expressions.pdf b/old_slides/01-values-types-expressions.pdf
similarity index 100%
rename from sofp-src/old_slides/01-values-types-expressions.pdf
rename to old_slides/01-values-types-expressions.pdf
diff --git a/sofp-src/old_slides/01-values-types-expressions.tex b/old_slides/01-values-types-expressions.tex
similarity index 100%
rename from sofp-src/old_slides/01-values-types-expressions.tex
rename to old_slides/01-values-types-expressions.tex
diff --git a/sofp-src/old_slides/02-functional-collections.lyx b/old_slides/02-functional-collections.lyx
similarity index 100%
rename from sofp-src/old_slides/02-functional-collections.lyx
rename to old_slides/02-functional-collections.lyx
diff --git a/sofp-src/old_slides/02-functional-collections.pdf b/old_slides/02-functional-collections.pdf
similarity index 100%
rename from sofp-src/old_slides/02-functional-collections.pdf
rename to old_slides/02-functional-collections.pdf
diff --git a/sofp-src/old_slides/02-functional-collections.tex b/old_slides/02-functional-collections.tex
similarity index 100%
rename from sofp-src/old_slides/02-functional-collections.tex
rename to old_slides/02-functional-collections.tex
diff --git a/sofp-src/old_slides/03-logic-of-types-1.lyx b/old_slides/03-logic-of-types-1.lyx
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-1.lyx
rename to old_slides/03-logic-of-types-1.lyx
diff --git a/sofp-src/old_slides/03-logic-of-types-1.pdf b/old_slides/03-logic-of-types-1.pdf
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-1.pdf
rename to old_slides/03-logic-of-types-1.pdf
diff --git a/sofp-src/old_slides/03-logic-of-types-1.tex b/old_slides/03-logic-of-types-1.tex
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-1.tex
rename to old_slides/03-logic-of-types-1.tex
diff --git a/sofp-src/old_slides/03-logic-of-types-2.lyx b/old_slides/03-logic-of-types-2.lyx
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-2.lyx
rename to old_slides/03-logic-of-types-2.lyx
diff --git a/sofp-src/old_slides/03-logic-of-types-2.pdf b/old_slides/03-logic-of-types-2.pdf
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-2.pdf
rename to old_slides/03-logic-of-types-2.pdf
diff --git a/sofp-src/old_slides/03-logic-of-types-2.tex b/old_slides/03-logic-of-types-2.tex
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-2.tex
rename to old_slides/03-logic-of-types-2.tex
diff --git a/sofp-src/old_slides/03-logic-of-types-3.lyx b/old_slides/03-logic-of-types-3.lyx
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-3.lyx
rename to old_slides/03-logic-of-types-3.lyx
diff --git a/sofp-src/old_slides/03-logic-of-types-3.pdf b/old_slides/03-logic-of-types-3.pdf
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-3.pdf
rename to old_slides/03-logic-of-types-3.pdf
diff --git a/sofp-src/old_slides/03-logic-of-types-3.tex b/old_slides/03-logic-of-types-3.tex
similarity index 100%
rename from sofp-src/old_slides/03-logic-of-types-3.tex
rename to old_slides/03-logic-of-types-3.tex
diff --git a/sofp-src/old_slides/04-functors.lyx b/old_slides/04-functors.lyx
similarity index 100%
rename from sofp-src/old_slides/04-functors.lyx
rename to old_slides/04-functors.lyx
diff --git a/sofp-src/old_slides/04-functors.pdf b/old_slides/04-functors.pdf
similarity index 100%
rename from sofp-src/old_slides/04-functors.pdf
rename to old_slides/04-functors.pdf
diff --git a/sofp-src/old_slides/04-functors.tex b/old_slides/04-functors.tex
similarity index 100%
rename from sofp-src/old_slides/04-functors.tex
rename to old_slides/04-functors.tex
diff --git a/sofp-src/old_slides/05-type-classes.lyx b/old_slides/05-type-classes.lyx
similarity index 100%
rename from sofp-src/old_slides/05-type-classes.lyx
rename to old_slides/05-type-classes.lyx
diff --git a/sofp-src/old_slides/05-type-classes.pdf b/old_slides/05-type-classes.pdf
similarity index 100%
rename from sofp-src/old_slides/05-type-classes.pdf
rename to old_slides/05-type-classes.pdf
diff --git a/sofp-src/old_slides/05-type-classes.tex b/old_slides/05-type-classes.tex
similarity index 100%
rename from sofp-src/old_slides/05-type-classes.tex
rename to old_slides/05-type-classes.tex
diff --git a/sofp-src/old_slides/06-filterable-functors.lyx b/old_slides/06-filterable-functors.lyx
similarity index 100%
rename from sofp-src/old_slides/06-filterable-functors.lyx
rename to old_slides/06-filterable-functors.lyx
diff --git a/sofp-src/old_slides/06-filterable-functors.pdf b/old_slides/06-filterable-functors.pdf
similarity index 100%
rename from sofp-src/old_slides/06-filterable-functors.pdf
rename to old_slides/06-filterable-functors.pdf
diff --git a/sofp-src/old_slides/06-filterable-functors.tex b/old_slides/06-filterable-functors.tex
similarity index 100%
rename from sofp-src/old_slides/06-filterable-functors.tex
rename to old_slides/06-filterable-functors.tex
diff --git a/sofp-src/old_slides/07-monads-part1.lyx b/old_slides/07-monads-part1.lyx
similarity index 100%
rename from sofp-src/old_slides/07-monads-part1.lyx
rename to old_slides/07-monads-part1.lyx
diff --git a/sofp-src/old_slides/07-monads-part1.pdf b/old_slides/07-monads-part1.pdf
similarity index 100%
rename from sofp-src/old_slides/07-monads-part1.pdf
rename to old_slides/07-monads-part1.pdf
diff --git a/sofp-src/old_slides/07-monads-part1.tex b/old_slides/07-monads-part1.tex
similarity index 100%
rename from sofp-src/old_slides/07-monads-part1.tex
rename to old_slides/07-monads-part1.tex
diff --git a/sofp-src/old_slides/07-monads-part2.lyx b/old_slides/07-monads-part2.lyx
similarity index 100%
rename from sofp-src/old_slides/07-monads-part2.lyx
rename to old_slides/07-monads-part2.lyx
diff --git a/sofp-src/old_slides/07-monads-part2.pdf b/old_slides/07-monads-part2.pdf
similarity index 100%
rename from sofp-src/old_slides/07-monads-part2.pdf
rename to old_slides/07-monads-part2.pdf
diff --git a/sofp-src/old_slides/07-monads-part2.tex b/old_slides/07-monads-part2.tex
similarity index 100%
rename from sofp-src/old_slides/07-monads-part2.tex
rename to old_slides/07-monads-part2.tex
diff --git a/sofp-src/old_slides/08-applicatives-part1.lyx b/old_slides/08-applicatives-part1.lyx
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part1.lyx
rename to old_slides/08-applicatives-part1.lyx
diff --git a/sofp-src/old_slides/08-applicatives-part1.pdf b/old_slides/08-applicatives-part1.pdf
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part1.pdf
rename to old_slides/08-applicatives-part1.pdf
diff --git a/sofp-src/old_slides/08-applicatives-part1.tex b/old_slides/08-applicatives-part1.tex
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part1.tex
rename to old_slides/08-applicatives-part1.tex
diff --git a/sofp-src/old_slides/08-applicatives-part2.lyx b/old_slides/08-applicatives-part2.lyx
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part2.lyx
rename to old_slides/08-applicatives-part2.lyx
diff --git a/sofp-src/old_slides/08-applicatives-part2.pdf b/old_slides/08-applicatives-part2.pdf
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part2.pdf
rename to old_slides/08-applicatives-part2.pdf
diff --git a/sofp-src/old_slides/08-applicatives-part2.tex b/old_slides/08-applicatives-part2.tex
similarity index 100%
rename from sofp-src/old_slides/08-applicatives-part2.tex
rename to old_slides/08-applicatives-part2.tex
diff --git a/sofp-src/old_slides/09-traversables.lyx b/old_slides/09-traversables.lyx
similarity index 100%
rename from sofp-src/old_slides/09-traversables.lyx
rename to old_slides/09-traversables.lyx
diff --git a/sofp-src/old_slides/09-traversables.pdf b/old_slides/09-traversables.pdf
similarity index 100%
rename from sofp-src/old_slides/09-traversables.pdf
rename to old_slides/09-traversables.pdf
diff --git a/sofp-src/old_slides/09-traversables.tex b/old_slides/09-traversables.tex
similarity index 100%
rename from sofp-src/old_slides/09-traversables.tex
rename to old_slides/09-traversables.tex
diff --git a/sofp-src/old_slides/10-free-constructions.lyx b/old_slides/10-free-constructions.lyx
similarity index 100%
rename from sofp-src/old_slides/10-free-constructions.lyx
rename to old_slides/10-free-constructions.lyx
diff --git a/sofp-src/old_slides/10-free-constructions.pdf b/old_slides/10-free-constructions.pdf
similarity index 100%
rename from sofp-src/old_slides/10-free-constructions.pdf
rename to old_slides/10-free-constructions.pdf
diff --git a/sofp-src/old_slides/10-free-constructions.tex b/old_slides/10-free-constructions.tex
similarity index 100%
rename from sofp-src/old_slides/10-free-constructions.tex
rename to old_slides/10-free-constructions.tex
diff --git a/sofp-src/old_slides/11-monad-transformers.lyx b/old_slides/11-monad-transformers.lyx
similarity index 100%
rename from sofp-src/old_slides/11-monad-transformers.lyx
rename to old_slides/11-monad-transformers.lyx
diff --git a/sofp-src/old_slides/11-monad-transformers.pdf b/old_slides/11-monad-transformers.pdf
similarity index 100%
rename from sofp-src/old_slides/11-monad-transformers.pdf
rename to old_slides/11-monad-transformers.pdf
diff --git a/sofp-src/old_slides/11-monad-transformers.tex b/old_slides/11-monad-transformers.tex
similarity index 100%
rename from sofp-src/old_slides/11-monad-transformers.tex
rename to old_slides/11-monad-transformers.tex
diff --git a/sofp-src/old_slides/chapter01-intro.txt b/old_slides/chapter01-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter01-intro.txt
rename to old_slides/chapter01-intro.txt
diff --git a/sofp-src/old_slides/chapter02-intro.txt b/old_slides/chapter02-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter02-intro.txt
rename to old_slides/chapter02-intro.txt
diff --git a/sofp-src/old_slides/chapter03-part1-intro.txt b/old_slides/chapter03-part1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter03-part1-intro.txt
rename to old_slides/chapter03-part1-intro.txt
diff --git a/sofp-src/old_slides/chapter03-part2-intro.txt b/old_slides/chapter03-part2-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter03-part2-intro.txt
rename to old_slides/chapter03-part2-intro.txt
diff --git a/sofp-src/old_slides/chapter03-part3-intro.txt b/old_slides/chapter03-part3-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter03-part3-intro.txt
rename to old_slides/chapter03-part3-intro.txt
diff --git a/sofp-src/old_slides/chapter04-intro.txt b/old_slides/chapter04-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter04-intro.txt
rename to old_slides/chapter04-intro.txt
diff --git a/sofp-src/old_slides/chapter05-intro.txt b/old_slides/chapter05-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter05-intro.txt
rename to old_slides/chapter05-intro.txt
diff --git a/sofp-src/old_slides/chapter06-part1-intro.txt b/old_slides/chapter06-part1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter06-part1-intro.txt
rename to old_slides/chapter06-part1-intro.txt
diff --git a/sofp-src/old_slides/chapter06-part2-intro.txt b/old_slides/chapter06-part2-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter06-part2-intro.txt
rename to old_slides/chapter06-part2-intro.txt
diff --git a/sofp-src/old_slides/chapter07-part1-intro.txt b/old_slides/chapter07-part1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter07-part1-intro.txt
rename to old_slides/chapter07-part1-intro.txt
diff --git a/sofp-src/old_slides/chapter07-part2-intro.txt b/old_slides/chapter07-part2-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter07-part2-intro.txt
rename to old_slides/chapter07-part2-intro.txt
diff --git a/sofp-src/old_slides/chapter08-part1-intro.txt b/old_slides/chapter08-part1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter08-part1-intro.txt
rename to old_slides/chapter08-part1-intro.txt
diff --git a/sofp-src/old_slides/chapter08-part2-1-intro.txt b/old_slides/chapter08-part2-1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter08-part2-1-intro.txt
rename to old_slides/chapter08-part2-1-intro.txt
diff --git a/sofp-src/old_slides/chapter08-part2-2-intro.txt b/old_slides/chapter08-part2-2-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter08-part2-2-intro.txt
rename to old_slides/chapter08-part2-2-intro.txt
diff --git a/sofp-src/old_slides/chapter08-part2-3-intro.txt b/old_slides/chapter08-part2-3-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter08-part2-3-intro.txt
rename to old_slides/chapter08-part2-3-intro.txt
diff --git a/sofp-src/old_slides/chapter09-intro.txt b/old_slides/chapter09-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter09-intro.txt
rename to old_slides/chapter09-intro.txt
diff --git a/sofp-src/old_slides/chapter10-part1-intro.txt b/old_slides/chapter10-part1-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter10-part1-intro.txt
rename to old_slides/chapter10-part1-intro.txt
diff --git a/sofp-src/old_slides/chapter10-part2-intro.txt b/old_slides/chapter10-part2-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter10-part2-intro.txt
rename to old_slides/chapter10-part2-intro.txt
diff --git a/sofp-src/old_slides/chapter10-part3-intro.txt b/old_slides/chapter10-part3-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter10-part3-intro.txt
rename to old_slides/chapter10-part3-intro.txt
diff --git a/sofp-src/old_slides/chapter10-part4-intro.txt b/old_slides/chapter10-part4-intro.txt
similarity index 100%
rename from sofp-src/old_slides/chapter10-part4-intro.txt
rename to old_slides/chapter10-part4-intro.txt
diff --git a/sofp-src/old_slides/curryhoward-2017.lyx b/old_slides/curryhoward-2017.lyx
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2017.lyx
rename to old_slides/curryhoward-2017.lyx
diff --git a/sofp-src/old_slides/curryhoward-2017.pdf b/old_slides/curryhoward-2017.pdf
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2017.pdf
rename to old_slides/curryhoward-2017.pdf
diff --git a/sofp-src/old_slides/curryhoward-2017.tex b/old_slides/curryhoward-2017.tex
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2017.tex
rename to old_slides/curryhoward-2017.tex
diff --git a/sofp-src/old_slides/curryhoward-2018-haskell.lyx b/old_slides/curryhoward-2018-haskell.lyx
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-haskell.lyx
rename to old_slides/curryhoward-2018-haskell.lyx
diff --git a/sofp-src/old_slides/curryhoward-2018-haskell.pdf b/old_slides/curryhoward-2018-haskell.pdf
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-haskell.pdf
rename to old_slides/curryhoward-2018-haskell.pdf
diff --git a/sofp-src/old_slides/curryhoward-2018-haskell.tex b/old_slides/curryhoward-2018-haskell.tex
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-haskell.tex
rename to old_slides/curryhoward-2018-haskell.tex
diff --git a/sofp-src/old_slides/curryhoward-2018-sfttpl.lyx b/old_slides/curryhoward-2018-sfttpl.lyx
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-sfttpl.lyx
rename to old_slides/curryhoward-2018-sfttpl.lyx
diff --git a/sofp-src/old_slides/curryhoward-2018-sfttpl.pdf b/old_slides/curryhoward-2018-sfttpl.pdf
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-sfttpl.pdf
rename to old_slides/curryhoward-2018-sfttpl.pdf
diff --git a/sofp-src/old_slides/curryhoward-2018-sfttpl.tex b/old_slides/curryhoward-2018-sfttpl.tex
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-sfttpl.tex
rename to old_slides/curryhoward-2018-sfttpl.tex
diff --git a/sofp-src/old_slides/curryhoward-2018-tutorial-intro.txt b/old_slides/curryhoward-2018-tutorial-intro.txt
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-tutorial-intro.txt
rename to old_slides/curryhoward-2018-tutorial-intro.txt
diff --git a/sofp-src/old_slides/curryhoward-2018-tutorial.lyx b/old_slides/curryhoward-2018-tutorial.lyx
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-tutorial.lyx
rename to old_slides/curryhoward-2018-tutorial.lyx
diff --git a/sofp-src/old_slides/curryhoward-2018-tutorial.pdf b/old_slides/curryhoward-2018-tutorial.pdf
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-tutorial.pdf
rename to old_slides/curryhoward-2018-tutorial.pdf
diff --git a/sofp-src/old_slides/curryhoward-2018-tutorial.tex b/old_slides/curryhoward-2018-tutorial.tex
similarity index 100%
rename from sofp-src/old_slides/curryhoward-2018-tutorial.tex
rename to old_slides/curryhoward-2018-tutorial.tex
diff --git a/sofp-src/old_slides/curryhoward2017-intro.txt b/old_slides/curryhoward2017-intro.txt
similarity index 100%
rename from sofp-src/old_slides/curryhoward2017-intro.txt
rename to old_slides/curryhoward2017-intro.txt
diff --git a/sample100pages.pdf b/sample100pages.pdf
index e122a4699..6b47fe2fd 100644
Binary files a/sample100pages.pdf and b/sample100pages.pdf differ
diff --git a/sofp-src/README_build.md b/sofp-src/README_build.md
new file mode 100644
index 000000000..73006147f
--- /dev/null
+++ b/sofp-src/README_build.md
@@ -0,0 +1,38 @@
+# Source code
+
+The full source of the book is in the subdirectory `sofp-src/`.
+
+The subdirectories `cover` and `lyx` contain source files and are edited.
+
+The subdirectory `tex` contains generated TeX files.
+
+# Building a PDF version of the book from LyX sources
+
+If you want to build from source, currently you need `LyX` 2.3.x and `pdftk` installed.
+
+Change to the directory `sofp-src`.
+
+The command `bash make_sofp_pdf.sh` builds PDF files `sofp.pdf` and `sofp-10pt.pdf`.
+
+If this does not work, you can build manually with a simple command such as `lyx --export pdf sofp.lyx`,
+but the resulting PDF version will lack certain cosmetic features such as special colors and formatting.
+
+If you do not have `LyX`, you can build from the provided LaTeX sources using commands such as:
+
+```bash
+cd tex/
+pdflatex --interaction=batchmode sofp.tex
+makeindex sofp.idx
+pdflatex --interaction=batchmode sofp.tex
+```
+
+# Docker image for PDF builds
+
+A Docker image (containing a compatible version of LyX and LaTeX) is configured by the repository https://github.com/winitzki/sofp-docker-build
+and is automatically uploaded to Docker Hub at https://hub.docker.com/repository/docker/winitzki/sofp-docker-build/builds
+
+This Docker image is loaded by the file [build-pdf.yml](.github/workflows/build-pdf.yml#L31) in order to build the PDF version of the book.
+
+The latest build is uploaded to Github when a new git tag is pushed.
+This happens with each new release.
+Also, a PDF build is performed on every commit to master.
diff --git a/sofp-src/book_cover/cover-background-4.jpg b/sofp-src/book_cover/cover-background-4.jpg
deleted file mode 100644
index 355d23be2..000000000
Binary files a/sofp-src/book_cover/cover-background-4.jpg and /dev/null differ
diff --git a/sofp-src/book_cover/sofp-cover-parameters.tex b/sofp-src/book_cover/sofp-cover-parameters.tex
deleted file mode 100644
index df37b5846..000000000
--- a/sofp-src/book_cover/sofp-cover-parameters.tex
+++ /dev/null
@@ -1,74 +0,0 @@
-\usepackage{wallpaper}
-\usepackage{amsmath}
-\usepackage{mathpazo}
-\usepackage{helvet}
-\renewcommand{\ttdefault}{cmtt}
-\usepackage{newtxmath}
-\usepackage[T2A,T1]{fontenc}
-\usepackage[utf8]{inputenc}
-\usepackage{tipa}
-\usepackage{tipx}
-%% ----------------------------------------------------------------------------
-%% Book Parameters - Included in body and cover
-%% ----------------------------------------------------------------------------
-\usepackage{pgf}% Fancy math
-
-% Note that some printers require specific page count multiples:
-% -- Createspace: page count MUST be divisible by 2.
-% -- Ingram: page count MUST be divisible by 2.
-% -- Blurb : page count MUST be divisible by 6.
-% Add blank pages as needed in final PDF generations!
-\pgfmathsetmacro\TotalPageCount{1293}% Must be manually entered
-\pgfmathsetmacro\PaperWidthPt{7.444in}%
-\pgfmathsetmacro\PaperHeightPt{9.68in}%
-
-%% ----------------------------------------------------------------------------
-%% Computed parameters for cover and jacket design
-
-% CreateSpace and Ingram, use different paper stock so the spine width must
-% be adjusted to refect that.
-% For example Createspace, White paper: multiply page count by 0.002252
-%
-% Use Createspace parameters for Lulu.com
-\pgfmathsetmacro\SinglePageThicknessPt{0.002252in}% Createspace, White B&W Paper
-%\pgfmathsetmacro\SinglePageThicknessPt{0.002143in}% Blurb, Standard and Economy B&W Paper
-%\pgfmathsetmacro\SinglePageThicknessPt{0.002602in}% Blurb, Standard and Economy Color Paper
-%\pgfmathsetmacro\SinglePageThicknessPt{0.002110in}% Ingram, Standard White B&W Paper (50lb)
-%\pgfmathsetmacro\SinglePageThicknessPt{0.002110in}% Ingram, Standard Color Paper (50lb)
-%\pgfmathsetmacro\SinglePageThicknessPt{0.002720in}% Ingram, Premium Color Paper (70lb)
-
-\pgfmathsetmacro\HorBleedPt{0.125in}%
-\pgfmathsetmacro\VerBleedPt{0.125in}%
-\pgfmathsetmacro\FoldVariancePt{0.0625in}%
-
-%% Every book will vary slightly when bound. Allow for 0.0625" variance on either
-%% side of the fold lines for your cover. For example, if your spine width is 1",
-%% your text should be no wider than 0.875". Because of this variance, avoid hard
-%% edges or lines that end on the fold line.
-
-%% Cover Width calculation at 6" x 9" cover with 60 B&W pages on white paper:
-%% 0.125" + 6" + (60 * 0.002252)" + 6" + .125" = 12.385"
-%% Cover Height calculation: 6" x 9": 0.125" + 9" + .125" = 9.25"
-
-\pgfmathsetmacro\SpineWidthPt{\SinglePageThicknessPt*\TotalPageCount}%
-\pgfmathsetmacro\CoverWidthPt{\PaperWidthPt+\HorBleedPt}%
-\pgfmathsetmacro\JacketWidthPt{\CoverWidthPt+\SpineWidthPt+\CoverWidthPt}%
-\pgfmathsetmacro\CoverHeightPt{\VerBleedPt+\PaperHeightPt+\VerBleedPt}%
-
-\pgfmathsetmacro\PtsPerInch{72.27}% Slightly more than 72 - odd.
-
-\pgfmathsetmacro\SpineWidth{\SpineWidthPt / \PtsPerInch}%
-\pgfmathsetmacro\PaperWidth{\PaperWidthPt / \PtsPerInch}%
-\pgfmathsetmacro\CoverWidth{\CoverWidthPt / \PtsPerInch}%
-\pgfmathsetmacro\JacketWidth{\JacketWidthPt / \PtsPerInch}%
-
-\pgfmathsetmacro\PaperHeight{\PaperHeightPt / \PtsPerInch}%
-\pgfmathsetmacro\CoverHeight{\CoverHeightPt / \PtsPerInch}%
-
-\pgfmathsetmacro\HorBleed{\HorBleedPt / \PtsPerInch}%
-\pgfmathsetmacro\VerBleed{\VerBleedPt / \PtsPerInch}%
-\pgfmathsetmacro\FoldVariance{\FoldVariancePt/ \PtsPerInch}%
-
-%% ----------------------------------------------------------------------------
-%% End of Book Parameters.
-%% ----------------------------------------------------------------------------
diff --git a/sofp-src/book_cover/sofp-make-cover.sh b/sofp-src/book_cover/sofp-make-cover.sh
deleted file mode 100644
index fcd8fd6cd..000000000
--- a/sofp-src/book_cover/sofp-make-cover.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-# Prepare the three cover pages in parallel.
-(
-for f in sofp-spine sofp-back-cover sofp-front-cover; do
-pdflatex --interaction=batchmode "$f" &
-done
-wait # Wait until all 3 cover pages are done.
-pdflatex --interaction=batchmode sofp-3page-cover
-) >& /dev/null
diff --git a/sofp-src/chapter3-figure-make-pdf.sh b/sofp-src/chapter3-figure-make-pdf.sh
deleted file mode 100644
index 7c26ee567..000000000
--- a/sofp-src/chapter3-figure-make-pdf.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-latex chapter3-picture.tex
-dvips chapter3-picture.dvi
-ps2pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true chapter3-picture.ps
-rm -f chapter3-picture.{aux,dvi,log,ps}
-
diff --git a/sofp-src/chapter3-picture.pdf b/sofp-src/chapter3-picture.pdf
deleted file mode 100644
index 3f24f3191..000000000
Binary files a/sofp-src/chapter3-picture.pdf and /dev/null differ
diff --git a/sofp-src/book_cover/cover-background-2.jpg b/sofp-src/cover/cover-background-2.jpg
similarity index 100%
rename from sofp-src/book_cover/cover-background-2.jpg
rename to sofp-src/cover/cover-background-2.jpg
diff --git a/sofp-src/book_cover/cover-background.jpg b/sofp-src/cover/cover-background.jpg
similarity index 100%
rename from sofp-src/book_cover/cover-background.jpg
rename to sofp-src/cover/cover-background.jpg
diff --git a/sofp-src/book_cover/monads_evil_face.jpg b/sofp-src/cover/monads_evil_face.jpg
similarity index 100%
rename from sofp-src/book_cover/monads_evil_face.jpg
rename to sofp-src/cover/monads_evil_face.jpg
diff --git a/sofp-src/book_cover/sofp-3page-cover.tex b/sofp-src/cover/sofp-3page-cover.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-3page-cover.tex
rename to sofp-src/cover/sofp-3page-cover.tex
diff --git a/sofp-src/book_cover/sofp-back-cover-page.tex b/sofp-src/cover/sofp-back-cover-for-main-pdf.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-back-cover-page.tex
rename to sofp-src/cover/sofp-back-cover-for-main-pdf.tex
diff --git a/sofp-src/book_cover/sofp-back-cover-no-bg.tex.src b/sofp-src/cover/sofp-back-cover-no-bg.tex.src
similarity index 100%
rename from sofp-src/book_cover/sofp-back-cover-no-bg.tex.src
rename to sofp-src/cover/sofp-back-cover-no-bg.tex.src
diff --git a/sofp-src/book_cover/sofp-back-cover.tex b/sofp-src/cover/sofp-back-cover.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-back-cover.tex
rename to sofp-src/cover/sofp-back-cover.tex
diff --git a/sofp-src/book_cover/sofp-cover-page.tex b/sofp-src/cover/sofp-cover-for-main-pdf.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-cover-page.tex
rename to sofp-src/cover/sofp-cover-for-main-pdf.tex
diff --git a/sofp-src/book_cover/sofp-cover-page-no-bg.tex b/sofp-src/cover/sofp-cover-page-no-bg.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-cover-page-no-bg.tex
rename to sofp-src/cover/sofp-cover-page-no-bg.tex
diff --git a/sofp-src/book_cover/sofp-cover-parameters.tex.src b/sofp-src/cover/sofp-cover-parameters.tex.src
similarity index 100%
rename from sofp-src/book_cover/sofp-cover-parameters.tex.src
rename to sofp-src/cover/sofp-cover-parameters.tex.src
diff --git a/sofp-src/book_cover/sofp-front-cover.tex b/sofp-src/cover/sofp-front-cover.tex
similarity index 95%
rename from sofp-src/book_cover/sofp-front-cover.tex
rename to sofp-src/cover/sofp-front-cover.tex
index ecdac24ab..2715e5d69 100644
--- a/sofp-src/book_cover/sofp-front-cover.tex
+++ b/sofp-src/cover/sofp-front-cover.tex
@@ -27,6 +27,6 @@
%% No header nor footer on the cover
\thispagestyle{empty}
-\input{../sofp-cover-page-no-bg}
+\input{sofp-cover-page-no-bg}
\end{document}
diff --git a/sofp-src/book_cover/sofp-spine.tex b/sofp-src/cover/sofp-spine.tex
similarity index 100%
rename from sofp-src/book_cover/sofp-spine.tex
rename to sofp-src/cover/sofp-spine.tex
diff --git a/sofp-src/book_cover/vol1_isbn_barcode.pdf b/sofp-src/cover/vol1_isbn_barcode.pdf
similarity index 100%
rename from sofp-src/book_cover/vol1_isbn_barcode.pdf
rename to sofp-src/cover/vol1_isbn_barcode.pdf
diff --git a/sofp-src/book_cover/vol2_isbn_barcode.pdf b/sofp-src/cover/vol2_isbn_barcode.pdf
similarity index 100%
rename from sofp-src/book_cover/vol2_isbn_barcode.pdf
rename to sofp-src/cover/vol2_isbn_barcode.pdf
diff --git a/sofp-src/book_cover/vol3_isbn_barcode.pdf b/sofp-src/cover/vol3_isbn_barcode.pdf
similarity index 100%
rename from sofp-src/book_cover/vol3_isbn_barcode.pdf
rename to sofp-src/cover/vol3_isbn_barcode.pdf
diff --git a/sofp-src/chapter3-picture.tex b/sofp-src/lyx/chapter3-picture.tex
similarity index 100%
rename from sofp-src/chapter3-picture.tex
rename to sofp-src/lyx/chapter3-picture.tex
diff --git a/sofp-src/ftt-example.jpg b/sofp-src/lyx/ftt-example.jpg
similarity index 100%
rename from sofp-src/ftt-example.jpg
rename to sofp-src/lyx/ftt-example.jpg
diff --git a/sofp-src/lyx/monads_evil_face.jpg b/sofp-src/lyx/monads_evil_face.jpg
new file mode 100644
index 000000000..992c6e965
Binary files /dev/null and b/sofp-src/lyx/monads_evil_face.jpg differ
diff --git a/sofp-src/no-bugs.jpg b/sofp-src/lyx/no-bugs.jpg
similarity index 100%
rename from sofp-src/no-bugs.jpg
rename to sofp-src/lyx/no-bugs.jpg
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-fpis-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpis-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpis-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpmortals-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpmortals-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-fpsimplified-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-fpsimplified-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-hefferon-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-hefferon-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-hefferon-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-kalinin-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kalinin-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-kalinin-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-kibble-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-kibble-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-kibble-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-pdbc-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-pdbc-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-pdbc-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-sofp-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-sofp-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-sofp-pdf-09.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-00.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-00.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-00.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-00.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-01.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-01.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-01.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-01.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-02.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-02.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-02.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-02.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-03.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-03.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-03.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-03.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-04.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-04.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-04.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-04.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-05.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-05.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-05.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-05.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-06.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-06.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-06.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-06.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-07.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-07.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-07.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-07.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-08.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-08.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-08.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-08.png
diff --git a/sofp-src/random-pages/random-pages-from-volpe-pdf-09.png b/sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-09.png
similarity index 100%
rename from sofp-src/random-pages/random-pages-from-volpe-pdf-09.png
rename to sofp-src/lyx/random-pages/random-pages-from-volpe-pdf-09.png
diff --git a/sofp-src/sofp-appendices.lyx b/sofp-src/lyx/sofp-appendices.lyx
similarity index 100%
rename from sofp-src/sofp-appendices.lyx
rename to sofp-src/lyx/sofp-appendices.lyx
diff --git a/sofp-src/sofp-applicative.lyx b/sofp-src/lyx/sofp-applicative.lyx
similarity index 100%
rename from sofp-src/sofp-applicative.lyx
rename to sofp-src/lyx/sofp-applicative.lyx
diff --git a/sofp-src/sofp-curry-howard.lyx b/sofp-src/lyx/sofp-curry-howard.lyx
similarity index 100%
rename from sofp-src/sofp-curry-howard.lyx
rename to sofp-src/lyx/sofp-curry-howard.lyx
diff --git a/sofp-src/sofp-disjunctions.lyx b/sofp-src/lyx/sofp-disjunctions.lyx
similarity index 100%
rename from sofp-src/sofp-disjunctions.lyx
rename to sofp-src/lyx/sofp-disjunctions.lyx
diff --git a/sofp-src/sofp-essay1.lyx b/sofp-src/lyx/sofp-essay1.lyx
similarity index 100%
rename from sofp-src/sofp-essay1.lyx
rename to sofp-src/lyx/sofp-essay1.lyx
diff --git a/sofp-src/sofp-essay2.lyx b/sofp-src/lyx/sofp-essay2.lyx
similarity index 100%
rename from sofp-src/sofp-essay2.lyx
rename to sofp-src/lyx/sofp-essay2.lyx
diff --git a/sofp-src/sofp-essay3.lyx b/sofp-src/lyx/sofp-essay3.lyx
similarity index 100%
rename from sofp-src/sofp-essay3.lyx
rename to sofp-src/lyx/sofp-essay3.lyx
diff --git a/sofp-src/sofp-filterable.lyx b/sofp-src/lyx/sofp-filterable.lyx
similarity index 100%
rename from sofp-src/sofp-filterable.lyx
rename to sofp-src/lyx/sofp-filterable.lyx
diff --git a/sofp-src/sofp-free-type.lyx b/sofp-src/lyx/sofp-free-type.lyx
similarity index 100%
rename from sofp-src/sofp-free-type.lyx
rename to sofp-src/lyx/sofp-free-type.lyx
diff --git a/sofp-src/sofp-functors.lyx b/sofp-src/lyx/sofp-functors.lyx
similarity index 100%
rename from sofp-src/sofp-functors.lyx
rename to sofp-src/lyx/sofp-functors.lyx
diff --git a/sofp-src/sofp-higher-order-functions.lyx b/sofp-src/lyx/sofp-higher-order-functions.lyx
similarity index 100%
rename from sofp-src/sofp-higher-order-functions.lyx
rename to sofp-src/lyx/sofp-higher-order-functions.lyx
diff --git a/sofp-src/sofp-induction.lyx b/sofp-src/lyx/sofp-induction.lyx
similarity index 100%
rename from sofp-src/sofp-induction.lyx
rename to sofp-src/lyx/sofp-induction.lyx
diff --git a/sofp-src/sofp-monads.lyx b/sofp-src/lyx/sofp-monads.lyx
similarity index 100%
rename from sofp-src/sofp-monads.lyx
rename to sofp-src/lyx/sofp-monads.lyx
diff --git a/sofp-src/sofp-nameless-functions.lyx b/sofp-src/lyx/sofp-nameless-functions.lyx
similarity index 100%
rename from sofp-src/sofp-nameless-functions.lyx
rename to sofp-src/lyx/sofp-nameless-functions.lyx
diff --git a/sofp-src/sofp-preface.lyx b/sofp-src/lyx/sofp-preface.lyx
similarity index 100%
rename from sofp-src/sofp-preface.lyx
rename to sofp-src/lyx/sofp-preface.lyx
diff --git a/sofp-src/sofp-reasoning.lyx b/sofp-src/lyx/sofp-reasoning.lyx
similarity index 100%
rename from sofp-src/sofp-reasoning.lyx
rename to sofp-src/lyx/sofp-reasoning.lyx
diff --git a/sofp-src/sofp-summary.lyx b/sofp-src/lyx/sofp-summary.lyx
similarity index 100%
rename from sofp-src/sofp-summary.lyx
rename to sofp-src/lyx/sofp-summary.lyx
diff --git a/sofp-src/sofp-transformers.lyx b/sofp-src/lyx/sofp-transformers.lyx
similarity index 99%
rename from sofp-src/sofp-transformers.lyx
rename to sofp-src/lyx/sofp-transformers.lyx
index 73db38bb9..d805bb961 100644
--- a/sofp-src/sofp-transformers.lyx
+++ b/sofp-src/lyx/sofp-transformers.lyx
@@ -23340,10 +23340,6 @@ inner interchange
\end_inset
is written as:
-\end_layout
-
-\begin_layout Standard
-\noindent
\begin_inset Formula
\[
\xymatrix{\xyScaleY{0.8pc}\xyScaleX{2.5pc} & M^{L^{L^{A}}}\ar[r]\sb(0.5){\text{ftn}_{L}^{\uparrow M}}\ar[ld]\sb(0.45){\text{sw}} & M^{L^{A}}\ar[d]\sb(0.45){\text{sw}}\\
diff --git a/sofp-src/sofp-traversable.lyx b/sofp-src/lyx/sofp-traversable.lyx
similarity index 100%
rename from sofp-src/sofp-traversable.lyx
rename to sofp-src/lyx/sofp-traversable.lyx
diff --git a/sofp-src/sofp-typeclasses.lyx b/sofp-src/lyx/sofp-typeclasses.lyx
similarity index 100%
rename from sofp-src/sofp-typeclasses.lyx
rename to sofp-src/lyx/sofp-typeclasses.lyx
diff --git a/sofp-src/sofp.lyx b/sofp-src/lyx/sofp.lyx
similarity index 99%
rename from sofp-src/sofp.lyx
rename to sofp-src/lyx/sofp.lyx
index 16a7c4d62..197d6b757 100644
--- a/sofp-src/sofp.lyx
+++ b/sofp-src/lyx/sofp.lyx
@@ -217,7 +217,7 @@
\output_sync 0
\bibtex_command default
\index_command makeindex
-\paperfontsize 12
+\paperfontsize 10
\spacing single
\use_hyperref true
\pdf_title "The Science of Functional Programming: A Tutorial, with Examples in Scala"
@@ -297,7 +297,7 @@ status open
\backslash
-input{sofp-cover-page}
+input{sofp-cover-for-main-pdf}
\end_layout
\end_inset
@@ -1018,7 +1018,7 @@ status open
\backslash
-input{sofp-back-cover-page}
+input{sofp-back-cover-for-main-pdf}
\end_layout
\end_inset
diff --git a/sofp-src/type-error.jpg b/sofp-src/lyx/type-error.jpg
similarity index 100%
rename from sofp-src/type-error.jpg
rename to sofp-src/lyx/type-error.jpg
diff --git a/sofp-src/user.bind b/sofp-src/lyx/user.bind
similarity index 95%
rename from sofp-src/user.bind
rename to sofp-src/lyx/user.bind
index 2cbb26375..dcb9143ca 100644
--- a/sofp-src/user.bind
+++ b/sofp-src/lyx/user.bind
@@ -43,6 +43,7 @@ Format 4
\bind "M-i 0" "command-sequence self-insert 0; char-left; math-insert \\bbnum"
\bind "M-i 1" "command-sequence self-insert 1; char-left; math-insert \\bbnum"
\bind "M-i w" "dialog-show-new-inset vspace"
+\bind "M-i y" "math-insert \\updownarrow"
\bind "C-equal" "math-insert \\Rightarrow"
\bind "C-S-c" "dialog-show character"
\bind "C-S-p" "dialog-show paragraph"
@@ -67,4 +68,6 @@ Format 4
\bind "C-S-backslash" "math-delim | |"
\bind "M-Up" "math-superscript"
\bind "M-Down" "math-subscript"
+\bind "C-S-equal" "math-insert \\leftrightarrow"
+\bind "C-S-comma" "math-delim < >"
diff --git a/sofp-src/make_sofp_pdf.sh b/sofp-src/make_sofp_pdf.sh
index ada9e45b8..a03653e7f 100644
--- a/sofp-src/make_sofp_pdf.sh
+++ b/sofp-src/make_sofp_pdf.sh
@@ -1,237 +1,2 @@
-#!/bin/bash
-
-# Requires pdftk and lyx.
-# Get lyx from www.lyx.org
-# For Mac, get pdftk from https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk_server-2.02-mac_osx-10.11-setup.pkg or else it may not work
-# For Windows, get pdftk from https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk_free-2.02-win-setup.exe
-
-name="sofp"
-
-draft="$name-draft"
-srcbase="sofp-src"
-
-export GS_OPTIONS="-dEmbedAllFonts=true -dPDFSETTINGS=/printer"
-
-# Set custom lyx directory if needed.
-if [ x"$LYXDIR" == x ]; then
- lyxdir=""
-else
- lyxdir="-userdir $LYXDIR"
-fi
-
-test -d $srcbase && cd $srcbase
-
-function git_commit_hash {
- git rev-parse HEAD # Do not use --short here.
-}
-
-function source_hash {
- cat $0 $name*.lyx | shasum -a 256 | cut -c 1-64
-}
-
-# Make a PDF package with embedded source archive.
-
-# This function is not used now.
-function run_latex_many_times {
- local base="$1"
- echo "LaTeX Warning - Rerun" > "$base.log"
- while grep -q '\(LaTeX Warning.*Rerun\|^(rerunfilecheck).*Rerun\)' "$base.log"; do
- latex --interaction=batchmode "$base.tex"
- done # This used to be only pdflatex but now we are using ps2pdf because of pstricks.
-}
-
-# Not used now, since we are using pdflatex.
-function make_pdf_with_index_via_ps2pdf {
- local base="$1" fast="$2"
- if [[ -z "$fast" ]]; then
- run_latex_many_times "$base"
- makeindex "$base.idx"
- fi
- run_latex_many_times "$base"
- (dvips "$base.dvi" >& $base.log1; cat $base.log1 >> $base.log; rm $base.log1) >& /dev/null
- (ps2pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true "$base.ps") 2>&1 >> $base.log
-}
-
-function make_pdf_with_index {
- local base="$1" fast="$2"
- if [ x"$fast" == x ]; then
- pdflatex --interaction=batchmode "$base"
- makeindex "$base.idx"
- fi
- pdflatex --interaction=batchmode "$base"
-}
-
-function add_color {
- local texsrc="$1"
- # Insert color comments into displayed equation arrays. Also, in some places the green color was inserted; replace by `greenunder`.
- # Example of inserted color: {\color{greenunder}\text{outer-interchange law for }M:}\quad &
- LC_ALL=C sed -i.bak -e 's|\\color{green}|\\color{greenunder}|; s|^\(.*\\text{[^}]*}.*:\)\( *\\quad \& \)|{\\color{greenunder}\1}\2|; s|\(\& *\\quad\)\(.*\\text{[^}]*}.*: *\)\(\\quad\\\\\)$|\1{\\color{greenunder}\2}\3|' "$texsrc"
- # Insert color background into all displayed equations. This is disabled because it does not always produce visually good results.
- if false; then
- LC_ALL=C sed -i.bak -E -e ' s!\\begin\{(align.?|equation)\}!\\begin{empheq}[box=\\mymathbgbox]{\1}!; s!\\end\{(align.?|equation)\}!\\end{empheq}!; ' "$texsrc"
- LC_ALL=C sed -i.bak -E -e ' s!^\\\[$!\\begin{empheq}[box=\\mymathbgbox]{equation*}!; s!^\\\]$!\\end{empheq}!; ' "$texsrc"
- fi
-}
-
-function add_source_hashes {
- gitcommit=`git_commit_hash`
- sourcehash=`source_hash`
- echo $sourcehash > $name.source_hash1
- LC_ALL=C sed -i.bak -E -e "s/INSERTSOURCEHASH/$sourcehash/; s/INSERTGITCOMMIT/$gitcommit/" $name.tex
- mv $name.source_hash1 $name.source_hash
-}
-
-function insert_examples_exercises_count { # This is replaced in the root file only.
- local base="$1" target="$2"
- local exercises=`cat "$base"-*.tex | LC_ALL=C fgrep -c '\subsubsection{Exercise '`
- local examples=`cat "$base"-*.tex | LC_ALL=C fgrep -c '\subsubsection{Example '`
- local codesnippets=`cat "$base"-*.tex | LC_ALL=C fgrep -c '\begin{lstlisting}'`
- local stmts=`cat "$base"-*.tex | LC_ALL=C fgrep -c '\subsubsection{Statement '`
- local diagrams=`cat "$base"-*.tex | LC_ALL=C fgrep -c '\xymatrix{'`
- local bdate=`date -R`
- local osinfo=`uname -s`
- local pdftex=`pdflatex --version | fgrep pdfTeX\ 3.14`
- LC_ALL=C sed -i.bak -e "s|PDFTEXVERSION|$pdftex|g; s|BUILDDATE|$bdate|g; s|BUILDOPERATINGSYSTEM|$osinfo|g; s,NUMBEROFEXAMPLES,$examples,g; s,NUMBEROFEXERCISES,$exercises,g; s,NUMBEROFDIAGRAMS,$diagrams,g; s,NUMBEROFSTATEMENTS,$stmts,g; s,NUMBEROFCODESNIPPETS,$codesnippets,g;" "$target"
-}
-
-function remove_lulu {
- local base="$1"
- LC_ALL=C sed -i.bak -e 's,^\(.publishers{Published by\),%\1,; s,^\(Published by\),%\1,; s,^\(ISBN:\),%\1,' "$base".tex
-}
-
-function add_lulu {
- local base="$1"
- LC_ALL=C sed -i.bak -e 's,^%\(.publishers{Published by \),\1,; s,^%\(Published by \),\1,; s,^%\(ISBN:\),\1,' "$base".tex
-}
-
-function assemble_sources {
- # Include graphics files referenced as images.
- cp ../README.md README_build.md
- tar jcvf "$name-src.tar.bz2" README*.md excluded_words $name*lyx $name*tex `grep -o 'includegraphics[^}]*}' $name*tex | sed -e 's,[^{]*{\([^}]*\)}.*,\1.*,' |while read f; do ls $f ; done` *.sh >& /dev/null
-}
-
-# This requires pdftk to be installed on the path. Edit the next line as needed.
-pdftk=`which pdftk`
-
-# LyX needs to be installed for this to work. Edit the next line as needed.
-lyx=`which lyx`
-
-echo "Info: Using pdftk from '$pdftk' and lyx from '$lyx', lyx directory $lyxdir"
-
-rm -f $name*tex $name*log $name*ilg $name*idx $name*toc $name.pdf
-
-echo "Exporting LyX files $name.lyx and its child documents into LaTeX..."
-"$lyx" $lyxdir -f all --export pdflatex $name.lyx # Exports LaTeX for all child documents as well.
-
-#### The LaTeX files are heavily post-processed after exporting from LyX.
-
-echo "Post-processing LaTeX files..."
-
-# Insert the number of examples and exercises. This replacement is only for the root file.
-insert_examples_exercises_count $name $name.tex
-
-## Remove mathpazo. This was a mistake: should not remove it.
-#LC_ALL=C sed -i.bak -e 's/^.*usepackage.*mathpazo.*$//' $name.tex
-
-# Replace ugly Palatino quote marks and apostrophes by sans-serif marks.
-LC_ALL=C sed -i.bak -e " s|'s|\\\\textsf{'}s|g; s|O'|O\\\\textsf{'}|g; s|s'|s\\\\textsf{'}|g; "' s|``|\\textsf{``}|g; s|“|\\textsf{``}|g; '" s|''|\\\\textsf{''}|g; s|”|\\\\textsf{''}|g; s|\\\\textsf{'}'|\\\\textsf{''}|g; " $name*.tex
-
-# Add color to equation displays.
-for f in $name*tex; do add_color "$f"; done
-
-# Export Scala code snippets.
-rm -rf mdoc; mkdir mdoc
-for f in $name-*tex; do g=`basename "$f" .tex`; cat $g.pre.md <(perl extract_scala_snippets.pl < $f) > mdoc/$g.md; done
-
-# Remove control annotations for Scala code snippets.
-LC_ALL=C sed -i.bak -e " s| *//IGNORETHIS.*||" $name*.tex
-
-# Preparing source files for the book cover.
-
-for f in sofp-back-cover-no-bg sofp-cover-parameters; do cp book_cover/$f.tex.src book_cover/$f.tex; done
-insert_examples_exercises_count $name book_cover/sofp-back-cover-no-bg.tex
-for f in sofp-cover-page-no-bg.tex sofp-cover-page.tex sofp-back-cover.tex sofp-back-cover-page.tex sofp-back-cover-no-bg.tex cover-background.jpg cover-background-2.jpg monads_evil_face.jpg; do cp book_cover/"$f" .; done
-
-# Check whether the sources have changed. If so, create a new sources archive and a new PDF file.
-add_source_hashes $name.tex
-
-# Prepare "$name-src.tar.bz2" with all sources.
-assemble_sources &
-
-echo "Creating a full PDF file..."
-
-# Output is $name.pdf, main file is $name.tex, and other .tex files are \include'd.
-make_pdf_with_index "$name" >& /dev/null
-
-# Wait until assemble_sources is finished.
-wait
-
- if ! test -s "$name".pdf; then
- echo Output file "$name".pdf not found, exiting.
- exit 1
- fi
-
-# Do not attach sources to the main PDF file.
-#"$pdftk" "$name.pdf" attach_files "$name-src.tar.bz2" output "1$name.pdf"
-#mv "1$name.pdf" "$name.pdf"
-
-# Cleanup.
-( tar jcf "$name-logs.tar.bz2" $name*log $name*ilg $name*idx $name*toc
- echo "Log files are found in $name-logs.tar.bz2"
-) &
-
-function kbSize {
- local file="$1"
- ls -l -n "$file"|sed -e 's/ */ /g'|cut -f5 -d ' '
-}
-
-function pdfPages {
- local file="$1"
- "$pdftk" "$file" dump_data | fgrep NumberOfPages | sed -e 's,^.* ,,'
-}
-
-total_pages=`pdfPages "$name".pdf`
-
-echo Result is "$name.pdf", size `kbSize "$name.pdf"` bytes, with $total_pages pages.
-
-bash prepare_10point.sh "$pdftk" &
-
-bash prepare_volume.sh 1 "$pdftk" &
-bash prepare_volume.sh 2 "$pdftk" &
-bash prepare_volume.sh 3 "$pdftk" &
-
-bash spelling_check.sh &
-
-# Create the "clean draft" pdf file by selecting the chapters that have been proofread.
-# Check page counts in the draft file and in individual chapters.
-#bash check_and_make_draft.sh
-#draft_pages=`pdfPages "$draft".pdf`
-bash check-consistent-labels.sh
-bash check-lines_with_displaymath_in_new_paragraph.sh
-bash check-punctuation-before-code-blocks.sh
-
-if [ x"$1" == x-nolulu ]; then
- # Create a pdf file without references to lulu.com and without lulu.com's ISBN.
- mv "$name".pdf "$name"-lulu.pdf
- remove_lulu $name
- make_pdf_with_index "$name" fast >& /dev/null
- create_draft $name $draft-nolulu.pdf
-
- # The main file "$name".pdf has lulu.com information.
- mv "$name"-lulu.pdf "$name".pdf
-fi
-
-# Prepare an entire PDF file without hyperlinks.
-#if [ x"$1" == x-print ]; then
-# bash remove_hyperlinks.sh $name
-#fi
-
-
-# Prepare the full 3-page book covers. Use $total_pages of the whole pdf file and not $draft_pages since the printed file has all unedited content as well.
-bash prepare_cover.sh "$name.pdf" "$pdftk" &
-
-# Cleanup?
-#rm -f $name*{idx,ind,aux,dvi,ilg,out,toc,log,ps,lof,lot,data}
-
-# Wait for background jobs.
-wait
+test -d sofp-src && cd sofp-src
+bash scripts/make_all.sh
diff --git a/sofp-src/prepare_10point.sh b/sofp-src/prepare_10point.sh
deleted file mode 100644
index a6bec7032..000000000
--- a/sofp-src/prepare_10point.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-pdftk=$1
-
-dir=12pt
-
-rm -rf $dir
-mkdir -p $dir/book_cover
-cd $dir
-
-tar jxf ../sofp-src.tar.bz2
-mv sofp-src/* .
-
-cp ../sofp*.tex ../sofp.* .
-cp ../book_cover/* ./book_cover/
-
-cp book_cover/* .
-
-cp book_cover/sofp-cover-parameters.tex.src book_cover/sofp-cover-parameters.tex
-echo "Preparing PDF with 10 point font."
-# Set 10pt font.
-LC_ALL=C sed -i.bak -e 's|fontsize=12pt|fontsize=10pt|' sofp.tex
-
-(
-pdflatex --interaction=batchmode sofp
-makeindex sofp.idx
-
-pdflatex --interaction=batchmode sofp
-) >& /dev/null
-mv sofp.pdf ../sofp-10pt.pdf
-echo "sofp-10pt.pdf prepared"
diff --git a/sofp-src/prepare_cover.sh b/sofp-src/prepare_cover.sh
deleted file mode 100644
index 2a4aede2d..000000000
--- a/sofp-src/prepare_cover.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-# Prepare the printable PDF file of volume v of the book. v = 1, 2, 3.
-
-pdffile="$1"
-pdftk="$2"
-
-function pdfPages {
- local file="$1"
- "$pdftk" "$file" dump_data | fgrep NumberOfPages | sed -e 's,^.* ,,'
-}
-
-export LC_ALL=C
-
-total_pages=`pdfPages "$pdffile"`
-
-cd book_cover
-
-sed -i.bak -e "s|TOTALPAGES|$total_pages|" sofp-cover-parameters.tex
-
-bash sofp-make-cover.sh
diff --git a/sofp-src/random-pages/random-pages-from-fpis.pdf b/sofp-src/random-pages/random-pages-from-fpis.pdf
deleted file mode 100644
index 1dbcb0af8..000000000
Binary files a/sofp-src/random-pages/random-pages-from-fpis.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-fpmortals.pdf b/sofp-src/random-pages/random-pages-from-fpmortals.pdf
deleted file mode 100644
index 6b37ac940..000000000
Binary files a/sofp-src/random-pages/random-pages-from-fpmortals.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-fpsimplified.pdf b/sofp-src/random-pages/random-pages-from-fpsimplified.pdf
deleted file mode 100644
index 53c9e5b29..000000000
Binary files a/sofp-src/random-pages/random-pages-from-fpsimplified.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-hefferon.pdf b/sofp-src/random-pages/random-pages-from-hefferon.pdf
deleted file mode 100644
index 7e5b39afa..000000000
Binary files a/sofp-src/random-pages/random-pages-from-hefferon.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-kalinin.pdf b/sofp-src/random-pages/random-pages-from-kalinin.pdf
deleted file mode 100644
index 6338c084b..000000000
Binary files a/sofp-src/random-pages/random-pages-from-kalinin.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-kibble.pdf b/sofp-src/random-pages/random-pages-from-kibble.pdf
deleted file mode 100644
index 408deead7..000000000
Binary files a/sofp-src/random-pages/random-pages-from-kibble.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-pdbc.pdf b/sofp-src/random-pages/random-pages-from-pdbc.pdf
deleted file mode 100644
index b122d9cae..000000000
Binary files a/sofp-src/random-pages/random-pages-from-pdbc.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-sofp.pdf b/sofp-src/random-pages/random-pages-from-sofp.pdf
deleted file mode 100644
index 3c81ee5ad..000000000
Binary files a/sofp-src/random-pages/random-pages-from-sofp.pdf and /dev/null differ
diff --git a/sofp-src/random-pages/random-pages-from-volpe.pdf b/sofp-src/random-pages/random-pages-from-volpe.pdf
deleted file mode 100644
index 7be0c1fdd..000000000
Binary files a/sofp-src/random-pages/random-pages-from-volpe.pdf and /dev/null differ
diff --git a/sofp-src/scripts/chapter3-figure-make-pdf.sh b/sofp-src/scripts/chapter3-figure-make-pdf.sh
new file mode 100644
index 000000000..e892861f6
--- /dev/null
+++ b/sofp-src/scripts/chapter3-figure-make-pdf.sh
@@ -0,0 +1,10 @@
+# This script runs in a tex/ source directory.
+
+# Input: chapter3-picture.tex
+# Output: chapter3-picture.pdf
+logfile="../build/chapter3-picture-build.log"
+latex chapter3-picture.tex >& "$logfile"
+dvips chapter3-picture.dvi >& "$logfile"
+ps2pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true chapter3-picture.ps >& "$logfile"
+mv chapter3-picture.log ../build/
+rm -f chapter3-picture.{tex,aux,dvi,ps}
diff --git a/sofp-src/check-consistent-labels.sh b/sofp-src/scripts/check-consistent-labels.sh
similarity index 100%
rename from sofp-src/check-consistent-labels.sh
rename to sofp-src/scripts/check-consistent-labels.sh
diff --git a/sofp-src/check-lines_with_displaymath_in_new_paragraph.sh b/sofp-src/scripts/check-lines_with_displaymath_in_new_paragraph.sh
similarity index 100%
rename from sofp-src/check-lines_with_displaymath_in_new_paragraph.sh
rename to sofp-src/scripts/check-lines_with_displaymath_in_new_paragraph.sh
diff --git a/sofp-src/check-punctuation-before-code-blocks.sh b/sofp-src/scripts/check-punctuation-before-code-blocks.sh
similarity index 90%
rename from sofp-src/check-punctuation-before-code-blocks.sh
rename to sofp-src/scripts/check-punctuation-before-code-blocks.sh
index 24ebce477..0a6348e14 100644
--- a/sofp-src/check-punctuation-before-code-blocks.sh
+++ b/sofp-src/scripts/check-punctuation-before-code-blocks.sh
@@ -5,7 +5,7 @@ for a in sofp*tex; do
| LC_ALL=C egrep -v '^[0-9]+-.*[]?$):%},.~] *$' \
| LC_ALL=C egrep '^[0-9]+-[^ ]' \
| LC_ALL=C sed -e 's/^x\([0-9][0-9]*\)-.*$/\1/' \
- | LC_ALL=C sed -e 's/^\(.*\)$/"\1"/' > $b
+ | LC_ALL=C sed -e 's/^\(.*\)$/ "\1"/' > $b
test -s $b && {
echo "Warning: file $a has no punctuation before code blocks or display math at lines:"
cat $b
diff --git a/sofp-src/check_and_make_draft.sh b/sofp-src/scripts/check_and_make_draft.sh
similarity index 100%
rename from sofp-src/check_and_make_draft.sh
rename to sofp-src/scripts/check_and_make_draft.sh
diff --git a/sofp-src/compile_mdoc.sh b/sofp-src/scripts/compile_mdoc.sh
similarity index 100%
rename from sofp-src/compile_mdoc.sh
rename to sofp-src/scripts/compile_mdoc.sh
diff --git a/sofp-src/copy_lyx_header.sh b/sofp-src/scripts/copy_lyx_header.sh
similarity index 100%
rename from sofp-src/copy_lyx_header.sh
rename to sofp-src/scripts/copy_lyx_header.sh
diff --git a/sofp-src/copy_misspelled.sh b/sofp-src/scripts/copy_misspelled.sh
similarity index 100%
rename from sofp-src/copy_misspelled.sh
rename to sofp-src/scripts/copy_misspelled.sh
diff --git a/sofp-src/excluded_words b/sofp-src/scripts/excluded_words
similarity index 100%
rename from sofp-src/excluded_words
rename to sofp-src/scripts/excluded_words
diff --git a/sofp-src/scripts/export_scala_snippets.sh b/sofp-src/scripts/export_scala_snippets.sh
new file mode 100644
index 000000000..49bf249fd
--- /dev/null
+++ b/sofp-src/scripts/export_scala_snippets.sh
@@ -0,0 +1,11 @@
+# This script needs to run in the directory sofp-src/ .
+# Export Scala code snippets.
+name=sofp
+rm -rf mdoc; mkdir mdoc
+test -d mdoc_src || mkdir mdoc_src
+for f in tex/$name-*.tex; do
+ g=`basename "$f" .tex`
+ touch mdoc_src/$g.pre.md
+ # Remove control annotations for Scala code snippets.
+ cat mdoc_src/$g.pre.md <(cat $f | LC_ALL=C sed -e 's| *// *IGNORETHIS.*||;' | perl scripts/extract_scala_snippets.pl) > mdoc/$g.md
+done
diff --git a/sofp-src/extract_scala_snippets.pl b/sofp-src/scripts/extract_scala_snippets.pl
similarity index 100%
rename from sofp-src/extract_scala_snippets.pl
rename to sofp-src/scripts/extract_scala_snippets.pl
diff --git a/sofp-src/extract_urls.sh b/sofp-src/scripts/extract_urls.sh
similarity index 100%
rename from sofp-src/extract_urls.sh
rename to sofp-src/scripts/extract_urls.sh
diff --git a/sofp-src/scripts/functions.sh b/sofp-src/scripts/functions.sh
new file mode 100644
index 000000000..40c729e50
--- /dev/null
+++ b/sofp-src/scripts/functions.sh
@@ -0,0 +1,109 @@
+name="sofp"
+
+function git_commit_hash {
+ git rev-parse HEAD # Do not use --short here.
+}
+
+function source_hash {
+ cat $name*.lyx | shasum -a 256 | cut -c 1-64
+}
+
+# Make a PDF package with embedded source archive.
+
+# This function is not used now.
+function run_latex_many_times {
+ local base="$1"
+ echo "LaTeX Warning - Rerun" > "$base.log"
+ while grep -q '\(LaTeX Warning.*Rerun\|^(rerunfilecheck).*Rerun\)' "$base.log"; do
+ latex --interaction=batchmode "$base.tex"
+ done # This used to be only pdflatex but now we are using ps2pdf because of pstricks.
+}
+
+# Not used now, since we are using pdflatex.
+function make_pdf_with_index_via_ps2pdf {
+ local base="$1" fast="$2"
+ if [[ -z "$fast" ]]; then
+ run_latex_many_times "$base"
+ makeindex "$base.idx"
+ fi
+ run_latex_many_times "$base"
+ (dvips "$base.dvi" >& $base.log1; cat $base.log1 >> $base.log; rm $base.log1) >& /dev/null
+ (ps2pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true "$base.ps") 2>&1 >> $base.log
+}
+
+function add_source_hashes {
+ gitcommit=`git_commit_hash`
+ sourcehash=`source_hash`
+ echo $sourcehash > $name.source_hash1
+ LC_ALL=C sed -i.bak -E -e "s/INSERTSOURCEHASH/$sourcehash/; s/INSERTGITCOMMIT/$gitcommit/" $name.tex
+ mv $name.source_hash1 $name.source_hash
+}
+
+function remove_lulu {
+ local base="$1"
+ LC_ALL=C sed -i.bak -e 's,^\(.publishers{Published by\),%\1,; s,^\(Published by\),%\1,; s,^\(ISBN:\),%\1,' "$base".tex
+}
+
+function add_lulu {
+ local base="$1"
+ LC_ALL=C sed -i.bak -e 's,^%\(.publishers{Published by \),\1,; s,^%\(Published by \),\1,; s,^%\(ISBN:\),\1,' "$base".tex
+}
+
+function assemble_sources {
+ rm -f tex/*.lyx tex/*.bak tex/sofp.source_hash # Copies of LyX files and other temporary files from tex/ should not be in sources.
+ test -d build || mkdir build
+ tar jcvf build/"$name-src.tar.bz2" \
+ README*.md LICENSE *.sh scripts tex/chapter3-picture.pdf cover tex/*.tex lyx \
+ >& /dev/null
+ size=$(kbSize build/"$name-src.tar.bz2")
+ echo "File build/$name-src.tar.bz2 created, size $size bytes."
+}
+
+function kbSize {
+ local file="$1"
+ ls -l -n "$file"|sed -e 's/ */ /g'|cut -f5 -d ' '
+}
+
+function pdfPages {
+ local file="$1"
+ "$pdftk" "$file" dump_data | fgrep NumberOfPages | sed -e 's,^.* ,,'
+}
+
+function insert_examples_exercises_count {
+ local target="$1"
+ local exercises=`cat $name-*.tex | LC_ALL=C fgrep -c '\subsubsection{Exercise '`
+ local examples=`cat $name-*.tex | LC_ALL=C fgrep -c '\subsubsection{Example '`
+ local codesnippets=`cat $name-*.tex | LC_ALL=C fgrep -c '\begin{lstlisting}'`
+ local stmts=`cat $name-*.tex | LC_ALL=C fgrep -c '\subsubsection{Statement '`
+ local diagrams=`cat $name-*.tex | LC_ALL=C fgrep -c '\xymatrix{'`
+ local bdate=`date -R`
+ local osinfo=`uname -s`
+ local pdftex=`pdflatex --version | fgrep pdfTeX\ 3.14`
+ LC_ALL=C sed -i.bak -e "s|PDFTEXVERSION|$pdftex|g; s|BUILDDATE|$bdate|g; s|BUILDOPERATINGSYSTEM|$osinfo|g; s,NUMBEROFEXAMPLES,$examples,g; s,NUMBEROFEXERCISES,$exercises,g; s,NUMBEROFDIAGRAMS,$diagrams,g; s,NUMBEROFSTATEMENTS,$stmts,g; s,NUMBEROFCODESNIPPETS,$codesnippets,g;" "$target"
+}
+
+function attach_sources_to_pdf {
+ local src=$1 target=$2
+ "$pdftk" "$src" attach_files build/"$name-src.tar.bz2" output "$target"
+}
+
+function create_main_pdf_file {
+ local pt=$1 # Font size in points. Must be one of 10pt, 11pt, 12pt.
+ local targetdir=pdf-$pt
+ echo "Creating the full PDF file in $targetdir..."
+ rm -rf $targetdir; mkdir $targetdir
+ cp -r tex/* $targetdir/
+ (
+ cd $targetdir
+ # Set font size.
+ LC_ALL=C sed -i.bak -e "s|fontsize=[0-9]*pt|fontsize=$pt|" $name.tex
+
+ # Output is $name.pdf, main file is $name.tex, and other .tex files are \include'd.
+ bash ../scripts/run_pdflatex_with_index.sh "$name" >& ../build/build_main_pdf.log
+ )
+}
+
+function archive_build_logs {
+ tar jcf build/"$name-logs.tar.bz2" pdf-*pt/$name*.{log,ilg,idx,toc} build/*.log
+ echo "Log files are prepared in build/$name-logs.tar.bz2"
+}
diff --git a/sofp-src/get_coursier.sh b/sofp-src/scripts/get_coursier.sh
similarity index 100%
rename from sofp-src/get_coursier.sh
rename to sofp-src/scripts/get_coursier.sh
diff --git a/sofp-src/scripts/make_all.sh b/sofp-src/scripts/make_all.sh
new file mode 100644
index 000000000..a8a206172
--- /dev/null
+++ b/sofp-src/scripts/make_all.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# This script needs to run in the sofp-src/ subdirectory.
+
+# Requires pdftk and lyx.
+# Get lyx from www.lyx.org
+# For Mac, get pdftk from https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk_server-2.02-mac_osx-10.11-setup.pkg or else it may not work
+# For Windows, get pdftk from https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/pdftk_free-2.02-win-setup.exe
+
+source scripts/functions.sh
+
+# This requires pdftk to be installed on the path. Edit the next line as needed.
+export pdftk=`which pdftk`
+
+# LyX needs to be installed for this to work. Edit the next line as needed.
+export lyx=`which lyx`
+
+
+# Set custom lyx directory if needed.
+if [ x"$LYXDIR" == x ]; then
+ export lyxdir=""
+else
+ export lyxdir="-userdir $LYXDIR"
+fi
+
+rm -rf build mdoc tex
+
+mkdir build mdoc
+
+echo "Info: Using pdftk from '$pdftk' and lyx from '$lyx', lyx directory '$lyxdir'"
+
+export GS_OPTIONS="-dEmbedAllFonts=true -dPDFSETTINGS=/printer"
+
+bash scripts/make_pdflatex_sources.sh
+
+# Prepare "build/$name-src.tar.bz2" with all sources.
+assemble_sources &
+
+(
+ (
+ cd tex/
+
+ bash ../scripts/spelling_check.sh
+ bash ../scripts/check-consistent-labels.sh
+ bash ../scripts/check-lines_with_displaymath_in_new_paragraph.sh
+ bash ../scripts/check-punctuation-before-code-blocks.sh
+ ) | tee build/checks.log
+) &
+
+create_main_pdf_file 12pt &
+
+create_main_pdf_file 10pt &
+
+# Wait until PDF builds, source tar, and checks are finished.
+wait
+
+
+main_pdf=pdf-12pt/$name.pdf
+
+attach_sources_to_pdf $main_pdf $name.pdf &
+
+attach_sources_to_pdf pdf-10pt/$name.pdf $name-10pt.pdf &
+
+
+archive_build_logs &
+
+total_pages=`pdfPages $main_pdf`
+size=`kbSize $main_pdf`
+
+echo Result is $main_pdf, size $size bytes, with $total_pages pages.
+
+bash scripts/prepare_volume.sh 1 "$pdftk" &
+bash scripts/prepare_volume.sh 2 "$pdftk" &
+bash scripts/prepare_volume.sh 3 "$pdftk" &
+
+
+# Wait for background jobs.
+wait
diff --git a/sofp-src/scripts/make_pdflatex_sources.sh b/sofp-src/scripts/make_pdflatex_sources.sh
new file mode 100644
index 000000000..5d94f547f
--- /dev/null
+++ b/sofp-src/scripts/make_pdflatex_sources.sh
@@ -0,0 +1,73 @@
+# This script needs to run in the directory sofp-src/ .
+
+# Inputs: lyx/ directory with all sources.
+# Outputs: tex/ directory with preprocessed pdflatex files, and mdoc/ directory with exported code snippets.
+
+source scripts/functions.sh
+
+if [ x"$lyx" == x ]; then lyx=`which lyx`; else echo "Using $lyx"; fi
+
+function add_color {
+ local texsrc="$1"
+ # Insert color comments into displayed equation arrays. Also, in some places the green color was inserted; replace by `greenunder`.
+ # Example of inserted color: {\color{greenunder}\text{outer-interchange law for }M:}\quad &
+ LC_ALL=C sed -i.bak -e 's|\\color{green}|\\color{greenunder}|; s|^\(.*\\text{[^}]*}.*:\)\( *\\quad \& \)|{\\color{greenunder}\1}\2|; s|\(\& *\\quad\)\(.*\\text{[^}]*}.*: *\)\(\\quad\\\\\)$|\1{\\color{greenunder}\2}\3|' "$texsrc"
+ # Insert color background into all displayed equations. This is disabled because it does not always produce visually good results.
+ if false; then
+ LC_ALL=C sed -i.bak -E -e ' s!\\begin\{(align.?|equation)\}!\\begin{empheq}[box=\\mymathbgbox]{\1}!; s!\\end\{(align.?|equation)\}!\\end{empheq}!; ' "$texsrc"
+ LC_ALL=C sed -i.bak -E -e ' s!^\\\[$!\\begin{empheq}[box=\\mymathbgbox]{equation*}!; s!^\\\]$!\\end{empheq}!; ' "$texsrc"
+ fi
+}
+
+function add_color_to_equation_displays {
+ for f in $name-*.tex; do
+ add_color "$f" &
+ done
+}
+
+echo "Copying LyX files to TeX source directory..."
+
+rm -rf tex
+
+cp -r lyx tex
+
+# Source file for the back cover blurb. This file will be modified.
+cp cover/sofp-back-cover-no-bg.tex.src tex/sofp-back-cover-no-bg.tex
+
+# Source files used by the main pdf.
+cp cover/cover-background.jpg cover/sofp-cover-for-main-pdf.tex cover/sofp-cover-page-no-bg.tex cover/sofp-back-cover-for-main-pdf.tex tex/
+
+cd tex/
+
+bash ../scripts/chapter3-figure-make-pdf.sh &
+
+echo "Exporting LyX files $name.lyx and its child documents into LaTeX..."
+"$lyx" $lyxdir -f all --export pdflatex $name.lyx # Exports LaTeX for all child documents as well.
+
+(
+ cd ..
+ bash scripts/export_scala_snippets.sh
+) &
+
+#### The LaTeX files are heavily post-processed after exporting from LyX.
+
+echo "Post-processing LaTeX files..."
+
+add_source_hashes $name.tex & # Compute source hash from LyX files only. Add it to the root tex file.
+
+# Insert the number of examples and exercises.
+# This replacement is needed for the root file and for the back cover.
+insert_examples_exercises_count $name.tex
+insert_examples_exercises_count sofp-back-cover-no-bg.tex
+
+## Remove mathpazo? This was a mistake: should not remove it.
+#LC_ALL=C sed -i.bak -e 's/^.*usepackage.*mathpazo.*$//' $name.tex
+
+# Replace ugly Palatino quote marks and apostrophes by sans-serif marks.
+LC_ALL=C sed -i.bak -e " s|'s|\\\\textsf{'}s|g; s|O'|O\\\\textsf{'}|g; s|s'|s\\\\textsf{'}|g; "' s|``|\\textsf{``}|g; s|“|\\textsf{``}|g; '" s|''|\\\\textsf{''}|g; s|”|\\\\textsf{''}|g; s|\\\\textsf{'}'|\\\\textsf{''}|g; " $name-*.tex
+
+rm -rf *.bak &
+
+add_color_to_equation_displays
+
+wait
diff --git a/sofp-src/prepare_volume.sh b/sofp-src/scripts/prepare_volume.sh
similarity index 64%
rename from sofp-src/prepare_volume.sh
rename to sofp-src/scripts/prepare_volume.sh
index 0d695fbdd..5f9445a95 100644
--- a/sofp-src/prepare_volume.sh
+++ b/sofp-src/scripts/prepare_volume.sh
@@ -1,6 +1,8 @@
# Prepare the printable PDF file of volume v of the book. v = 1, 2, 3.
# The files are designed for printing and will have no color in the PDF hyperlinks.
+# This script needs to run in the sofp-src/ subdirectory.
+
function pdfPages {
local file="$1"
"$pdftk" "$file" dump_data | fgrep NumberOfPages | sed -e 's,^.* ,,'
@@ -21,22 +23,22 @@ vol3_url="https://www.lulu.com/shop/sergei-winitzki/the-science-of-functional-pr
v=$1
pdftk=$2
+# This directory will be used as the source of references and page numbers for the full book file.
+full_file=pdf-12pt
+
+if [ x"$pdftk" == x ]; then pdftk=`which pdftk`; fi
+
dir=vol$v
name=sofp-$dir
export LC_ALL=C
rm -rf $dir
-mkdir -p $dir/book_cover
-cd $dir
-
-tar jxf ../sofp-src.tar.bz2
-mv sofp-src/* .
-cp ../sofp*.tex ../sofp.* .
-cp ../book_cover/* ./book_cover/
+cp -r tex $dir
-cp book_cover/sofp-cover-parameters.tex.src book_cover/sofp-cover-parameters.tex
+cp cover/sofp-cover-parameters.tex.src $dir/sofp-cover-parameters.tex
+cp cover/*.{tex,jpg,pdf} $dir/
function remove_part1 {
fgrep -v '\part{Introductory level}' | \
@@ -59,8 +61,8 @@ function remove_part3 {
}
# Set part, section, page counters. \setcounter{page}{1} and so on.
-firstpart1=$(fgrep '\contentsline {part}' ../sofp.aux | tail -n +$v | head -1 | sed -e 's|.*{part.\([0-9]\)}.*|\1|')
-firstpage1=$(fgrep '\contentsline {part}' ../sofp.aux | tail -n +$v | head -1 | sed -e 's|.*{\([0-9]*\)}{part.[0-9]}.*|\1|')
+firstpart1=$(fgrep '\contentsline {part}' $full_file/sofp.aux | tail -n +$v | head -1 | sed -e 's|.*{part.\([0-9]\)}.*|\1|')
+firstpage1=$(fgrep '\contentsline {part}' $full_file/sofp.aux | tail -n +$v | head -1 | sed -e 's|.*{\([0-9]*\)}{part.[0-9]}.*|\1|')
# Latex will increment those counters immediately. So, we decrement them here before setting.
firstpart=$((firstpart1-1))
firstpage=$((firstpage1-0))
@@ -73,8 +75,8 @@ function get_chapter {
# Remove all content except for this volume.
case $v in
1)
- firstchapter=$(get_chapter ../sofp-nameless-functions.aux)
- cat sofp.tex | remove_part2 | remove_part3 > $name.tex
+ firstchapter=$(get_chapter $full_file/sofp-nameless-functions.aux)
+ cat $dir/sofp.tex | remove_part2 | remove_part3 > $dir/$name.tex
title1="Part I"
title2="Part I: Introductory level"
url="$vol1_url"
@@ -83,8 +85,8 @@ case $v in
;;
2)
- firstchapter=$(get_chapter ../sofp-functors.aux)
- cat sofp.tex | remove_part1 | remove_part3 > $name.tex
+ firstchapter=$(get_chapter $full_file/sofp-functors.aux)
+ cat $dir/sofp.tex | remove_part1 | remove_part3 > $dir/$name.tex
title1="Part II"
title2="Part II: Intermediate level"
url="$vol2_url"
@@ -93,8 +95,8 @@ case $v in
;;
3)
- firstchapter=$(get_chapter ../sofp-free-type.aux)
- cat sofp.tex | remove_part1 | remove_part2 > $name.tex
+ firstchapter=$(get_chapter $full_file/sofp-free-type.aux)
+ cat $dir/sofp.tex | remove_part1 | remove_part2 > $dir/$name.tex
title1="Part III"
title2="Part III: Advanced level"
url="$vol3_url"
@@ -106,39 +108,52 @@ esac
echo "Detected previous chapter $firstchapter, first page $firstpage, previous part number $firstpart"
- sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|; s|\(\\part{.*}\)|\\setcounter{page}{'$firstpage'}\\setcounter{part}{'$firstpart'}\\setcounter{chapter}{'$firstchapter'}\1|;' $name.tex
+ sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|; s|\(\\part{.*}\)|\\setcounter{page}{'$firstpage'}\\setcounter{part}{'$firstpart'}\\setcounter{chapter}{'$firstchapter'}\1|;' $dir/$name.tex
# Subtitle on cover page.
- sed -i.bak -e 's|% End of title.|\\vspace{0.2in}\\centerline{\\fontsize{20pt}{20pt}\\selectfont{'"$title2"'}}|' book_cover/sofp-cover-page-no-bg.tex
+ sed -i.bak -e 's|% End of title.|\\vspace{0.2in}\\centerline{\\fontsize{20pt}{20pt}\\selectfont{'"$title2"'}}|' $dir/sofp-cover-page-no-bg.tex
# Title on spine.
- sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|;' book_cover/sofp-spine.tex
+ sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|;' $dir/sofp-spine.tex
# Replace lulu.com hyperlink.
- sed -i.bak -e 's|{https://www.lulu.com/[^}]*}{\(Print on demand[^}]*\)}|{'"$url"'}{\1}|;' $name.tex
+ sed -i.bak -e 's|{https://www.lulu.com/[^}]*}{\(Print on demand[^}]*\)}|{'"$url"'}{\1}|;' $dir/$name.tex
# Replace ISBN information.
echo "Using volume $v ISBN '$isbn'"
- sed -i.bak -e 's|\({\\footnotesize{}\)ISBN: [^}]*\(}\\\\\)|\1'"$isbn"'\2|;' $name.tex
+ sed -i.bak -e 's|\({\\footnotesize{}\)ISBN: [^}]*\(}\\\\\)|\1'"$isbn"'\2|;' $dir/$name.tex
# Add barcode to back cover.
- sed -i.bak -e 's|%\(.*\){barcode}.*|\1{'"$barcode"'}|' book_cover/sofp-back-cover-no-bg.tex
+ sed -i.bak -e 's|%\(.*\){barcode}.*|\1{'"$barcode"'}|' $dir/sofp-back-cover-no-bg.tex
-cp book_cover/* .
-
-mv $name.tex sofp.tex
+mv $dir/$name.tex $dir/sofp.tex
# Disable PDF hyperlinks and remove covers.
-LC_ALL=C sed -i.bak -e 's|colorlinks=true|colorlinks=false|; s|\\input{sofp-cover-page}||; s|\\input{sofp-back-cover-page}||; ' sofp.tex
+LC_ALL=C sed -i.bak -e 's|colorlinks=true|colorlinks=false|; s|\\input{sofp-cover-page}||; s|\\input{sofp-back-cover-page}||; ' $dir/sofp.tex
echo "Starting to prepare volume $v"
(
-pdflatex --interaction=batchmode sofp /dev/null
-makeindex sofp.idx
-cp ../*.aux . # Enable references to other chapters.
-pdflatex --interaction=batchmode sofp
+
+ cd $dir
+ pdflatex --interaction=batchmode sofp /dev/null
+ makeindex sofp.idx
+ cp ../$full_file/*.aux . # Enable references to other chapters.
+ pdflatex --interaction=batchmode sofp
+
) >& /dev/null
-mv sofp.pdf ../$name.pdf
-echo "Volume $v is prepared in $name.pdf"
-bash ../prepare_cover.sh ../$name.pdf "$pdftk"
-mv book_cover/sofp-3page-cover.pdf ../$name-3page-cover.pdf
+mv $dir/sofp.pdf $name.pdf
+
+pages=$(pdfPages $name.pdf)
+
+echo "Volume $v is prepared in $name.pdf, with $pages pages"
+
+# Preparing cover.
+sed -i.bak -e "s|TOTALPAGES|$pages|" $dir/sofp-cover-parameters.tex
+
+(
+ cd $dir/
+ bash ../scripts/sofp-make-cover.sh >& ../build/build-cover-$dir.log
+)
+
+mv $dir/sofp-3page-cover.pdf $name-3page-cover.pdf
+
echo "Cover for volume $v is prepared in $name-3page-cover.pdf"
diff --git a/sofp-src/remove_hyperlinks.sh b/sofp-src/scripts/remove_hyperlinks.sh
similarity index 100%
rename from sofp-src/remove_hyperlinks.sh
rename to sofp-src/scripts/remove_hyperlinks.sh
diff --git a/sofp-src/scripts/run_pdflatex_with_index.sh b/sofp-src/scripts/run_pdflatex_with_index.sh
new file mode 100644
index 000000000..a82c10e97
--- /dev/null
+++ b/sofp-src/scripts/run_pdflatex_with_index.sh
@@ -0,0 +1,12 @@
+base="$1"
+echo "Running pdfltex for $base"
+pdflatex --interaction=batchmode "$base"
+makeindex "$base.idx"
+pdflatex --interaction=batchmode "$base"
+
+if ! test -s "$base".pdf; then
+ echo Output file "$base".pdf not found, exiting.
+ exit 1
+else
+ echo "File $base.pdf is ready."
+fi
diff --git a/sofp-src/select_random_pages.sh b/sofp-src/scripts/select_random_pages.sh
similarity index 100%
rename from sofp-src/select_random_pages.sh
rename to sofp-src/scripts/select_random_pages.sh
diff --git a/sofp-src/scripts/sofp-make-cover.sh b/sofp-src/scripts/sofp-make-cover.sh
new file mode 100644
index 000000000..8fadeb026
--- /dev/null
+++ b/sofp-src/scripts/sofp-make-cover.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Inputs:
+# sofp-spine.tex
+# sofp-cover-parameters.tex
+#
+# sofp-back-cover.tex
+# sofp-cover-parameters.tex sofp-back-cover-no-bg.tex
+#
+# sofp-back-cover-no-bg.tex (generated from sofp-back-cover-no-bg.tex.src)
+# monads_evil_face.jpg .pdf
+#
+# sofp-front-cover.tex
+# sofp-cover-parameters.tex sofp-cover-page-no-bg.tex
+#
+# sofp-cover-for-main-pdf.tex
+# cover-background.jpg sofp-cover-page-no-bg.tex
+# sofp-back-cover-for-main-pdf.tex
+# cover-background.jpg sofp-back-cover-no-bg.tex
+
+
+# Prepare the three cover pages in parallel.
+
+for f in sofp-spine sofp-back-cover sofp-front-cover; do
+ pdflatex --interaction=batchmode "$f" &
+done
+wait # Wait until all 3 cover pages are done.
+
+# Inputs:
+# sofp-3page-cover.tex
+# sofp-spine.pdf sofp-back-cover.pdf sofp-front-cover.pdf cover-background-2.jpg
+pdflatex --interaction=batchmode sofp-3page-cover
+pdflatex --interaction=batchmode sofp-3page-cover
diff --git a/sofp-src/spelling_check.sh b/sofp-src/scripts/spelling_check.sh
similarity index 89%
rename from sofp-src/spelling_check.sh
rename to sofp-src/scripts/spelling_check.sh
index ec80d4978..ef8b5ab78 100644
--- a/sofp-src/spelling_check.sh
+++ b/sofp-src/scripts/spelling_check.sh
@@ -10,8 +10,8 @@ cat sofp*.tex | \
perl -e 'while(<>) { last if (/The purpose of this license/i); print; }; while (<>) { last if (/but changing it is not allowed/);}; while(<>) { print;};' | \
tee tempfile | \
hunspell -t -l -d en_US | \
- sort | uniq | egrep -iv -f excluded_words > misspelled_words
+ sort | uniq | egrep -iv -f ../scripts/excluded_words > misspelled_words
echo Found `wc -l misspelled_words`.
-#rm -rf tempfile
-
+cat misspelled_words
+rm -f tempfile
diff --git a/sofp-src/scripts/user_bind_copy.sh b/sofp-src/scripts/user_bind_copy.sh
new file mode 100644
index 000000000..890f7c491
--- /dev/null
+++ b/sofp-src/scripts/user_bind_copy.sh
@@ -0,0 +1 @@
+cp $HOME/Library/Application\ Support/LyX-2.3/bind/user.bind lyx/
diff --git a/sofp-src/sofp-appendices.pre.md b/sofp-src/sofp-appendices.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-applicative.pre.md b/sofp-src/sofp-applicative.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-curry-howard.pre.md b/sofp-src/sofp-curry-howard.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-disjunctions.pre.md b/sofp-src/sofp-disjunctions.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-essay1.pre.md b/sofp-src/sofp-essay1.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-essay2.pre.md b/sofp-src/sofp-essay2.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-essay3.pre.md b/sofp-src/sofp-essay3.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-essays.pre.md b/sofp-src/sofp-essays.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-filterable.pre.md b/sofp-src/sofp-filterable.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-free-type.pre.md b/sofp-src/sofp-free-type.pre.md
deleted file mode 100644
index 6af1103b4..000000000
--- a/sofp-src/sofp-free-type.pre.md
+++ /dev/null
@@ -1,12 +0,0 @@
-//> using scala 2.13.10
-
-import scala.util.{Failure, Try}
-object tools {
- implicit class MustBeOp[A](x: => A) {
- def mustBe[B >: A]: B = { assert(x.isInstanceOf[B]); x : B }
- def equal[B >: A](y: B): Unit = assert(x == y)
- def mustThrow[T](message: String): Unit = assert(Try(x) match { case Failure(t: T) if t.getMessage == message => true } )
- }
-}
-import tools._
-
diff --git a/sofp-src/sofp-functors.pre.md b/sofp-src/sofp-functors.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-higher-order-functions.pre.md b/sofp-src/sofp-higher-order-functions.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-induction.pre.md b/sofp-src/sofp-induction.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-monads.pre.md b/sofp-src/sofp-monads.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-nameless-functions.pre.md b/sofp-src/sofp-nameless-functions.pre.md
deleted file mode 100644
index d05351f03..000000000
--- a/sofp-src/sofp-nameless-functions.pre.md
+++ /dev/null
@@ -1,13 +0,0 @@
-import scala.util.{Failure, Try}
-
-object tools {
- implicit class MustBeOp[A](x: => A) {
- def mustBe[B >: A]: B = { assert(x.isInstanceOf[B]); x : B }
- def equal[B >: A](y: B): Unit = assert(x == y)
- def mustThrow[T](message: String): Unit = assert(Try(x) match { case Failure(t: T) if t.getMessage == message => true } )
- }
-}
-import tools._
-
-val n: Int = 10 // Defined in the text.
-
diff --git a/sofp-src/sofp-preface.pre.md b/sofp-src/sofp-preface.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-reasoning.pre.md b/sofp-src/sofp-reasoning.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-summary.pre.md b/sofp-src/sofp-summary.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-transformers.pre.md b/sofp-src/sofp-transformers.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-traversable.pre.md b/sofp-src/sofp-traversable.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/sofp-typeclasses.pre.md b/sofp-src/sofp-typeclasses.pre.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/sofp-src/tex/chapter3-picture.pdf b/sofp-src/tex/chapter3-picture.pdf
new file mode 100644
index 000000000..9376f360e
Binary files /dev/null and b/sofp-src/tex/chapter3-picture.pdf differ
diff --git a/sofp-src/tex/cover-background.jpg b/sofp-src/tex/cover-background.jpg
new file mode 100644
index 000000000..3d7f0eb4e
Binary files /dev/null and b/sofp-src/tex/cover-background.jpg differ
diff --git a/sofp-src/tex/ftt-example.jpg b/sofp-src/tex/ftt-example.jpg
new file mode 100644
index 000000000..40f1f660e
Binary files /dev/null and b/sofp-src/tex/ftt-example.jpg differ
diff --git a/sofp-src/tex/monads_evil_face.jpg b/sofp-src/tex/monads_evil_face.jpg
new file mode 100644
index 000000000..992c6e965
Binary files /dev/null and b/sofp-src/tex/monads_evil_face.jpg differ
diff --git a/sofp-src/tex/no-bugs.jpg b/sofp-src/tex/no-bugs.jpg
new file mode 100644
index 000000000..9fafccc2d
Binary files /dev/null and b/sofp-src/tex/no-bugs.jpg differ
diff --git a/sofp-src/sofp-appendices.tex b/sofp-src/tex/sofp-appendices.tex
similarity index 100%
rename from sofp-src/sofp-appendices.tex
rename to sofp-src/tex/sofp-appendices.tex
diff --git a/sofp-src/sofp-applicative.tex b/sofp-src/tex/sofp-applicative.tex
similarity index 100%
rename from sofp-src/sofp-applicative.tex
rename to sofp-src/tex/sofp-applicative.tex
diff --git a/sofp-src/tex/sofp-back-cover-for-main-pdf.tex b/sofp-src/tex/sofp-back-cover-for-main-pdf.tex
new file mode 100644
index 000000000..012e31ab1
--- /dev/null
+++ b/sofp-src/tex/sofp-back-cover-for-main-pdf.tex
@@ -0,0 +1,3 @@
+\ThisCenterWallPaper{1.01}{cover-background.jpg}
+\input{sofp-back-cover-no-bg.tex}
+
diff --git a/sofp-src/tex/sofp-back-cover-no-bg.tex b/sofp-src/tex/sofp-back-cover-no-bg.tex
new file mode 100644
index 000000000..c45484bd8
--- /dev/null
+++ b/sofp-src/tex/sofp-back-cover-no-bg.tex
@@ -0,0 +1,56 @@
+\onecolumn
+\thispagestyle{empty}
+\newgeometry{top=2cm, left=2.5cm, right=3.9cm,bottom=1cm}
+
+\begin{wrapfigure}{l}{0.4\columnwidth}
+\includegraphics[width=0.4\columnwidth]{monads_evil_face}
+\vspace{-2.0\baselineskip}
+\end{wrapfigure}
+
+%\noindent
+\smaller
+This book is a pedagogical in-depth tutorial and reference
+on the theory of functional programming (FP) as practiced in the early
+21$^{\text{st}}$ century. Starting from issues found in practical
+coding, the book builds up the theoretical intuition, knowledge, and
+techniques that programmers need for rigorous reasoning about types
+and code. Examples are given in Scala, but most of the material applies equally
+to other FP languages.
+
+The book\textsf{'}s topics include working with FP-style collections; reasoning about recursive
+functions and types; the Curry-Howard correspondence; laws, structural
+analysis, and code for functors, monads, and other typeclasses based on exponential-polynomial data types;
+techniques of symbolic derivation and proof;
+free typeclass constructions; and
+parametricity theorems.
+
+Long and difficult, yet boring explanations are logically
+developed in excruciating detail through 1882
+Scala code snippets, 191 statements with step-by-step
+derivations, 103 diagrams, 218 examples
+with tested Scala code, and 297 exercises. Discussions
+build upon each chapter\textsf{'}s material further.
+
+Beginners in FP will find tutorials about the \texttt{map}/\texttt{reduce}
+programming style, type parameters, disjunctive types, and higher-order
+functions. For more advanced readers, the book shows the practical
+uses of the Curry-Howard correspondence and the parametricity theorems
+without unnecessary jargon; proves that all the standard monads (e.g.,
+\texttt{List} or \texttt{State})
+satisfy the monad laws; derives lawful instances of \texttt{Functor}
+and other typeclasses from types; shows that monad transformers need
+18 laws;
+and explains the use of parametricity for reasoning about the Church encoding and the free typeclasses.
+
+Readers should have a working knowledge of programming; e.g.,
+be able to write code that prints the number of distinct words in
+a sentence. The difficulty of this book\textsf{'}s mathematical derivations
+is at the level of undergraduate multivariate calculus, similar to that of multiplying
+matrices or simplifying the expressions:
+\[
+\frac{1}{x-2}-\frac{1}{x+2}\quad\text{ and }\quad\frac{d}{dx}\left((x+1)f(x)e^{-x}\right)\quad.
+\]
+
+The author received a Ph.D. in theoretical physics. After a career in academic research, he works as a software engineer.
+
+%\vspace{0.2cm}\hspace*{\fill}\includegraphics[scale=1.0]{barcode}
diff --git a/sofp-src/sofp-cover-page.tex b/sofp-src/tex/sofp-cover-for-main-pdf.tex
similarity index 100%
rename from sofp-src/sofp-cover-page.tex
rename to sofp-src/tex/sofp-cover-for-main-pdf.tex
diff --git a/sofp-src/sofp-cover-page-no-bg.tex b/sofp-src/tex/sofp-cover-page-no-bg.tex
similarity index 100%
rename from sofp-src/sofp-cover-page-no-bg.tex
rename to sofp-src/tex/sofp-cover-page-no-bg.tex
diff --git a/sofp-src/sofp-curry-howard.tex b/sofp-src/tex/sofp-curry-howard.tex
similarity index 100%
rename from sofp-src/sofp-curry-howard.tex
rename to sofp-src/tex/sofp-curry-howard.tex
diff --git a/sofp-src/sofp-disjunctions.tex b/sofp-src/tex/sofp-disjunctions.tex
similarity index 100%
rename from sofp-src/sofp-disjunctions.tex
rename to sofp-src/tex/sofp-disjunctions.tex
diff --git a/sofp-src/tex/sofp-essay1.tex b/sofp-src/tex/sofp-essay1.tex
new file mode 100644
index 000000000..a666daa12
--- /dev/null
+++ b/sofp-src/tex/sofp-essay1.tex
@@ -0,0 +1,206 @@
+
+\addchap{Essay: Towards functional data engineering with Scala}
+
+Data engineering is among the highest-demand\footnote{\texttt{\href{http://archive.is/mK59h}{http://archive.is/mK59h}}}
+novel occupations in the IT world today. Data engineers create software
+pipelines that process large volumes of data efficiently. Why did
+the Scala programming language emerge as a premier tool\footnote{\texttt{\href{https://www.slideshare.net/noootsab/scala-the-unpredicted-lingua-franca-for-data-science}{https://tinyurl.com/4wwsedrz}}}
+for crafting the foundational data engineering technologies such as
+Spark or Akka? Why is Scala in high demand\footnote{\texttt{\href{https://techcrunch.com/2016/06/14/scala-is-the-new-golden-child/}{https://techcrunch.com/2016/06/14/scala-is-the-new-golden-child/}}}
+within the world of big data?
+
+There are reasons to believe that the choice of Scala was not accidental.
+
+\addsec{Data is math}
+
+Humanity has been working with data at least since Babylonian tax
+tables\footnote{\texttt{\href{https://www.nytimes.com/2017/08/29/science/trigonometry-babylonian-tablet.html}{https://www.nytimes.com/2017/08/29/science/trigonometry-babylonian-tablet.html}}}
+and the ancient Chinese number books.\footnote{\texttt{\href{https://web.archive.org/web/20170425233550/https://quatr.us/china/science/chinamath.htm}{https://quatr.us/china/science/chinamath.htm}}}
+Mathematics summarizes several millennia\textsf{'}s worth of data processing
+experience in a few fundamental tenets:
+
+\begin{figure}
+\begin{centering}
+\includegraphics[width=0.4\linewidth]{type-error}\vspace{-0.5\baselineskip}
+\par\end{centering}
+\caption{\index{jokes}Mixing incompatible data types produces nonsensical
+results.\label{fig:A-nonsensical-calculation-1}}
+
+\end{figure}
+
+\begin{itemize}
+\item Data is \emph{immutable} (because true facts are immutable).
+\item Values of different \emph{type} (population count, land area, distance,
+price, location, time, growth percentage, etc.) need to be handled
+separately. For example, it is an error to add a distance to a population
+count.
+\item Data processing should be performed according to \emph{mathematical
+formulas}. True mathematical formulas are immutable and always give
+the same results from the same input data.
+\end{itemize}
+Violating these tenets produces nonsense (see Fig.\ \ref{fig:A-nonsensical-calculation-1}
+for a real-life illustration).
+
+The power of the principles of mathematics extends over all epochs
+and all cultures; math is the same in San Francisco, in Rio de Janeiro,
+in Kuala-Lumpur, and in Pyongyang (Fig.\ \ref{fig:The-Pyongyang-method-of-error-free-programming-1}).
+
+\addsec{Functional programming is math}
+
+The functional programming paradigm is based on mathematical principles:
+values are immutable, data processing is coded through formula-like
+expressions, and each type of data is required to match correctly
+during the computations. The type-checking process automatically prevents
+programmers from making many kinds of coding errors. In addition,
+programming languages such as Scala and Haskell have a set of features
+adapted to building powerful abstractions and domain-specific languages.
+This power of abstraction is not accidental. Since mathematics is
+the ultimate art of building abstractions, math-based functional programming
+languages capitalize on several millennia of mathematical experience.
+
+A prominent example of how mathematics informs the design of programming
+languages is the connection between constructive logic\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Intuitionistic_logic}{https://en.wikipedia.org/wiki/Intuitionistic\_logic}}}
+and the programming language\textsf{'}s type system, called the Curry-Howard
+(CH) correspondence. The main idea of the CH correspondence\index{Curry-Howard correspondence}
+is to think of programs as mathematical formulas that compute a value
+of a certain type $A$. The CH correspondence is between programs
+and logical propositions: To any program that computes a value of
+type $A$, there corresponds a proposition stating that \textsf{``}a value
+of type $A$ can be computed\textsf{''}.
+
+This may sound rather theoretical so far. To see the real value of
+the CH correspondence, recall that formal logic has operations \textsf{``}\textbf{\emph{and}}\textsf{''},
+\textsf{``}\textbf{\emph{or}}\textsf{''}, and \textsf{``}\textbf{\emph{implies}}\textsf{''}. For any
+two propositions $A$, $B$, we can construct the propositions \textsf{``}$A$
+\textbf{\emph{and}} $B$\textsf{''}, \textsf{``}$A$ \textbf{\emph{or}} $B$\textsf{''}, \textsf{``}$A$
+\textbf{\emph{implies}} $B$\textsf{''}. These three logical operations are
+foundational; without one of them, the logic is \emph{incomplete}
+(cannot derive some theorems).
+
+A programming language \textbf{obeys the CH correspondence}\index{Curry-Howard correspondence}
+with the logic if for any types $A$, $B$, the language also contains
+composite types corresponding to the logical formulas \textsf{``}$A$ \textbf{\emph{or}}
+$B$\textsf{''}, \textsf{``}$A$ \textbf{\emph{and}} $B$\textsf{''}, \textsf{``}$A$ \textbf{\emph{implies}}
+$B$\textsf{''}. In Scala, these composite types are \lstinline!Either[A, B]!,
+the tuple \lstinline!(A, B)!, and the function type \lstinline!A => B!.
+All modern functional languages such as OCaml, Haskell, Scala, F\#,
+and Swift support these three type constructions and thus obey the
+CH correspondence. Having a \emph{complete} logic in a language\textsf{'}s
+type system enables declarative domain-driven code design.\footnote{\texttt{\href{https://fsharpforfunandprofit.com/ddd/}{https://fsharpforfunandprofit.com/ddd/}}}
+
+\begin{wrapfigure}{I}{0.5\columnwidth}%
+\begin{centering}
+\vspace{-0.5\baselineskip}
+\par\end{centering}
+\vspace{-3\baselineskip}
+\end{wrapfigure}%
+
+\begin{figure}
+
+\begin{centering}
+\includegraphics[width=0.5\linewidth]{no-bugs}
+\par\end{centering}
+\caption{\index{jokes}The Pyongyang method of error-free software engineering.\label{fig:The-Pyongyang-method-of-error-free-programming-1}}
+
+\end{figure}
+
+It is interesting to note that most older programming languages (C/C++,
+Java, JavaScript, Python) do not support some of these composite types.
+In other words, these programming languages have type systems based
+on an incomplete logic. As a result, users of these languages have
+to implement burdensome workarounds that make for error-prone code.
+Failure to follow mathematical principles has real costs (Figure~\ref{fig:The-Pyongyang-method-of-error-free-programming-1}).
+
+\addsec{The power of abstraction}
+
+Early adopters of Scala, such as Netflix, LinkedIn, and Twitter, were
+implementing what is now called \textsf{``}big data engineering\textsf{''}. The required
+software needs to be highly concurrent, distributed, and resilient
+to failure. Those software companies used Scala as their main implementation
+language and reaped the benefits of functional programming.
+
+What makes Scala suitable for big data tasks? The only reliable way
+of managing massively concurrent code is to use sufficiently high-level
+abstractions that make application code declarative. The two most
+important such abstractions are the \textsf{``}resilient distributed dataset\textsf{''}
+(RDD) of Apache Spark and the \textsf{``}reactive stream\textsf{''} used in systems
+such as Kafka, Akka Streams, and Apache Flink. While these abstractions
+are certainly implementable in Java or Python, a fully declarative
+and type-safe usage is possible only in a programming language with
+a sophisticated type system. Among the currently available mature
+functional languages, only Scala and Haskell are technically adequate
+for that task, due to their support for typeclasses and higher-order
+types. The early adopters of Scala were able to benefit from the powerful
+abstractions Scala supports. In this way, Scala enabled those businesses
+to engineer and to scale up their massively concurrent computations.
+
+It remains to see why Scala (and not, say, OCaml or Haskell) became
+the \emph{lingua franca} of big data.
+
+\addsec{Scala is Java on math }
+
+The recently invented general-purpose functional programming languages
+may be divided into \textsf{``}academic\textsf{''} (OCaml, Haskell) and \textsf{``}industrial\textsf{''}
+(F\#, Scala, Swift).
+
+The \textsf{``}academic\textsf{''} languages are clean-room implementations of well-researched
+mathematical principles of programming language design (the CH correspondence
+being one such principle). These languages are not limited by requirements
+of compatibility with any existing platforms or libraries. Because
+of this, the \textsf{``}academic\textsf{''} languages have been designed and used
+for pursuing various mathematical ideas to their logical conclusion.\footnote{OCaml has recursive and polymorphic product and co-product types that
+can be freely combined with object-oriented types. Haskell removes
+all side effects from the language and supports type-level functions
+of arbitrarily high order.} At the same time, software practitioners struggle to adopt these
+programming languages due to a steep learning curve, a lack of enterprise-grade
+libraries and tool support, and immature package management.
+
+The languages from the \textsf{``}industrial\textsf{''} group are based on existing
+and mature software ecosystems: F\# on .NET, Scala on JVM, and Swift
+on the MacOS/iOS platform. One of the important design requirements
+for these languages is 100\% binary compatibility with their \textsf{``}parent\textsf{''}
+platform\textsf{'}s languages (F\# with C\#, Scala with Java, and Swift with
+Objective-C). Because of this, developers can immediately take advantage
+of the existing tooling, package management, and industry-strength
+libraries, while slowly ramping up the idiomatic usage of new language
+features. However, the same compatibility requirements dictate certain
+limitations in the languages, making their design less than fully
+satisfactory from the functional programming viewpoint.
+
+It is now easy to see why the adoption rate of the \textsf{``}industrial\textsf{''}
+group of languages is much higher\footnote{\texttt{\href{https://www.tiobe.com/tiobe-index/}{https://www.tiobe.com/tiobe-index/}},
+archived in 2019 at \texttt{\href{http://archive.is/RsNH8}{http://archive.is/RsNH8}}} than that of the \textsf{``}academic\textsf{''} languages. The transition to the
+functional paradigm is also smoother for software developers because
+F\#, Scala, and Swift seamlessly support the familiar object-oriented
+programming\index{object-oriented programming} paradigm. At the same
+time, these new languages still have logically complete type systems,
+which gives developers an important benefit of type-safe domain modeling.
+
+Nevertheless, the type systems of these languages are not equally
+powerful. For instance, F\# and Swift are similar to OCaml in many
+ways but omit OCaml\textsf{'}s parameterized modules and some other features.
+Of all the mentioned languages, only Scala and Haskell directly support
+typeclasses and higher-order functions on types, which are helpful
+for expressing abstractions such as automatically parallelized data
+sets or asynchronous data streams.
+
+To see the impact of these advanced features, consider LINQ, a domain-specific
+language for database queries on .NET, implemented in C\# and F\#
+through a special built-in syntax supported by Microsoft\textsf{'}s compilers.
+Analogous functionality is provided in Scala as a \emph{library},
+without need to modify the Scala compiler, by several open-source
+projects such as Slick and Quill. Similar libraries exist for Haskell
+\textemdash{} but not in languages with less powerful type systems.
+
+\addsec{Summary}
+
+Only Scala has all of the features required for industrial-grade functional
+programming:
+\begin{enumerate}
+\item Functional collections in the standard library.
+\item A sophisticated type system with support for typeclasses and higher-order
+types.
+\item Seamless compatibility with a mature software ecosystem (JVM).
+\end{enumerate}
+Based on this assessment, it appears that Scala is a good choice of
+an implementation language for big data engineering.
diff --git a/sofp-src/tex/sofp-essay2.tex b/sofp-src/tex/sofp-essay2.tex
new file mode 100644
index 000000000..1a3e19f78
--- /dev/null
+++ b/sofp-src/tex/sofp-essay2.tex
@@ -0,0 +1,856 @@
+
+\addchap{Essay: Software engineers and software artisans}
+
+Let us examine what we ordinarily understand by \emph{engineering}
+as opposed to artisanship or craftsmanship. It will then become apparent
+that today\textsf{'}s computer programmers must be viewed as \textsf{``}software artisans\textsf{''}
+rather than software engineers.
+
+\addsec{Engineering disciplines }
+
+Consider the way mechanical engineers, chemical engineers, or electrical
+engineers work, and look at the studies they require for becoming
+proficient in their fields.
+
+A mechanical engineer studies calculus, linear algebra, differential
+geometry, and several areas of physics such as theoretical mechanics,
+thermodynamics, and elasticity theory,\footnote{\texttt{\href{https://www.colorado.edu/mechanical/academics/undergraduate-program/curriculum}{https://www.colorado.edu/mechanical/academics/undergraduate-program/curriculum}}}
+and then uses calculations to guide the design of a bridge. A chemical
+engineer studies chemistry, thermodynamics, calculus, linear algebra,
+differential equations, some areas of physics such as thermodynamics
+and kinetic theory,\footnote{\texttt{\href{https://www.colorado.edu/engineering/sample-undergraduate-curriculum-chemical}{https://www.colorado.edu/engineering/sample-undergraduate-curriculum-chemical}}}
+and uses calculations to guide the design of a chemical process. An
+electrical engineer studies advanced calculus, linear algebra, and
+several areas of physics such as electrodynamics and quantum theory,\footnote{\texttt{\href{http://archive.is/XYLyE}{http://archive.is/XYLyE}}}
+and uses calculations to design an antenna or a microchip.
+
+The common pattern is that engineers use mathematics and natural sciences
+in order to create new devices. Mathematical calculations and scientific
+reasoning are performed \emph{before} designing or building a real
+machine.
+
+Some of the studies required for engineers include arcane abstract
+concepts such as the \textsf{``}Fourier transform of the delta function\textsf{''}\footnote{\texttt{\href{https://www.youtube.com/watch?v=KAbqISZ6SHQ}{https://www.youtube.com/watch?v=KAbqISZ6SHQ}}}
+and the \textsf{``}inverse $Z$-transform\textsf{''}\footnote{\texttt{\href{http://archive.is/SsJqP}{http://archive.is/SsJqP}}}
+in digital signal processing, \textsf{``}rank 4 tensors\textsf{''}\footnote{\texttt{\href{https://serc.carleton.edu/NAGTWorkshops/mineralogy/mineral_physics/tensors.html}{https://serc.carleton.edu/NAGTWorkshops/mineralogy/mineral\_physics/tensors.html}}}
+in calculations of elasticity of materials, \textsf{``}Lagrangians with non-holonomic
+constraints\textsf{''}\footnote{\texttt{\href{https://arxiv.org/abs/math/0008147}{https://arxiv.org/abs/math/0008147}}}
+in robotics, and the \textsf{``}Gibbs free energy\textsf{''} in chemical reactor design.\footnote{\texttt{\href{https://amzn.com/dp/1118368258}{https://amzn.com/dp/1118368258}}}
+
+To be sure, a significant part of what engineers do is not covered
+by any theory: the \emph{know-how}, the informal reasoning, the traditional
+knowledge passed on from expert to novice, \textemdash{} all those
+skills that are hard to formalize are important. Nevertheless, engineering
+is crucially based on natural science and mathematics for some of
+its decision-making about new designs.
+
+\addsec{Artisanship: Trades and crafts }
+
+Now consider what kinds of things shoemakers, plumbers, or home painters
+do, and what they have to learn in order to become proficient in their
+profession.
+
+A novice shoemaker, for example, begins by copying some drawings\footnote{\texttt{\href{https://youtu.be/cY5MY0czMAk?t=141}{https://youtu.be/cY5MY0czMAk?t=141}}}
+and goes on to cutting leather in a home workshop. Apprenticeships
+proceed via learning by doing, with comments and instruction from
+an expert. After a few years of study (for example, a painter apprenticeship
+in California can be as short as two years\footnote{\texttt{\href{http://www.calapprenticeship.org/programs/painter_apprenticeship.php}{http://www.calapprenticeship.org/programs/painter\_apprenticeship.php}}}),
+a new artisan is ready to start productive work.
+
+All trades operate entirely from tradition and practical experience.
+It takes a prolonged learning effort to become a good artisan in any
+profession. But the trades do not require academic study because there
+is no formal theory from which to proceed. There are no Fourier transforms
+applied to delta functions, no Lagrangians with non-holonomic constraints,
+no fourth rank tensors to calculate, nor any differential equations
+to solve.
+
+Artisans do not study science or mathematics because their professions
+do not make use of any formal theory for guiding their designs or
+processes.
+
+\addsec{Programmers today are artisans, not engineers }
+
+Programmers are \emph{not engineers} in the sense normally used in
+the engineering professions.
+
+\subsection*{No requirements of licensing or formal study}
+
+Mechanical, electrical, chemical engineers are required to pass a
+license exam to become certified to work. The license exam certifies
+that the person is proficient in applying a known set of engineering
+tools and methods. But in software engineering, no certifications
+or licenses are required for the job (although many certification
+programs exist).
+
+Working software engineers are also not required to have studied software
+engineering or computer science (CS). According to a recent Stack
+Overflow survey,\footnote{\texttt{\href{https://thenextweb.com/insider/2016/04/23/dont-need-go-college-anymore-programmer/}{https://thenextweb.com/insider/2016/04/23/dont-need-go-college-anymore-programmer/}}}
+about 56\% of working programmers have no CS degree. The author of
+this book is a self-taught programmer who has degrees in physics but
+never formally studied CS or taken any academic courses in algorithms,
+data structures, computer networks, compilers, programming languages,
+or other standard CS topics.
+
+A large fraction of successful programmers have no college degrees
+and perhaps \emph{never} studied formally. They acquired all their
+knowledge and skills through self-study and practical work. A prominent
+example is Robert C.~Martin\index{Robert C.~Martin},\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Robert_C._Martin}{https://en.wikipedia.org/wiki/Robert\_C.\_Martin}}}
+an outspoken guru in the arts of programming. He routinely refers
+to programmers as artisans\footnote{\texttt{\href{https://blog.cleancoder.com/uncle-bob/2013/02/01/The-Humble-Craftsman.html}{https://blog.cleancoder.com/uncle-bob/2013/02/01/The-Humble-Craftsman.html}}}
+and uses the appropriate imagery: novices and masters, trade and craft,
+the honor of the guild, etc. He compares programmers to plumbers,
+electricians, lawyers, and surgeons, but never to mathematicians,
+physicists, or engineers of any kind. According to one of his blog
+posts,\footnote{\texttt{\href{https://blog.cleancoder.com/uncle-bob/2013/11/25/Novices-Coda.html}{https://blog.cleancoder.com/uncle-bob/2013/11/25/Novices-Coda.html}}}
+he started working at age 17 as a self-taught programmer. He never
+went to college and holds no degrees.\footnote{\texttt{\href{https://hashnode.com/post/i-am-robert-c-martin-uncle-bob-ask-me-anything-cjr7pnh8g000k2cs18o5nhulp/2}{https://archive.is/MNlgT}}}
+It is clear that R.~C.~Martin \emph{is} an expert craftsman and
+that he did \emph{not} need academic study to master the craft of
+programming.
+
+Here is another opinion\footnote{\texttt{\href{http://archive.is/tAKQ3}{http://archive.is/tAKQ3}}}
+(emphasis is theirs):
+\begin{quotation}
+{\small{}Software Engineering is unique among the STEM careers in
+that it absolutely does }\emph{\small{}not}{\small{} require a college
+degree to be successful. It most certainly does not require licensing
+or certification. }\emph{\small{}It requires experience}{\small{}.}{\small\par}
+\end{quotation}
+This description fits a career in crafts \textemdash{} but certainly
+not a career, say, in electrical engineering.
+
+The high demand for software developers gave rise to \textsf{``}developer
+boot camps\textsf{''}\footnote{\texttt{\href{http://archive.is/GkOL9}{http://archive.is/GkOL9}}}
+\textemdash{} vocational schools that educate new programmers in a
+few months through purely practical training, with no formal theory
+or mathematics involved. These vocational schools are successful\footnote{\texttt{\href{http://archive.is/E9FXP}{http://archive.is/E9FXP}}}
+in job placement. But it is unimaginable that a $6$-month crash course
+or even a $2$-year vocational school could prepare engineers to work
+successfully on designing, say, analog quantum computers\footnote{\texttt{\href{https://www.dwavesys.com/quantum-computing}{https://www.dwavesys.com/quantum-computing}}}
+without ever learning quantum physics or calculus.
+
+\subsection*{No mathematical formalism guides software development}
+
+Most books on software engineering contain no formulas or equations,
+no mathematical derivations, and no precise definitions of the various
+technical terms they are using (such as \textsf{``}object-oriented\textsf{''} or \textsf{``}module\textsf{'}s
+responsibilities\textsf{''}). Some of those books\footnote{E.g., \texttt{\href{https://amzn.com/dp/0073376256}{https://amzn.com/dp/0073376256}}}
+also have almost no program code in them. Some of those books are
+written by practitioners such as R.\ C.\ Martin never studied any
+formalisms and do not think in terms of formalisms. Instead, they
+summarize their programming experience in vaguely formulated heuristic
+\textquotedblleft principles\textquotedblright .\footnote{\texttt{\href{https://blog.cleancoder.com/uncle-bob/2016/03/19/GivingUpOnTDD.html}{https://blog.cleancoder.com/uncle-bob/2016/03/19/GivingUpOnTDD.html}}}
+The programmers are told: \textsf{``}code is about detail\textsf{''}, \textsf{``}never abandon
+the big picture\textsf{''}, \textsf{``}avoid tight coupling in your modules\textsf{''}, \textsf{``}a
+class must serve a single responsibility\textsf{''}, \textsf{``}strive for good interfaces\textsf{''},
+etc.
+
+In contrast, textbooks on mechanical or electrical engineering include
+a significant amount of mathematics. The design of a microwave antenna
+is guided not by an \textsf{``}open and closed module principle\textsf{''} but by
+solving the relevant differential equations\footnote{\texttt{\href{https://youtu.be/8KpfVsJ5Jw4?t=447}{https://youtu.be/8KpfVsJ5Jw4?t=447}}}
+of electrodynamics.
+
+Another example of programmers\textsf{'} avoidance of mathematical tools is
+given by the \textsf{``}Liskov substitution principle\index{Liskov substitution principle}\textsf{''}
+for subtyping\index{subtyping}.\footnote{See \texttt{\href{https://en.wikipedia.org/wiki/Liskov_substitution_principle}{https://en.wikipedia.org/wiki/Liskov\_substitution\_principle}}.
+The LSP always holds in functional programming if values are immutable
+and subtyping is viewed as an automatic type conversion function (see
+Definition~\ref{subsec:Definition-subtyping}). A property $\phi(y)$
+is rewritten as $\phi(c(y))$ by inserting a suitable type conversion
+function, $c:S\rightarrow T$. Since $c(y)$ has type $T$ and $\phi(x)$
+holds for all values $x:T$, the property $\phi(c(y))$ holds automatically.} Its rigorous formulation (\textsf{``}for any property $\phi(x)$ that holds
+for all $x$ of type $T$, and for any subtype $S$ of $T$, the property
+$\phi(y)$ must also hold for all $y$ of type $S$\textsf{''}) is not used
+by programmers. Instead, the literature on object-oriented programming
+formulates the principle as \textsf{``}objects of type $T$ may be substituted
+by objects of type $S$ while keeping the correctness of the program\textsf{''}.
+This formulation \index{object-oriented programming} is both vague
+(it does not specify how to choose the substituted objects of type
+$S$) and, strictly speaking, incorrect: If the program contains a
+function $f(t)$ where $t$ is a value of type $T$, it is not always
+possible to find some value $s$ of type $S$ such that $f(s)=f(t)$.
+The reason is that some subtyping relations are not surjective, as
+shown in Section~\ref{subsec:Subtyping-with-injective} of this book.
+
+Donald Knuth\textsf{'}s classic textbook \textsf{``}\emph{The Art of Programming}\textsf{''}
+indeed treats programming as an art and not as a science. Knuth shows
+many algorithms and derives their mathematical properties but gives
+almost no examples of realistic program code and does not provide
+any theory that could guide programmers in actually \emph{writing}
+programs (say, choosing the data types to be used). Knuth assumes
+that the reader who understands the mathematical properties of an
+algorithm will be able \emph{somehow} to write correct code.
+
+The books \textsf{``}The Science of Programming\textsf{''}\footnote{\texttt{\href{https://amzn.com/dp/0387964800}{https://amzn.com/dp/0387964800}}}
+and \textsf{``}Program derivation\textsf{''}\footnote{\texttt{\href{https://amzn.com/dp/0201416247}{https://amzn.com/dp/0201416247}}}
+are attempts to provide a mathematical basis for writing programs
+starting from formal specifications. The books give some methods that
+guide programmers in writing code and at the same time produce a proof
+that the code conforms to the specification. However, the scope of
+proposed methods is limited to designing algorithms for iterative
+manipulation of data, such as sorting and searching algorithms. The
+procedures suggested in those books are far from a formal mathematical
+\emph{derivation} of a wide range of software programs from specifications.
+In any case, most programmers today are unaware of these books and
+do not use the methods explained there, even when those methods could
+apply.
+
+Today\textsf{'}s computer science courses do not teach a true engineering approach
+to software construction. Some courses teach analysis of programs
+using mathematical methods. Two such methods are complexity analysis\footnote{\texttt{\href{https://www.cs.cmu.edu/~adamchik/15-121/lectures/Algorithmic\%20Complexity/complexity.html}{https://archive.is/6D796}}}
+(the \textsf{``}big-$O$ notation\textsf{''}) and formal verification.\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Formal_verification}{https://en.wikipedia.org/wiki/Formal\_verification}}}
+But programs are analyzed or verified only \emph{after} they are somehow
+written. Theory does not guide the actual \emph{process} of writing
+code: it does not define good ways of organizing the code (e.g., how
+to decompose the code into modules, classes, or functions) and does
+not tell programmers which data structures and type signatures of
+functions will be useful to implement. Programmers make these design
+decisions on the basis of experience and intuition, trial-and-error,
+copy-paste, guesswork, and debugging.
+
+In a sense, program analysis and verification is analogous to writing
+mathematical equations for the surface of a shoe made by a fashion
+designer. The resulting \textsf{``}shoe equations\textsf{''} are mathematically rigorous
+and can be analyzed or \textsf{``}verified\textsf{''}. But the equations are merely
+written after the fact, they do not guide the fashion designers in
+actually making shoes. It is understandable that fashion designers
+do not study the mathematical theory of surfaces.
+
+\subsection*{Programmers avoid academic terminology }
+
+Programmers jokingly grumble about terms such as \textsf{``}functor\textsf{''} and
+\textsf{``}monad\textsf{''}:
+\begin{quote}
+{\small{}Those fancy words used by functional programmers purists
+really annoy me. Monads, functors... Nonsense!!! }\footnote{\texttt{\href{http://archive.is/65K3D}{http://archive.is/65K3D}}}
+\end{quote}
+Perhaps only a small minority of software developers complain about
+this, as the majority seems to be unaware of \textsf{``}applicative functors\textsf{''},
+\textsf{``}free monads\textsf{''}, and other arcane terminology. Indeed, that sort
+of terminology is intentionally avoided by most books and tutorials
+aimed at programmers.\footnote{For example, the recent book \textsf{``}Grokking functional programming\textsf{''}
+\emph{never} mentions \textsf{``}functors\textsf{''} or \textsf{``}monads\textsf{''}. See \texttt{\href{https://www.manning.com/books/grokking-functional-programming}{https://www.manning.com/books/grokking-functional-programming}}}
+
+But why would an \emph{engineer} wince at \textsf{``}functors\textsf{''} or at \textsf{``}free
+monads\textsf{''}? Other branches of engineering use lots of terminology that
+is far from self-explanatory and requires some study. Chemical engineers
+learn about \textsf{``}Gibbs free energy\textsf{''}, which is a technical term that
+denotes a certain function. (It\index{jokes} does not mean getting
+energy from J.~W.~Gibbs\index{Josiah Willard Gibbs} for free!)
+Chemical engineers accept the need for studying \textsf{``}phase diagrams\textsf{''}
+and \textsf{``}Fourier\textsf{'}s law\textsf{''}. Mechanical engineers take it for granted
+that they have to work with \textsf{``}rank 4 tensors\textsf{''}, \textsf{``}Lagrangians\textsf{''},
+and \textsf{``}non-holonomic constraints\textsf{''}. Electrical engineers do not avoid
+\textsf{``}Fourier transforms\textsf{''} or \textsf{``}delta functions\textsf{''} just because those
+are weird things to say. The arcane terminology seems to be the least
+of their difficulties, as their textbooks are full of complicated
+equations and long derivations.
+
+Textbooks on true software engineering would have been full of equations
+and derivations, teaching engineers how to perform certain calculations
+that are required \emph{before} starting to write code.
+
+\addsec{Towards true engineering in software}
+
+It is now clear that we do not presently have true software engineering.
+The people employed under that job title are actually artisans. They
+work using artisanal methods, and their education and design processes
+are typical of a crafts guild.
+
+True software engineering means having a mathematical theory that
+guides the process of writing programs, \textemdash{} not just theory
+that describes or analyzes programs after they are \emph{somehow}
+written.
+
+It is not enough that the numerical methods required for physics or
+the matrix calculations required for data science are \textsf{``}mathematical\textsf{''}.
+These programming tasks are indeed formulated using mathematical theory.
+However, mathematical \emph{subject matter} (aerospace control, physics
+simulations, or statistics) does not mean that mathematics is used
+to guide the process of writing code. Data scientists, aerospace engineers,
+and physicists almost always work as artisans when converting their
+computations into program code.
+
+We expect that software engineers\textsf{'} textbooks should be full
+of equations and derivations. What theory would those equations represent?
+
+This theory is what this book calls \textbf{applied functional type
+theory}\index{applied functional type theory} (see Chapter~\ref{chap:Applied-functional-type}).
+It represents the mathematical foundation of the modern practice of
+functional programming, as implemented in languages such as OCaml,
+Haskell, and Scala. This theory is a blend of set theory, category
+theory, and logical proof theory, adapted for the needs of programmers.
+It has been in development since late 1990s and is still being actively
+worked on by a community of software practitioners and academic computer
+scientists.
+
+To appreciate that functional programming, unlike other paradigms,
+is based on a \emph{theory that guides coding}, we can look at some
+recent software engineering conferences such as \textsf{``}Scala By the Bay\textsf{''}\footnote{\texttt{\href{http://2015.scala.bythebay.io/}{http://2015.scala.bythebay.io/}}}
+or BayHac,\footnote{\texttt{\href{http://bayhac.org/}{http://bayhac.org/}}}
+or at the numerous FP-related online tutorials and blogs. We cannot
+fail to notice that speakers devote significant time to a peculiar
+kind of applied mathematical reasoning. Rather than focusing on one
+or another API or algorithm, as it is often the case with other software
+engineering blogs or presentations, an FP speaker describes a \emph{mathematical
+structure} \textemdash{} such as the \textsf{``}applicative functor\textsf{''}\footnote{\texttt{\href{http://www.youtube.com/watch?v=bmIxIslimVY}{http://www.youtube.com/watch?v=bmIxIslimVY}}}
+or the \textsf{``}free monad\textsf{''}\footnote{\texttt{\href{http://www.youtube.com/watch?v=U0lK0hnbc4U}{http://www.youtube.com/watch?v=U0lK0hnbc4U}}}
+\textemdash{} and illustrates its use for practical coding.
+
+These people are not graduate students showing off their theoretical
+research. They are practitioners, software engineers who use FP on
+their jobs. It is just the nature of FP that certain mathematical
+tools and constructions are directly applicable to practical programming
+tasks.
+
+These mathematical tools are not mere tricks for a specific programming
+language; they apply equally to all FP languages. Before starting
+to write code, the programmer can jot down certain calculations in
+a mathematical notation (see Fig.\ \ref{fig:Example-calculation-in-type-theory}).
+The results of those calculations will help design the code fragment
+the programmer is about to write. This activity is similar to that
+of an engineer who performs some mathematical calculations before
+embarking on a design project.
+
+\begin{figure}
+\begin{centering}
+{\footnotesize{}\includegraphics[width=0.6\linewidth]{ftt-example}}{\footnotesize\par}
+\par\end{centering}
+\caption{An imaginary programmer performs a derivation before writing Haskell
+code.\label{fig:Example-calculation-in-type-theory}}
+
+\end{figure}
+
+A recent example of a development in applied functional type theory
+is the \textsf{``}free applicative functor\textsf{''} construction. It was first described
+in a 2014 paper;\footnote{\texttt{\href{https://arxiv.org/pdf/1403.0749.pdf}{https://arxiv.org/pdf/1403.0749.pdf}}}
+a couple of years later, a combined free applicative / free monad
+data type was designed and its implementation proposed in Scala\footnote{\texttt{\href{https://github.com/typelevel/cats/issues/983}{https://github.com/typelevel/cats/issues/983}}}
+as well as in Haskell.\footnote{\texttt{\href{https://elvishjerricco.github.io/2016/04/08/applicative-effects-in-free-monads.html}{https://archive.is/kwD2a}}}
+This technique allows programmers to implement declarative side-effect
+computations where some parts are sequential but other parts are computed
+in parallel, and to achieve the parallelism \emph{automatically} while
+maintaining the composability of the resulting programs. The new technique
+has advantages over monad transformers, which was a previously known
+method of composing declarative side-effects. The combined \textsf{``}free
+applicative / free monad\textsf{''} code was designed and implemented by true
+software engineers. They first derived the type constructor that has
+the necessary algebraic properties. Guided by the resulting type formula,
+they wrote code that was guaranteed to work as intended.
+
+Another example of using applied functional type theory is the \textsf{``}\index{tagless final}tagless
+final\textsf{''} encoding of effects, first described\footnote{\texttt{\href{http://okmij.org/ftp/tagless-final/index.html}{http://okmij.org/ftp/tagless-final/index.html}}}
+in 2009. That technique (called \textsf{``}Church-encoded free monad\index{free monad}\textsf{''}
+in the present book) has advantages over the ordinary free monad in
+a number of cases \textemdash{} just as the free monad itself was
+used to cure certain problems with monad transformers.\footnote{\texttt{\href{http://blog.ezyang.com/2013/09/if-youre-using-lift-youre-doing-it-wrong-probably/}{http://blog.ezyang.com/2013/09/if-youre-using-lift-youre-doing-it-wrong-probably/}}}
+The new encoding is not tied to a specific programming language. Rather,
+it is a language-agnostic construction that was originally described
+in OCaml and later used in Haskell and Scala, but can be made to work
+even in Java,\footnote{\texttt{\href{https://oleksandrmanzyuk.wordpress.com/2014/06/18/}{https://oleksandrmanzyuk.wordpress.com/2014/06/18/}}}
+which is not an FP language.
+
+This example shows that we may need several more years of work before
+the practical aspects of using applied functional type theory are
+sufficiently well understood by the FP community. The theory is in
+active development, and its design patterns \textemdash{} as well
+as the exact scope of the requisite theoretical material \textemdash{}
+are still being figured out. If the 40-year gap hypothesis\footnote{\texttt{\href{https://www.linkedin.com/pulse/40-year-gap-what-has-academic-computer-science-ever-done-winitzki}{https://archive.is/kVYYt}}}
+holds, we should expect applied functional type theory (perhaps under
+a different name) to become mainstream by 2030. This book is a step
+towards a clear designation of the scope of that theory.
+
+\addsec{Does software need engineers, or are artisans sufficient? }
+
+The demand for programmers is growing. \textsf{``}Software developer\textsf{''} was
+\#1 best job\footnote{\texttt{\href{http://money.usnews.com/money/careers/articles/how-us-news-ranks-the-best-jobs}{http://money.usnews.com/money/careers/articles/how-us-news-ranks-the-best-jobs}}}
+in the US in 2018. But is there a demand for engineers or just for
+artisans?
+
+We do not seem to be able to train enough software artisans.\footnote{\texttt{\href{http://archive.is/137b8}{http://archive.is/137b8}}}
+So, it is probably impossible to train as many software engineers
+in the true sense of the word. Modern computer science courses do
+not actually train engineers in that sense. Instead, they train academic
+researchers who can also work as software artisans and write code.
+
+Looking at the situation in construction business in the U.S.A., we
+find that it employs about $10$ times more construction workers as
+architects. We might conclude that perhaps one software engineer is
+required per dozen software artisans.
+
+What is the price of \emph{not} having engineers, of replacing them
+with artisans?
+
+Software practitioners have long bemoaned the permanent state of \textsf{``}crisis\textsf{''}
+in software development. Code \textsf{``}rots with time\textsf{''}, its complexity
+grows \textsf{``}out of control\textsf{''}, and operating systems have been notorious
+for constantly appearing new security flaws\footnote{\texttt{\href{http://archive.fo/HtQzw}{http://archive.fo/HtQzw}}}
+despite many thousands of programmers and testers employed. It appears
+that the growing complexity of software tends to overwhelm the capacity
+of the human brain for correct \emph{artisanal} programming.
+
+It is precisely in designing large and robust software systems that
+we would benefit from true engineering. Artisans has been building
+bridges and using chemical reactions by trial and error and via tradition,
+long before mechanical or chemical engineering disciplines were developed
+and founded upon rigorous theory. But once the theory became available,
+engineers were able to design unimaginably more powerful and complicated
+structures, devices, and processes. So, we may expect that trial,
+error, and adherence to tradition is inadequate for some of the more
+complex software development tasks in front of us.
+
+To build large and reliable software, such as new mobile or embedded
+operating systems or distributed peer-to-peer trust architectures,
+we will most likely need the qualitative increase in productivity
+and reliability that can only come from replacing artisanal programming
+by a true engineering discipline. Applied functional type theory and
+functional programming are steps in that direction.
+
+\addchap{Essay: Declarative programming as a silver bullet}
+
+The main difficulty of software engineering is that programs tend
+to grow in size and to become progressively less understandable. As
+a result, bugs become hard or impossible to avoid as programmers need
+to add new features.
+
+Initially, the paradigm of structural programming was supposed to
+solve this problem. A famous paper, \textsf{``}No silver bullet\textsf{''},\footnote{\texttt{\href{https://en.wikipedia.org/wiki/No_Silver_Bullet}{https://en.wikipedia.org/wiki/No\_Silver\_Bullet}}}
+rejected that view while at the same time doing little more than bemoaning
+the mysterious difficulty of writing correct programs. Brooks blamed
+it on the \textsf{``}inherent complexity\textsf{''} somehow present in all software
+engineering because the domain problems being solved are complex.
+Since then, people have claimed that object-oriented programming\footnote{\texttt{\href{http://www.drdobbs.com/there-is-a-silver-bullet/184407534}{http://www.drdobbs.com/there-is-a-silver-bullet/184407534}}}
+or functional programming\footnote{\texttt{\href{http://archive.li/TE9iB}{http://archive.li/TE9iB}}}
+are solutions to this difficulty; namely, that they will increase
+productivity by order of magnitude while avoiding bugs. Many people
+immediately stepped in to say that functional programming languages
+\textemdash{} Lisp, Haskell, and such \textemdash{} are not a silver
+bullet.\footnote{\texttt{\href{https://www.slideshare.net/nashjain/no-silver-bullets-in-functional-programming-by-brian-mckenna}{https://archive.is/pA1hz}}}
+
+I think we actually do have a silver bullet, hiding in plain sight.
+But rather than trying to argue from philosophical reasons, I would
+like to look at practical results. What are historical examples where
+a great increase in programmer productivity has been achieved by introducing
+some new paradigm that proved sufficiently useful for most programming
+languages to have adopted it later on?
+
+After describing these past innovations, or \textsf{``}silver bullets\textsf{''},
+we will be able to distill an underlying principle that drives the
+productivity advantage. That principle is what I call declarative
+programming.
+
+\addsec{The silver bullets we know and love}
+
+Perhaps the first real silver bullet (after Alan Turing invented the
+subroutine and the stack frame\footnote{\texttt{\href{https://people.cs.clemson.edu/~mark/subroutines.html}{https://people.cs.clemson.edu/$\sim$mark/subroutines.html}}})
+came as one of the features of the Fortran language. That feature
+of Fortran (that still survives in virtually all programming languages
+today) is the math-like syntax for arithmetic expressions. With Fortran,
+for the first time, the programmer could write a formula such as \lstinline!A = B * C - SQRT(D)!
+and the computer would generate all the necessary machine codes for
+computing that arithmetical expression. Before this innovation, programmers
+would have to write out all the required elementary operations and
+intermediate results in full, using machine instructions that corresponded
+to the following sequence of actions:
+\begin{lyxcode}
+allocate~memory~1~(intended~for~A)
+
+allocate~memory~2~(intended~for~B~{*}~C)
+
+put~B~into~memory~2
+
+multiply~memory~2~with~C~and~put~result~into~memory~2
+
+allocate~memory~3~(intended~for~SQRT(D))
+
+copy~register~0~into~memory~3~(to~save~it~for~later)
+
+put~D~into~register~0
+
+call~subroutine~SQRT~(expecting~result~again~in~register~0)
+
+swap~register~0~and~memory~3~(now~restoring~old~register~0)
+
+flip~sign~of~value~in~memory~3~(now~have~-SQRT(D)~in~memory~3)
+
+add~memory~2~to~memory~3~and~put~result~into~memory~2
+
+copy~memory~2~into~register~0
+
+free~memory~2
+
+free~memory~3
+
+free~memory~1
+
+return
+\end{lyxcode}
+Instead of this quite tedious and error-prone sequence of instructions,
+Fortran programmers could simply write \lstinline!A = B * C - SQRT(D)!.
+The order-of-magnitude productivity increase is obvious from this
+example.
+
+After Fortran, the LISP language enabled programmers to write recursive
+computations on lists and trees quite easily. These kinds of computations
+are important in two areas of computer science: compilers and strategy
+games. Implementing a backtracking search without a direct access
+to recursive data structures is a difficult and error-prone task.
+Most programming languages today support recursive data structures
+and recursive functions.
+
+Another innovation was in the Prolog language. Prolog implemented
+a backtracking search as a built-in feature that the programmer does
+not even need to mention explicitly. A Prolog program only needs to
+declare the logical relationships that define the search space. The
+program may also specify shortcuts or speedups, to make the backtracking
+search run more efficiently. Prolog, however, did not find a lot of
+use outside the European artificial intelligence community of 1970\textendash 1980s.
+Its best area of application (expert systems) has had its heyday and
+is now a distant memory.
+
+Nevertheless, the legacy of Prolog is alive and well in the form of
+SQL, the relational database language. SQL simplified Prolog by removing
+recursion, which made complicated search algorithms unnecessary, and
+instead added various convenience features to support table-driven
+accounting and reporting tasks. SQL is still a cornerstone of industrial
+data processing today.
+
+Object-oriented programming was initially intended, as in the SIMULA
+language, for simulation of real-time interactions between systems.
+It was thought that people would simply imagine how real-world objects
+interact by sending each other requests or data, and transcribe that
+picture into code. Later, it was argued that OOP is especially suitable
+for developing a powerful graphical user interface, called OOUI.\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Object-oriented_user_interface}{https://en.wikipedia.org/wiki/Object-oriented\_user\_interface}}}
+Many programming languages today include some object-oriented features.
+
+Functional programming languages started with Standard ML, which was
+a language for programming a mathematical proof assistant. Languages
+later developed in the spirit of Standard ML, such as OCaml and Haskell,
+were mostly used for writing compilers and verified code. However,
+basic features of Standard ML \textemdash{} immutable polynomial data
+types, pattern-matching, higher-order functions, and parametric polymorphism
+with a static type inference \textemdash{} have become standard, so
+that many new languages, such as F\#, Scala, Swift, and Rust, include
+them, while older languages (Java, C\#, Python) have also added some
+of these features.
+
+\addsec{What is \textquotedblleft declarative programming\textquotedblright}
+
+I first encountered the concept of \textsf{``}declarative programming\textsf{''} when
+I started studying Haskell and then Prolog. Both languages are claimed
+up front to be declarative, as opposed to imperative languages such
+as C++ or Java. It was confusing, however, that two languages that
+are so different can be both deemed declarative. It was also clear
+that Prolog would be quite awkward for, say, numerical calculations,
+while Haskell would require a lot of hard-to-read, imperative code
+for tasks such as downloading a file from a Web server. The book \textsf{``}Real
+World Haskell\textsf{''}\footnote{\texttt{\href{https://amzn.com/dp/B0026OR2FY}{https://amzn.com/dp/B0026OR2FY}}}
+shows some examples.\texttt{}\footnote{\texttt{\href{http://book.realworldhaskell.org/read/extended-example-web-client-programming.html}{http://book.realworldhaskell.org/read/extended-example-web-client-programming.html}}}
+
+So I then tried to understand what people mean by declarative programming.
+The Wikipedia definition\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Declarative_programming}{https://en.wikipedia.org/wiki/Declarative\_programming}}}
+essentially says that declarative is \textsf{``}not imperative\textsf{''}, and yet
+that definition is so vague that one could easily claim that Haskell
+is imperative while Visual Basic is declarative. Essentially, \textsf{``}declarative\textsf{''}
+is understood as a feature of a programming language as a whole, and
+any programming language could be argued to be either \textsf{``}declarative\textsf{''}
+or not.
+
+I was never satisfied with this definition and kept thinking about
+this question until I found a better definition, which I will explain
+now.
+
+The common pattern among all the \textsf{``}silver bullet\textsf{''} paradigms is
+that 1) they were supposed to make programs very concise and easily
+readable when written for a specific and narrowly delineated problem
+domain, 2) they came with a new programming language designed specifically
+for that domain. Fortran was designed as a language for numerical
+mathematics; Prolog as a language for rule-based expert systems; and
+so on. One could plausibly argue that Fortran was as well adapted
+to programming numerical expressions as Prolog to expert systems or
+Haskell to compilers.
+
+An important consequence is that the same languages were not suitable
+for other problem domains! Prolog was not easily suitable for matrix
+multiplication, nor Fortran for expert systems, nor Haskell for GUI
+programs.
+
+Therefore, \textsf{``}declarativeness\textsf{''} is not really a property of a programming
+language, but a \emph{relation} between a programming language and
+a problem domain. A language can be declarative for one specific problem
+domain but not for another.
+
+The second important consequence is that a program in a \textsf{``}declarative\textsf{''}
+language must be something that is clearly understandable to humans.
+For example, the expression \lstinline!A = B * C - SQRT(D)! is unambiguous,
+and its intent and effect are clear at first sight. This is because
+the program closely resembles what a person would write on paper in
+order to describe the required task. Similarly, Prolog programs look
+like declarations of facts and logical relations between facts or
+properties of some symbols. This is again very close to something
+that a human would write informally on paper when describing a particular
+task or problem.
+
+Here is an example showing how Prolog is adapted to tasks involving
+logical relations. Consider the following logic puzzle:
+\begin{quotation}
+All jumping creatures are green. All small jumping creatures are martians.
+All green martians are intelligent. \noun{Ngtrks} is small and green.
+\noun{Pgvdrk} is a jumping martian. Who is intelligent? \emph{(Inspired
+by the short story \textsf{``}Invasion from Aldebaran\textsf{''}}\footnote{\texttt{\href{https://de.wikipedia.org/wiki/Invasion_vom_Aldebaran}{https://de.wikipedia.org/wiki/Invasion\_vom\_Aldebaran}}}\emph{
+by S.~Lem.)}
+\end{quotation}
+The following is the complete code of the Prolog program that solves
+this puzzle, together with an example execution command using SWI-Prolog:
+\begin{lstlisting}[language=bash]
+$ cat > martians.pl
+small(ngtrks). green(ngtrks).
+martian(pgvdrk). jumping(pgvdrk).
+green(X) :- jumping(X).
+martian(X) :- small(X), jumping(X).
+intelligent(X) :- green(X), martian(X).
+
+main :- intelligent(X), format('~w is intelligent.~n', X), halt.
+^D
+$ swipl -o martians -q -t main -c martians.pl
+$ ./martians
+pgvdrk is intelligent.
+\end{lstlisting}
+We could mechanically rewrite this code and replace Prolog predicates
+such as \lstinline!green(X)! by phrases such as \textsf{``}\lstinline!X!
+is green\textsf{''}, the Prolog operator \lstinline!:-! by the word \textsf{``}when\textsf{''},
+and the comma (\lstinline!,!) by the word \textsf{``}and\textsf{''}. Then we would
+find that the program code closely resembles the English-language
+description of the puzzle. In this sense, Prolog programs can be viewed
+as \textsf{``}executable specifications\textsf{''} for logic puzzles.
+
+However, writing a matrix multiplication program in Prolog would require
+code that is far removed from any human-readable specification or
+mathematical notation.\footnote{See, e.g., \texttt{\href{https://stackoverflow.com/questions/55687499}{https://stackoverflow.com/questions/55687499}}}
+It is clear that Prolog is \emph{not} declarative for numerical calculations.
+
+As an illustration of why Haskell is declarative for recursive data
+structures, consider this excerpt from the book \textsf{``}Algorithms in C\textsf{''}\footnote{\texttt{\href{https://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structures/dp/0201314525}{https://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structures/dp/0201314525}}}
+and its almost mechanical translation into Haskell code:
+\begin{quotation}
+\textbf{Definition 5.1} A binary tree is either an external node or
+an internal node connected to a pair of binary trees, which are called
+the left subtree and the right subtree of that node.
+\end{quotation}
+\begin{lstlisting}[language=Haskell]
+data BTree a = BTNode a | BTVertex (BTree a) (BTree a)
+\end{lstlisting}
+
+\begin{quotation}
+\textbf{Definition 5.6} The level of a node in a tree is one higher
+than the level of its parent (with the root at level 0). The height
+of a tree is the maximum of the levels of the tree\textsf{'}s nodes.
+\end{quotation}
+\begin{lstlisting}[language=Haskell]
+heightOf :: BTree a -> Int
+heightOf (BTNode _) = 0
+heightOf (BTVertex left right) = 1 + max (heightOf left) (heightOf right)
+\end{lstlisting}
+
+These code snippets suggest that Haskell is declarative for the problem
+domain of manipulating tree-like data structures via recursive algorithms.
+Object-oriented implementations of these algorithms in C++ or Java
+require significantly more code, and the code will not syntactically
+resemble the specification.
+
+By looking at the \textsf{``}silver bullet\textsf{''} examples, we can now formulate
+the principle of declarative programming:
+\begin{quote}
+\emph{A program is declarative if it syntactically resembles a human-written
+specification of the required task, expressed in a commonly used specification
+language. }
+\end{quote}
+It follows that the concept of \textsf{``}declarative programming\textsf{''} is actually
+still narrower than a relation between a language and a problem domain.
+Given the same programming language, a program for the same problem
+domain can be written in different ways. Some of these equivalent
+programs will be non-declarative if they do not closely resemble a
+human-readable specification of the task.
+
+A programming language is \textbf{declarative for a chosen problem
+domain} if it allows us to write declarative programs for that domain.
+Declarative programs are executable but still human-readable specifications,
+written within the syntactic conventions of a specific programming
+language.
+
+\addsec{The problem of choosing a specification language}
+
+A key question remains: what exactly is a \textsf{``}human-readable specification\textsf{''}?
+Again, we need to look at known history to understand what specification
+languages people have been using to communicate tasks in various problem
+domains.
+
+Mathematicians have spent millennia developing adequate notation for
+the various tasks relating to numerical calculations and logical abstractions.
+Writing the expression $A=B\cdot C-\sqrt{D}$ or the corresponding
+code \lstinline!A = B * C - SQRT(D)! is as clear and unambiguous
+as it gets when we want to talk about numerical formulas. We do not
+know if another, \textsf{``}better\textsf{''} mathematical notation exists; but the
+one we have today seems to work well enough.
+
+Each domain where humans have developed sophisticated artifacts, such
+as music, linguistics, technical drafting, and so on, has its own
+specialized notation. These notations do not all have the same level
+of formality or expressivity. For instance, the International Phonetic
+Alphabet\footnote{\texttt{\href{https://en.wikipedia.org/wiki/International_Phonetic_Alphabet}{https://en.wikipedia.org/wiki/International\_Phonetic\_Alphabet}}}
+denotes pronunciation rather precisely, but there seems to be no accepted
+specification language that could denote unambiguously all the richness
+of the expressive intonation people use when actually talking.
+
+It is safe to say that the task of developing a \textsf{``}good\textsf{''} notation
+\textemdash{} i.e., an unambiguous, expressive, and yet readable specification
+language \textemdash{} for a given problem domain is an extremely
+difficult task that may take a long time for newer problem domains.
+The main reason for the difficulty is that a successful specification
+language must be somehow convenient for human practitioners (whose
+detailed behavior, to date, has evaded a formal description). A person
+reading a description of a task in a good specification language must
+be able to understand the task quickly and should have no further
+questions or ambiguities to clarify.
+
+It is precisely in areas where the specification language is well
+understood (for example: mathematical formulas, formal grammars, relational
+logic) that the development of a declarative programming language
+produced an order of magnitude increase in productivity. In all those
+cases, the programming language syntactically reproduces the specification
+language and, in this sense, makes the specifications \textsf{``}executable\textsf{''}.
+However, blind attempts to use the same language for other problem
+domains did not bring any advantages. The widely expressed disappointment
+with structural programming, with OOP, or with functional programming
+is probably due to the fact that people expected a \textsf{``}declarativeness\textsf{''}
+in one domain to transfer to advantages in all other problem domains.
+But this does not seem to be the case with any of the attempts so
+far. Different problem domains are incompatible and require quite
+different specification languages.
+
+Without an accepted specification language, there is no hope of reaping
+the full benefits of declarative programming. One domain where a specification
+language seems to be currently lacking is the visual logic of GUI
+applications. Several approaches \textemdash{} from business process
+management formalisms to temporal logic \textemdash{} have been tried,
+but so far no consensus emerged that any of those notations is truly
+declarative, \textemdash{} that is, unambiguously expressive and at
+the same time readily understandable to humans. When people design
+GUIs, they communicate their designs to each other informally and
+in multiple stages, gradually resolving the inevitable ambiguities.
+(\textquotedbl And what if I now press this button in that window
+while the old message box is still visible?\textquotedbl ) As a result,
+GUI programming remains a difficult and error-prone exercise. Established
+GUI environments (X Window, MS Windows, macOS, iOS, Android) predominantly
+use the object-oriented paradigm, which turned out to be not a silver
+bullet for complex GUI design. Accordingly, programming a GUI application
+in these environments is a messy and painful affair (I am speaking
+from first-hand experience). Newer developments based on functional
+reactive programming are more promising but yet to be proven declarative,
+since no adequate specification language has emerged as yet in that
+area.
+
+\addsec{How to use the silver bullet today: make your own DSL}
+
+In the 1980s, 1990s, and 2000s, many companies (including IBM, Microsoft,
+Sun, Apple, SAP, Bloomberg, and Workday) invented their own programming
+languages adapted to their respective business domains. The idea was
+that a specialized programming language would be necessary to serve
+their specific business. I think their intuition was that not merely
+that existing programming languages were not well adapted for business
+applications, but also that the newly designed programming languages
+would be made declarative for those domains. However, those companies
+most likely did not have a precise definition of their specification
+languages or problem domains before designing their new languages,
+which thus did not necessarily achieve the goal of being declarative.
+
+Suppose you know the specification language of your problem domain,
+and you would like to create a language adapted to that domain, i.e.,
+a domain-specific language (DSL). It takes a great deal of work to
+create and support an entirely new programming language. The return
+on the investment is relatively small.
+
+A better approach is to implement your DSL as a library in an established
+programming language (the \textsf{``}host\textsf{''} language). This produces a so-called
+embedded DSL (EDSL). The EDSL does not need to be particularly complicated
+or extensive. Its goal is to fit your problem domain so that you can
+express specifications for your tasks syntactically, more or less
+as you would tell them to a fellow human.
+
+The immediate next question is to identify programming languages that
+allow us to easily implement domain-specific languages. Several language
+features seem to be required of a good \textsf{``}DSL-friendly\textsf{''} host language.
+One is the ability to redefine the meaning of existing operations,
+to fit the human-readable specification language. For example, we
+might want to redefine (\textsf{``}overload\textsf{''}) the multiplication operator
+(\lstinline!*!) so that \lstinline!m * n! would mean the matrix
+multiplication when \lstinline!m! and \lstinline!n! are matrices.
+C++, Python, Haskell, and Scala support operator overloading, but
+Java and JavaScript do not.
+
+Another useful feature would be the ability to make syntax shorter
+and more easily understandable. For example, the \lstinline!scalatest!
+library for Scala defines syntax that allows programmers to write
+test conditions resembling English sentences, such as:
+\begin{lstlisting}
+a + b should be > 0
+\end{lstlisting}
+This code is more easily readable than an equivalent Java syntax:
+\begin{lstlisting}
+(a + b).should().be().greaterThan(0)
+\end{lstlisting}
+
+Another DSL-friendly feature is the ability to generate or transform
+programs at compile time. For instance, a database DSL could read
+the database schema at compile time and generate the data access layer
+code, freeing the programmer from the tedious mechanical task of writing
+and updating the code each time the schema is revised. If a host language
+supports these features, a programmer can easily implement their own
+little DSL adapted specifically to the problem domain at hand, without
+modifying the host language\textsf{'}s compiler or creating an entirely new
+programming language.
+
+Finally, a DSL is hard to use if it is \textsf{``}brittle\textsf{''}, \textemdash{}
+that is, permitting users to easily write correct-looking but buggy
+programs. The key to assuring correctness is to be able to verify,
+preferably at compile time (but in any case early in the development
+cycle), that the user\textsf{'}s DSL program is consistent within the intended
+meaning of the DSL. For instance, if the DSL allows us to multiply
+matrices by writing \lstinline!m * n!, we should not be able to write
+\lstinline!m * n! by mistake when \lstinline!n! is a telephone number
+rather than a matrix, only to discover the error much later when the
+code is running in production. The host language must have a tight
+control over the abstractions behind the DSL.
+
+Because of the importance of DSL-friendly features, some programming
+languages are more suitable to building DSLs than others. In particular,
+Scala and Haskell have outstanding abilities to redefine syntax, prevent
+user mistakes, perform compile-time code generation or transformation,
+and hide complexity behind tightly controlled abstractions, \textemdash{}
+all without modifying the existing compiler or tooling. For this reason,
+it is much easier to create custom DSLs in Scala and Haskell than
+in most other programming languages.
+
+\addsec{Conclusion}
+
+Declarative programs are executable specifications. Thanks to the
+development of modern programming languages such as Scala and Haskell,
+the silver bullet is in our hands today. Just follow these easy steps
+and you will slay the software werewolf!
+\begin{enumerate}
+\item Discover or develop a good specification language for your problem
+domain. The specification language should be unambiguously expressive,
+complete for the problem domain, pragmatically convenient, and yet
+human-readable. It should be obvious at first reading that the specification
+says exactly what we intend to do.
+\item Learn Scala and/or Haskell.
+\item Implement the specification language syntactically as a DSL in a chosen
+host language. Iterate on the language as necessary to support your
+problem domain.
+\item If you have different problem domains in the same project, do not
+mix different DSLs into one uber-language; this has proven to be counterproductive.
+It is best to keep DSLs separate and independent.
+\end{enumerate}
+
diff --git a/sofp-src/tex/sofp-essay3.tex b/sofp-src/tex/sofp-essay3.tex
new file mode 100644
index 000000000..482dcc6dd
--- /dev/null
+++ b/sofp-src/tex/sofp-essay3.tex
@@ -0,0 +1,739 @@
+
+\addchap{\textquotedblleft Applied functional type theory\textquotedblright :
+A proposal\label{chap:Applied-functional-type}}
+
+What exactly is the extent of \textsf{``}theory\textsf{''} that a software engineer
+should know in order to be a proficient functional programmer? This
+book proposes an answer to that question by presenting a coherent
+body of theoretical knowledge that, in the author\textsf{'}s view, \emph{is}
+the theory that underlies the practice of functional programming and
+guides software engineers in writing code. This body of knowledge
+may be viewed as a new emerging sub-branch of computer science, tentatively
+called \textbf{\index{applied functional type theory}applied functional
+type theory} (AFTT).
+
+In order to discover the proper scope of AFTT, this book appraises
+the various inventions made in the field of functional programming
+in the last 30 years, such as the \textquotedblleft functional pearls\textquotedblright{}
+papers\footnote{\texttt{\href{https://wiki.haskell.org/Research_papers/Functional_pearls}{https://wiki.haskell.org/Research\_papers/Functional\_pearls}}}
+and various online tutorials, looking for theoretical material that
+has demonstrated its pragmatic usefulness. As a first step towards
+formulating AFTT from the ground up, the results are presented in
+the form of a tutorial, with motivations and rigorous derivations
+of substantially all relevant mathematical facts.
+
+In this book, code examples are written in Scala because the author
+is fluent in that language. However, most of the material will work
+equally well in Haskell, OCaml, and other FP languages. This is because
+AFTT is the science of functional programming and not a set of tricks
+specific to Scala or Haskell. An advanced user of any functional programming
+language will have to face the same questions and struggle with the
+same practical issues.
+
+\addsec{AFTT is not covered by courses in computer science}
+
+Traditional courses of computer science (algorithms and data structures,
+complexity theory, distributed systems, databases, network systems,
+compilers, operating systems) are largely not relevant to AFTT. Courses
+in programming language theory are more relevant but are not presented
+at an appropriate level. To an academic computer scientist, the theory
+behind Haskell is \textsf{``}System $F\omega$\textsf{''}, a version of $\lambda$-calculus\index{System Fomega (Haskell)@System $F\omega$ (Haskell)}.\footnote{\texttt{\href{https://babel.ls.fi.upm.es/~pablo/Papers/Notes/f-fw.pdf}{https://babel.ls.fi.upm.es/$\sim$pablo/Papers/Notes/f-fw.pdf}}}
+That theory guided the design of the Haskell language and defines
+rigorously what a Haskell program means in a mathematical sense. The
+theory behind Scala is called the \textsf{``}DOT\textsf{''} (dependent object type)
+calculus.\footnote{\texttt{\href{https://www.scala-lang.org/blog/2016/02/03/essence-of-scala.html}{https://www.scala-lang.org/blog/2016/02/03/essence-of-scala.html}}}\index{dependent object type (DOT) calculus}
+That theory guided the design of Scala version 3.
+
+However, a practicing Haskell or Scala programmer is not concerned
+with designing Haskell or Scala, or with proving theoretical properties
+of those languages. Instead, the programmer is mainly concerned with
+\emph{using} a chosen programming language to write code.
+
+Knowing how to prove various properties of System $F\omega$ or DOT
+will not actually help programmers to write code. So, these theories
+are outside the scope of AFTT. The practice of functional programming
+does not require graduate-level theoretical studies.
+
+As an example of theoretical material that \emph{is} within the scope
+of AFTT, consider applicative functors (Chapter~\ref{chap:8-Applicative-functors,-contrafunctors}).\index{applicative functors}
+It is helpful for a practicing functional programmer to be able to
+recognize and use applicative functors. An applicative functor is
+a data structure specifying declaratively some operations that can
+run independently of each other. Programs may combine these operations,
+execute them in parallel, check for validity, or refactor for optimization
+or better maintainability.
+
+To use this functionality, the programmer must begin by checking whether
+a given data structure satisfies the laws of applicative functors.
+In a given application, the choice of a data structure may be dictated
+in part by the business logic. The programmer first writes down the
+type of that data structure and the code implementing the required
+methods. The programmer can then check whether the laws hold. The
+data structure and the code may need to be adjusted in order to fit
+the definition of an applicative functor and to make the laws hold.
+
+So, the programmer needs to perform a certain amount of symbolic derivations
+before coding. The derivations can be done using pen and paper by
+writing equations in a concise mathematical notation. Once the laws
+are verified, the programmer proceeds to write code.
+
+The mathematical proofs and derivations assure that the chosen data
+structure will satisfy the laws of applicative functors, no matter
+how the rest of the program is written. So, for example, it is assured
+that the relevant operations can be automatically parallelized and
+will still work correctly. In this way, AFTT directly guides the programmer
+and helps write correct code.
+
+Applicative functors were discovered by practitioners who were using
+Haskell to implement parser combinators for compilers. However, applicative
+functors are not a feature of Haskell. Rather, they are a design pattern
+that may be used in Scala or in any other functional programming language.
+A prominent example of an applicative functor is Apache Spark\textsf{'}s \lstinline!RDD!
+data type, which is widely used for implementing large-scale parallel
+computations.\footnote{\texttt{\href{https://spark.apache.org/docs/latest/rdd-programming-guide.html}{https://spark.apache.org/docs/latest/rdd-programming-guide.html}}}
+And yet, no standard computer science course or textbook defines applicative
+functors, motivates their laws, explores their structure on examples,
+or shows data types that are \emph{not} applicative functors (and
+explains why not).
+
+\addsec{AFTT is not category theory, type theory, or formal logic}
+
+One often hears that functional programming is based on category theory.\footnote{\texttt{\href{https://www.47deg.com/blog/science-behind-functional-programming/}{https://www.47deg.com/blog/science-behind-functional-programming/}}}
+Indeed, the material shown in this book includes a (small) number
+of notions from category theory, as well as from formal logic and
+type theory. However, software engineers would not benefit from traditional
+academic courses in those subjects: their presentation is too abstract
+and at the same time lacks specific results necessary for practical
+programming. Those courses answer questions that academic mathematicians
+have, not questions that practicing functional programmers have.
+
+There exist books intended as presentations of category theory for
+computer scientists\footnote{See, e.g., \texttt{\href{https://www.amazon.com/dp/0262660717}{https://www.amazon.com/dp/0262660717}}
+or \texttt{\href{https://www.math.mcgill.ca/triples/Barr-Wells-ctcs.pdf}{https://www.math.mcgill.ca/triples/Barr-Wells-ctcs.pdf}}} or for programmers.\footnote{\texttt{\href{https://github.com/hmemcpy/milewski-ctfp-pdf}{https://github.com/hmemcpy/milewski-ctfp-pdf}}}
+However, those books do not cover certain concepts relevant to programming,
+such as applicative\footnote{Applicative functors are known in mathematics as \textsf{``}monoidal\textsf{''}: \texttt{\href{https://en.wikipedia.org/wiki/Monoidal_functor}{https://en.wikipedia.org/wiki/Monoidal\_functor}}}
+or traversable functors. Instead, those books dwell on concepts (e.g.,
+limits, enriched categories, topoi) that have no applications in practical
+functional programming today.
+
+Typical questions in academic books are \textsf{``}Is $X$ an introduction
+rule or an elimination rule\textsf{''} and \textsf{``}Does property $Y$ hold in non-small
+categories or only in the category of sets\textsf{''}. Questions a Scala programmer
+might ask are \textsf{``}Can we compute a value of type \lstinline!Either[Z, R => A]!
+from a value of type \lstinline!R => Either[Z, A]!\textsf{''} and \textsf{``}Is the
+type constructor \lstinline!F[A] = Option[(A,A,A)]! a monad or only
+an applicative functor\textsf{''}. The scope of AFTT includes answering the
+last two questions but \emph{not} the first two.
+
+A software engineer hoping to understand the theory behind functional
+programming will not find the concepts of filterable, applicative,
+or traversable functors in any currently available books on category
+theory, including books intended for programmers. And yet these concepts
+are necessary for correct implementations of the important and widely
+used operations \lstinline!filter!, \lstinline!zip!, and \lstinline!fold!.
+
+To compensate for the lack of AFTT textbooks, programmers have written
+many online tutorials, aiming to explain the theoretical concepts
+necessary for practical work. The term \textsf{``}monad tutorial\textsf{''} became
+infamous because so many were posted online.\footnote{\texttt{\href{https://www.johndcook.com/blog/2014/03/03/monads-are-hard-because/}{https://www.johndcook.com/blog/2014/03/03/monads-are-hard-because/}}}
+Tutorials were also written about applicative functors, traversable
+functors, free monads, etc., showing a real unfulfilled need for presenting
+practice-relevant fragments of theory in an applied setting.
+
+For example, free monads became popular in the Scala community around
+2015. Many talks about free monads were presented at Scala engineering
+conferences, giving different implementations but never formulating
+rigorously the properties required of a valid implementation of a
+free monad. Without knowing the required mathematical properties of
+free monads, a programmer cannot make sure that a given implementation
+is correct. However, books on category theory define free monads in
+a way that is unsuitable for programming applications (a free monad
+is an adjoint functor to a forgetful functor from a Kleisli category
+to the category of sets).\footnote{\textsf{``}\emph{A monad is just a monoid in the category of endofunctors.
+What\textsf{'}s the problem?}\textsf{''} is a well-known joke.\index{jokes}\label{fn:A-monad-is-a-monoid-in-category-of-endofunctors-big-deal}
+See \texttt{\href{https://stackoverflow.com/questions/3870088/}{https://stackoverflow.com/questions/3870088/}}
+for background information about that joke. A related joke is in footnote~\ref{fn:Whats-the-big-deal-monad-transformers}
+on page~\pageref{fn:Whats-the-big-deal-monad-transformers}.} Such \textsf{``}academic\textsf{''} definitions can be used neither as guidance for
+writing code or checking code correctness, nor as a conceptual explanation
+that a learner would find helpful.
+
+Perhaps the best selection of AFTT tutorial material today can be
+found in the \textsf{``}Haskell Wikibooks\textsf{''}.\footnote{\texttt{\href{https://en.wikibooks.org/wiki/Haskell}{https://en.wikibooks.org/wiki/Haskell}}}
+However, those tutorials are incomplete and limited to explaining
+the use of Haskell. Many of them are suitable neither as a first introduction
+nor as a reference on AFTT. Also, the Haskell Wikibooks tutorials
+rarely show any derivations of laws or explain the required techniques.
+
+Apart from referring to some notions of category theory, AFTT also
+uses concepts from type theory and formal logic. However, existing
+textbooks of type theory and logic focus on formal semantics, domain
+theory, and proof theory. From a practicing programmer\textsf{'}s viewpoint,
+these books present a lot of difficult-to-learn material that will
+not help in writing code. At the same time, those academic books never
+mention the practical techniques used in many functional programming
+libraries today, such as reasoning about and implementing types with
+quantifiers, types parameterized by type constructors, or partial
+type-to-value functions (known as \textsf{``}typeclasses\textsf{''}).
+
+The proper scope of AFTT is to help the programmer with practical
+tasks such as:
+\begin{enumerate}
+\item Deciding whether two data types are equivalent and implementing the
+isomorphism transformations. For example, the Scala type \lstinline!(A, Either[B, C])!
+is equivalent to \lstinline!Either[(A, B), (A, C)]!, but the type
+\lstinline!A => Either[B, C]! is \emph{not} equivalent to \lstinline!Either[A => B, A => C]!.
+\item Checking whether a definition of a recursive type is \textsf{``}valid\textsf{''},
+i.e., does not lead to infinite loops. A simple example of an \textsf{``}invalid\textsf{''}
+recursive type definition in Scala is \lstinline!class Bad(x: Bad)!.
+A small change transforms that example into a \textsf{``}valid\textsf{''} recursive
+type: \lstinline!class Good(x: Option[Good])!.
+\item Deciding whether a function with a given type signature can be implemented.
+For example,
+\begin{lstlisting}
+def f[Z,A,R]: (R => Either[Z, A]) => Either[Z, R => A] = ??? // Cannot be implemented.
+def g[Z,A,R]: Either[Z, R => A] => (R => Either[Z, A]) = ??? // Can be implemented.
+\end{lstlisting}
+\item Deriving an implementation of a function from its type signature and
+checking required laws. For example, deriving the \lstinline!flatMap!
+method and checking its laws for the \lstinline!Reader! monad:
+\begin{lstlisting}
+def flatMap[Z, A, B](r: Z => A)(f: A => Z => B): Z => B = ???
+\end{lstlisting}
+\item Deriving a simpler but equivalent code by calculating with functions
+and laws.
+\end{enumerate}
+These are real-world applications of type theory and the Curry-Howard
+correspondence, but existing books on type theory and logic do not
+give practical recipes for performing these tasks.\footnote{Task 5 is addressed in several programming-oriented books such as
+\emph{Pearls of functional algorithm design} by \index{Richard Bird}Richard
+Bird (\texttt{\href{https://www.cambridge.org/9780521513388}{https://www.cambridge.org/9780521513388}}).}
+
+Books such as \emph{Scala with Cats},\footnote{\texttt{\href{https://underscore.io/books/scala-with-cats/}{https://underscore.io/books/scala-with-cats/}}}
+\emph{Functional programming simplified},\footnote{\texttt{\href{https://alvinalexander.com/scala/functional-programming-simplified-book}{https://alvinalexander.com/scala/functional-programming-simplified-book}}}
+and \emph{Functional programming for mortals}\footnote{\texttt{\href{http://www.lulu.com/shop/search.ep?contributorId=1600066}{http://www.lulu.com/shop/search.ep?contributorId=1600066}}}
+are primarily focused on explaining practical aspects of functional
+programming and do not derive the mathematical laws for, e.g., filterable,
+monadic, applicative, or traversable functors.
+
+The only currently available Scala-based AFTT textbook is \emph{Functional
+Programming in Scala}.\footnote{\texttt{\href{https://www.manning.com/books/functional-programming-in-scala}{https://www.manning.com/books/functional-programming-in-scala}}}
+It balances practical coding with theoretical developments and laws.
+\emph{Program design by calculation}\footnote{\texttt{\href{http://www4.di.uminho.pt/~jno/ps/pdbc.pdf}{http://www4.di.uminho.pt/$\sim$jno/ps/pdbc.pdf}}}
+is another (Haskell-oriented) AFTT book in progress. The present book
+is written at about the same level but aims at better motivation for
+mathematical concepts and a wider range of pedagogical examples that
+help build the necessary intuition and facility with the techniques
+of formal derivation.
+
+Figures~\ref{fig:Randomly-chosen-pages-1}\textendash \ref{fig:Randomly-chosen-pages}
+illustrate the difference between AFTT books, programming books, and
+academic science books, by showing randomly chosen pages from such
+books. One gets a visual impression that programming-oriented books
+contain code examples and explanations in words but no formal derivations.
+Books on AFTT, as well as books on mathematics and science, will typically
+show equations, diagrams, and derivations. The present book contains
+both code examples and mathematical proofs.
+
+\begin{figure}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpsimplified-pdf-07}
+\par\end{centering}
+\begin{centering}
+\vspace{-0.3\baselineskip}
+\par\end{centering}
+\begin{centering}
+\emph{Functional programming simplified}, by A.~Alexander
+\par\end{centering}
+\begin{centering}
+\vspace{1\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-07}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpmortals-pdf-08}
+\par\end{centering}
+\begin{centering}
+\emph{\vspace{-1.6\baselineskip}
+}
+\par\end{centering}
+\begin{centering}
+\emph{Functional programming for mortals}, by S.~Halliday
+\par\end{centering}
+\begin{centering}
+\vspace{1\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-07}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-08}\includegraphics[height=2.51cm]{random-pages/random-pages-from-volpe-pdf-09}
+\par\end{centering}
+\begin{centering}
+\emph{\vspace{-1.9\baselineskip}
+}
+\par\end{centering}
+\begin{centering}
+\emph{Practical functional programming in Scala}, by G.~Volpe (\texttt{\small{}\href{https://leanpub.com/pfp-scala}{https://leanpub.com/pfp-scala}})
+\par\end{centering}
+\begin{centering}
+\vspace{1\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-07}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-08}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kalinin-pdf-09}
+\par\end{centering}
+\vspace{-0.6\baselineskip}
+
+\begin{centering}
+\emph{Mastering advanced Scala}, by D.~Kalinin (\texttt{\small{}\href{https://leanpub.com/mastering-advanced-scala}{https://leanpub.com/mastering-advanced-scala}})
+\par\end{centering}
+\caption{Randomly chosen pages from books on Scala programming.\label{fig:Randomly-chosen-pages-1}}
+\end{figure}
+
+\begin{figure}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-hefferon-pdf-07}
+\par\end{centering}
+\vspace{-0.4\baselineskip}
+
+\begin{centering}
+\emph{Linear algebra}, by J.~Hefferon (\texttt{\small{}\href{http://joshua.smcvt.edu/linearalgebra/}{http://joshua.smcvt.edu/linearalgebra/}})
+\par\end{centering}
+\begin{centering}
+\vspace{0.6\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-kibble-pdf-09}
+\par\end{centering}
+\vspace{-0.6\baselineskip}
+
+\begin{centering}
+\emph{Classical mechanics}, by T.~W.~B.~Kibble and F.~H.~Berkshire
+(\texttt{\small{}\href{https://archive.org/details/116772449ClassicalMechanics}{https://archive.org/details/116772449ClassicalMechanics}})
+\par\end{centering}
+\vspace{0.6\baselineskip}
+
+\caption{Randomly chosen pages from books on mathematics and physics.\label{fig:Randomly-chosen-pages-2}}
+\end{figure}
+
+\begin{figure}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-07}\includegraphics[height=2.51cm]{random-pages/random-pages-from-fpis-pdf-08}
+\par\end{centering}
+\vspace{-0\baselineskip}
+
+\begin{centering}
+\emph{Functional programming in Scala}, by P.~Chiusano and R.~Bjarnason
+\par\end{centering}
+\begin{centering}
+\vspace{1\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-03}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-04}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-pdbc-pdf-07}
+\par\end{centering}
+\vspace{-0.7\baselineskip}
+
+\begin{centering}
+\emph{Program design by calculation}, by J.~N.~Oliveira
+\par\end{centering}
+\begin{centering}
+\vspace{1\baselineskip}
+\par\end{centering}
+\begin{centering}
+\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-00}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-01}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-02}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-05}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-06}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-07}\includegraphics[height=2.51cm]{random-pages/random-pages-from-sofp-pdf-08}
+\par\end{centering}
+\vspace{-0.3\baselineskip}
+
+\begin{centering}
+\emph{The science of functional programming} (this book)
+\par\end{centering}
+\vspace{1\baselineskip}
+
+\caption{Randomly chosen pages from books on applied functional type theory.\label{fig:Randomly-chosen-pages}}
+\end{figure}
+
+
+\addchap{Essay: Why category theory is useful in functional programming}
+
+\index{category theory!in functional programming}This essay is for
+readers who are already somewhat familiar with category theory.
+
+\addsec{A \textquotedblleft types/functions\textquotedblright{} category for
+a programming language}
+
+We consider programming languages that support various data types,
+such as integers (\lstinline!Int!), floating-point numbers (\lstinline!Float!),
+strings (\lstinline!String!), arrays of strings (\lstinline!Array[String]!),
+and so on. Such languages allow programmers to define functions with
+specified types of arguments and return values. The compiler will
+then verify that all functions are always applied to arguments of
+correct types, and also that all return values have the expected types.
+
+To each programming language of that kind, there corresponds\footnote{Academically minded computer scientists say that this definition of
+a \textsf{``}types/functions\textsf{''} category is insufficiently rigorous. See the
+discussion in \texttt{\href{https://cstheory.stackexchange.com/questions/53389}{https://cstheory.stackexchange.com/questions/53389}}} a \textsf{``}types/functions\textsf{''} category:
+\begin{itemize}
+\item The objects of the category are all the data types supported by the
+language (including user-defined data types). As an example, for Scala
+there will be an object \lstinline!Int!, an object \lstinline!Float!,
+an object \lstinline!String!, an object \lstinline!Array[String]!,
+and so on.
+\item The morphisms between objects \lstinline!A! and \lstinline!B! are
+all functions implementable in the language (with finitely long program
+code) that take a single argument of type \lstinline!A! and return
+a value of type \lstinline!B!.
+\item We assume that the computer has countably infinite memory, so objects
+can be viewed as (at most) countably infinite sets. Morphisms will
+also form at most countably infinite sets.
+\end{itemize}
+The category defined in this way will typically have a large number
+of morphisms between most objects. For example, morphisms between
+objects \lstinline!Boolean! and \lstinline!Int! are functions that
+take a single argument of type \lstinline!Boolean! and return a value
+of type \lstinline!Int!. There are as many such functions as pairs
+of integers. Scala code for one of those morphisms looks like this:
+\begin{lstlisting}
+def morphismBooleanToInt: Boolean => Int = { b => if (b) 123 else 456 }
+\end{lstlisting}
+
+Why do the category laws hold? The composition of morphisms corresponds
+to composition of functions, which we can implement by writing code
+that applies the first function and then applies the second function.
+In Scala:
+\begin{lstlisting}
+def composeMorphisms[A, B, C](f: A => B, g: B => C): A => C = { a => g(f(a)) }
+\end{lstlisting}
+Equivalent functionality can be implemented in most programming languages.
+
+The category\textsf{'}s identity law says that there must be a morphism between
+objects \lstinline!A! and \lstinline!A!. This can be implemented
+in most programming languages as a function that returns its argument
+unchanged:
+\begin{lstlisting}
+def identity[A]: A => A = { x => x }
+\end{lstlisting}
+One can check that morphism composition is associative and agrees
+with the identity morphism.
+
+For a given programming language, we have thus defined the \textsf{``}types/functions
+category\textsf{''}, which can be seen as a subcategory of the category of
+sets. Most of the time, we will be working with that category, or
+with the category of its endofunctors, or with a sub-category of these
+categories.
+
+Different programming languages will give rise to different \textsf{``}types/functions\textsf{''}
+categories, but all those categories have many common features that
+are especially important in languages designed for functional programming
+(the \textsf{``}FP languages\textsf{''}, such as OCaml, Haskell, Scala and others).
+
+\addsec{The use of endofunctors}
+
+An endofunctor in the \textsf{``}types/functions\textsf{''} category is a mapping
+of types together with a mapping of functions. A good example is the
+\lstinline!Array! data type. In some programming languages, the type
+of an array\textsf{'}s elements can be specified and enforced throughout the
+code. For example, in Scala one can use the type \lstinline!Array[Int]!
+for an array of integers, \lstinline!Array[String]! for an array
+of strings, \lstinline!Array[Array[Int]]! for an array containing
+nested arrays of integers, etc. So, \lstinline!Array! can be seen
+as a mapping from types to types: it maps the type \lstinline!Int!
+to the type \lstinline!Array[Int]!, the type \lstinline!String!
+to the type \lstinline!Array[String]!, etc. For any type \lstinline!X!,
+we have the type \lstinline!Array[X]!. This is the object-to-object
+map of an endofunctor.
+
+An endofunctor also needs a map from morphisms to morphisms. Given
+a function \lstinline!f: X => Y!, we need to implement a function
+of type \lstinline!Array[X] => Array[Y]!. This can be done by writing
+a loop over the array and applying the function \lstinline!f! to
+each element (of type \lstinline!X!). The resulting values (of type
+\lstinline!Y!) are then collected in a new array, of type \lstinline!Array[Y]!.
+
+This code can be written in many programming languages in a generic
+manner, using type parameters such as \lstinline!X! and \lstinline!Y!.
+The same code will then work for arrays and functions of any given
+type. In Scala, the code could be written as the following function
+(usually called \lstinline!fmap! in FP libraries):
+\begin{lstlisting}
+def fmap[X, Y: ClassTag](f: X => Y): Array[X] => Array[Y] = { arrayX: Array[X] =>
+ val arrayY = new Array[Y](arrayX.size)
+ for { i <- arrayX.indices } arrayY(i) = f(arrayX(i))
+ arrayY // Return this array of type Array[Y].
+}
+\end{lstlisting}
+One can then check that the code of \lstinline!fmap! satisfies the
+identity and composition laws of endofunctors. This completes the
+implementation of the \lstinline!Array! endofunctor.
+
+Why does \lstinline!fmap! satisfy the laws of endofunctors? The categorical
+properties of functions are preserved if we apply functions to each
+element of an array and collect the results \emph{in the same order}.
+An identity function applied to every element will not modify the
+array. Function composition is preserved because a composition of
+two functions will be applied separately to each array element.
+
+The same construction can be applied to many data structures other
+than arrays. It turns out that many programs can be reformulated using
+the operation of applying a function to every value in a data structure
+(i.e., the function \lstinline!fmap!). This reformulation leads to
+code that avoids loops: the loops are replaced by \lstinline!fmap!
+functions of some endofunctors, and all those \lstinline!fmap! functions
+are implemented in a standard library. In practice, code written via
+\lstinline!fmap! instead of loops is more concise and admits fewer
+opportunities for errors. The programmer\textsf{'}s intuition about \textsf{``}applying
+functions to every value held within a data structure\textsf{''} is then directly
+represented by the formal laws of endofunctors. Once those laws are
+verified, the programmer is assured that the code written via \lstinline!fmap!
+will work according to the programmer\textsf{'}s intuitive expectations.
+
+\addsec{The use of natural transformations}
+
+What is a natural transformation between endofunctors in the \textsf{``}types/functions\textsf{''}
+category? For two given endofunctors \lstinline!F! and \lstinline!G!,
+a natural transformation \lstinline!t: F ~> G! is defined by its
+components. The component at object \lstinline!X! is a function of
+type \lstinline!F[X] => G[X]!; this must be defined for all \lstinline!X!.
+Some programming languages support functions with type parameters.
+In Scala, the syntax is
+\begin{lstlisting}
+def t[X]: F[X] => G[X] = ...
+\end{lstlisting}
+The code of such a function is written once and will work in the same
+way for all types \lstinline!X!.
+
+An example of natural transformation is a function that reverses the
+order of elements in an array:
+\begin{lstlisting}
+def reverse[X]: Array[X] => Array[X] = ...
+\end{lstlisting}
+The algorithm is \textsf{``}fully parametric\textsf{''}: it is written in the same
+way for all type parameters \lstinline!X!.
+
+It turns out that, by the Reynolds-Wadler parametricity theorem, any
+code written in a fully parametric manner will satisfy the law of
+a natural transformation (the naturality law). The naturality law
+states that applying the endofunctor \lstinline!F!\textsf{'}s morphism map
+before a natural transformation \lstinline!t! must be equal to applying
+the endofunctor \lstinline!G!\textsf{'}s map after \lstinline!t!. In Scala
+syntax, the law is written as
+\begin{lstlisting}
+t(fmap_F(f)(x)) == fmap_G(f)(t(x))
+\end{lstlisting}
+This law can be verified directly for a given code of \lstinline!t!
+and with known code for \lstinline!fmap_F! and \lstinline!fmap_G!.
+
+Naturality laws are satisfied by transformations that rearrange data
+items in a data structure in some way that does not depend on specific
+values or types. In this way, the formal laws of natural transformations
+directly represent programmers\textsf{'} intuitions about code that works \textsf{``}in
+the same way for all type parameters\textsf{''}.
+
+As we have just seen, the notions of endofunctors and natural transformations
+are useful in programming languages that support types with type parameters
+(such as \lstinline!Array[X]!) and functions with type parameters
+(such as \lstinline!reverse[X]!). Programming languages that do not
+support those features cannot benefit from the powerful reasoning
+tools of category theory.
+
+\addsec{Other properties of the \textquotedblleft types/functions\textquotedblright{}
+category}
+
+Morphisms in the \textsf{``}types/functions\textsf{''} category are always functions
+of a single argument. However, programming languages usually support
+functions with many arguments. There are two ways to imitate such
+functions: tupling and currying.
+
+Tupling means that we put all arguments into a compound structure
+(a pair, a triple, etc.). The function is still viewed as having a
+single argument, but the type of that argument is the type of a pair,
+or a triple, or a longer tuple type. This works when the programming
+language supports tuple types. A tupled function\textsf{'}s type is written
+(in Scala) as, e.g., \lstinline!((A, B, C)) => D!.
+
+Tuple types correspond to finite products of objects in the \textsf{``}types/functions\textsf{''}
+category. So, it is useful if the category has (finite) products.
+
+Currying means that we create a function that takes the first argument
+and returns a curried function that handles the rest of the arguments
+in the same way (takes the second argument and again returns a function,
+etc.). A curried function\textsf{'}s type is written in Scala as, e.g., \lstinline!A => B => C => D!.
+To support this method, the programming language should have function
+types. The corresponding categorical construction is the \textsf{``}exponential\textsf{''}
+object.
+
+In the practice of functional programming, it has been found useful
+to have the type \lstinline!Unit!, which has exactly one value, and
+the type \lstinline!Nothing!, which has no values. In the \textsf{``}types/functions\textsf{''}
+category, these types correspond to the terminal and the initial objects.
+
+Finally, disjunctive types correspond to co-products in the \textsf{``}types/functions\textsf{''}
+category.
+
+In this way, we find that various well-known mathematical properties
+of the \textsf{``}types/functions\textsf{''} category (initial and terminal objects,
+finite products and co-products, exponentials) correspond to properties
+of the programming language that proved useful in the practice of
+software engineering.
+
+\addsec{Some useful sub-categories of endofunctors}
+
+Besides loops that apply functions to array elements, other frequently
+used computations are nested loops and \textsf{``}while\textsf{''}-loops that are
+repeated while a given condition holds and then stopped. It turns
+out that category theory provides a convenient language for reasoning
+about such computations. Similarly to representing loops via endofunctors,
+the various kinds of loops are encoded via certain sub-categories
+of endofunctors in the \textsf{``}types/functions\textsf{''} category.
+
+To see how this works, we need to define an auxiliary sub-category
+called the \textsf{``}\lstinline!F!-lifted\textsf{''} (where \lstinline!F! may be
+any given endofunctor, such as \lstinline!Array!). The \lstinline!F!-lifted
+sub-category is the image of the endofunctor \lstinline!F!. The objects
+of that sub-category are types of the form \lstinline!F[A]!. The
+morphisms of that sub-category are functions of type \lstinline!F[A] => F[B]!
+(not necessarily obtained by lifting some function \lstinline!f: A => B!
+through the endofunctor \lstinline!F!\textsf{'}s \lstinline!fmap! method).
+
+\subsection*{Filterable endofunctors}
+
+To describe \textsf{``}while\textsf{''}-loops using category theory, we begin by reformulating
+the loop as a \emph{mathematical function} rather than as a sequence
+of computer instructions. To be specific, consider a program with
+a loop that stops when a certain condition first becomes \lstinline!false!.
+A loop of this kind may be modeled by a function that takes an initial
+array as argument and returns a new array that is truncated when a
+given condition first becomes \lstinline!false!. The condition is
+represented by a function evaluated on each element of the array.
+The Scala standard library includes such a function (\lstinline!takeWhile!).
+An example of its usage is:
+\begin{lstlisting}[mathescape=true]
+scala> Array(1, 2, 3, 4, 5).takeWhile(x => x < 4) // Truncate the array when $\color{dkgreen} x \geq 4$ is first found.
+res0: Array[Int] = Array(1, 2, 3)
+\end{lstlisting}
+The next step is to extend this function to work with arbitrary types
+instead of integers. The type signature of \lstinline!takeWhile!
+may be written as:
+\begin{lstlisting}
+def takeWhile[X](p: X => Boolean): Array[X] => Array[X]
+\end{lstlisting}
+Here \lstinline!X! is a type parameter. The first argument (\lstinline!p!)
+is a predicate of type \lstinline!X => Boolean!.
+
+Finally, we write the laws that we expect this function to satisfy.
+For instance, if the given predicate \lstinline!p! always returns
+\lstinline!true!, the function should not change the given array
+(the \textsf{``}identity law\textsf{''}):
+\begin{lstlisting}
+takeWhile(x => true) == identity
+\end{lstlisting}
+Another plausible law is called the \textsf{``}composition law\textsf{''}. If we apply
+\lstinline!takeWhile! with a predicate \lstinline!p1! and then again
+apply \lstinline!takeWhile! with another predicate \lstinline!p2!,
+the resulting truncated array should be the same as if we applied
+\lstinline!takeWhile! just once with a Boolean conjunction of \lstinline!p1!
+and \lstinline!p2!:
+\begin{lstlisting}
+takeWhile(p1) andThen takeWhile(p2) == takeWhile( x => p1(x) && p2(x) )
+\end{lstlisting}
+
+The identity and composition laws of \lstinline!takeWhile! are analogous
+to the identity and composition laws of functors. More precisely,
+one can derive the laws of \lstinline!takeWhile! from the laws of
+an auxiliary functor between a certain Kleisli category and the \lstinline!F!-lifted
+category (see Example~\ref{subsec:Example-category-definition-of-filterable-functor}
+for details). That auxiliary functor exists only for some endofunctors
+\lstinline!F!, which are called \textsf{``}filterable\textsf{''} in this book. Filterable
+endofunctors are a sub-category of all endofunctors of the \textsf{``}types/functions\textsf{''}
+category.
+
+With this construction, one may now regard the laws of \lstinline!takeWhile!
+not as arbitrarily postulated properties but as a consequence of the
+functor laws. In this way, category theory validates the programmer\textsf{'}s
+intuition for the choice of the laws for \lstinline!takeWhile!.
+
+\subsection*{Monadic endofunctors}
+
+To evaluate a nested loop, which may be written in Scala as in this
+example:
+\begin{lstlisting}
+for {
+ x <- 1 to 10
+ y <- 1 to x / 2
+} yield f(x, y) // Some computation that may use x and y.
+\end{lstlisting}
+the computer will perform ten repetitions of the inner loop over \lstinline!y!.
+This computation is equivalent to converting the nested loop into
+an ordinary, \textsf{``}flattened\textsf{''} loop that has a larger total number of
+repetitions (in this example, $25$ repetitions). To describe this
+situation using category theory, we start by reformulating a nested
+loop into a mathematical function. The arguments of that function
+are the first array (\lstinline!1 to 10!) for iterating with \lstinline!x!,
+and a function from a value of \lstinline!x! to the nested array
+(\lstinline!x => 1 to x / 2!). The function returns a \textsf{``}flattened\textsf{''}
+array of $25$ values.
+
+The Scala library contains such a function, named \lstinline!flatMap!.
+An example of usage is:
+\begin{lstlisting}
+scala> (1 to 10).toArray.flatMap(x => 1 to x / 2)
+res0: Array[Int] = Array(1, 1, 1, 2, 1, 2, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5)
+\end{lstlisting}
+This function can be used repeatedly to convert arbitrarily deeply
+nested loops into \textsf{``}flat\textsf{''} loops.
+
+The next step is to formulate a fully parametric type signature for
+\lstinline!flatMap!:
+\begin{lstlisting}
+def flatMap[A, B](f: A => Array[B]): Array[A] => Array[B]
+\end{lstlisting}
+In this way, \lstinline!flatMap! can transform arrays with elements
+of any type.
+
+The \lstinline!flatMap! function must satisfy certain properties
+that are useful for practical programming. One of these properties
+is \textsf{``}associativity\textsf{''}. A deeply nested loop may be flattened by applying
+\lstinline!flatMap! first to the outer layers and then to the inner
+layers, or by applying \lstinline!flatMap! first to the inner layers;
+the results must be the same. This and other properties of \lstinline!flatMap!
+are analogous to the laws of a category: there are two identity laws
+and one associativity law. More precisely, one can derive the laws
+of \lstinline!flatMap! from the requirement that the Kleisli category
+on the endofunctor \lstinline!Array! is well-defined (see Section~\ref{subsec:Monads-in-category-theory-monad-morphisms}
+for details). This is equivalent to saying that \lstinline!Array!
+is a monad. Monads form a sub-category of endofunctors of the \textsf{``}types/functions\textsf{''}
+category.
+
+\addsec{Category theory and the laws of FP idioms}
+
+We have seen that \textsf{``}while\textsf{''}-loops and nested loops can be reformulated
+through type-parameterized functions satisfying certain laws. Those
+laws are then equivalent to the laws of suitably chosen functors or
+categories. This turns out to be a general pattern:
+\begin{itemize}
+\item Begin with a known idiom of computation (e.g., a certain kind of a
+loop).
+\item Reformulate that idiom through functions with parameterized argument
+types.
+\item Write the laws that programmers expect those functions to satisfy.
+\item Prove that those laws are equivalent to the laws of a suitable functor
+and/or category.
+\end{itemize}
+The derivations in Chapters~\ref{chap:Functors,-contrafunctors,-and}\textendash \ref{chap:monad-transformers}
+of this book follow this pattern. One can show that this pattern holds
+for at least \emph{eleven} sub-categories of endofunctors used in
+FP practice: functors, contrafunctors, filterable functors, filterable
+contrafunctors, applicative functors, applicative contrafunctors,
+monads, comonads, traversable functors, monad transformers, and comonad
+transformers.
+
+It appears that the basic tools of category theory (functors, natural
+transformations, commutative diagrams) provide a convenient language
+for reasoning about laws of various FP idioms. By invoking category
+theory, programmers avoid having to memorize a large number of laws
+and constructions. Without the underlying categorical justification,
+the laws for different endofunctors will appear to be chosen arbitrarily,
+with no clearly recognizable system or pattern.
+
+In addition, category theory guides programmers in creating highly
+abstract libraries that work uniformly with all endofunctors of a
+certain sub-category. In programmer\textsf{'}s terms, such libraries contain
+functions parameterized by type constructors satisfying appropriate
+constraints. Examples are functions that define the product or the
+co-product of any two given functors, or define a free monad on a
+given functor. Implementing libraries of that kind requires formulating
+and verifying the relevant laws. Category theory is a reliable foundation
+for such libraries.
diff --git a/sofp-src/sofp-filterable.tex b/sofp-src/tex/sofp-filterable.tex
similarity index 100%
rename from sofp-src/sofp-filterable.tex
rename to sofp-src/tex/sofp-filterable.tex
diff --git a/sofp-src/sofp-free-type.tex b/sofp-src/tex/sofp-free-type.tex
similarity index 100%
rename from sofp-src/sofp-free-type.tex
rename to sofp-src/tex/sofp-free-type.tex
diff --git a/sofp-src/sofp-functors.tex b/sofp-src/tex/sofp-functors.tex
similarity index 100%
rename from sofp-src/sofp-functors.tex
rename to sofp-src/tex/sofp-functors.tex
diff --git a/sofp-src/sofp-higher-order-functions.tex b/sofp-src/tex/sofp-higher-order-functions.tex
similarity index 100%
rename from sofp-src/sofp-higher-order-functions.tex
rename to sofp-src/tex/sofp-higher-order-functions.tex
diff --git a/sofp-src/sofp-induction.tex b/sofp-src/tex/sofp-induction.tex
similarity index 100%
rename from sofp-src/sofp-induction.tex
rename to sofp-src/tex/sofp-induction.tex
diff --git a/sofp-src/sofp-monads.tex b/sofp-src/tex/sofp-monads.tex
similarity index 100%
rename from sofp-src/sofp-monads.tex
rename to sofp-src/tex/sofp-monads.tex
diff --git a/sofp-src/sofp-nameless-functions.tex b/sofp-src/tex/sofp-nameless-functions.tex
similarity index 100%
rename from sofp-src/sofp-nameless-functions.tex
rename to sofp-src/tex/sofp-nameless-functions.tex
diff --git a/sofp-src/sofp-preface.tex b/sofp-src/tex/sofp-preface.tex
similarity index 100%
rename from sofp-src/sofp-preface.tex
rename to sofp-src/tex/sofp-preface.tex
diff --git a/sofp-src/sofp-reasoning.tex b/sofp-src/tex/sofp-reasoning.tex
similarity index 100%
rename from sofp-src/sofp-reasoning.tex
rename to sofp-src/tex/sofp-reasoning.tex
diff --git a/sofp-src/sofp-summary.tex b/sofp-src/tex/sofp-summary.tex
similarity index 100%
rename from sofp-src/sofp-summary.tex
rename to sofp-src/tex/sofp-summary.tex
diff --git a/sofp-src/sofp-transformers.tex b/sofp-src/tex/sofp-transformers.tex
similarity index 100%
rename from sofp-src/sofp-transformers.tex
rename to sofp-src/tex/sofp-transformers.tex
diff --git a/sofp-src/sofp-traversable.tex b/sofp-src/tex/sofp-traversable.tex
similarity index 100%
rename from sofp-src/sofp-traversable.tex
rename to sofp-src/tex/sofp-traversable.tex
diff --git a/sofp-src/sofp-typeclasses.tex b/sofp-src/tex/sofp-typeclasses.tex
similarity index 100%
rename from sofp-src/sofp-typeclasses.tex
rename to sofp-src/tex/sofp-typeclasses.tex
diff --git a/sofp-src/sofp.tex b/sofp-src/tex/sofp.tex
similarity index 91%
rename from sofp-src/sofp.tex
rename to sofp-src/tex/sofp.tex
index 882d08139..811aa1616 100644
--- a/sofp-src/sofp.tex
+++ b/sofp-src/tex/sofp.tex
@@ -1,6 +1,6 @@
%% LyX 2.3.7 created this file. For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
-\documentclass[12pt,russian,english,openright,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt]{scrbook}
+\documentclass[10pt,russian,english,openright,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt]{scrbook}
\usepackage{amsmath}
\usepackage{mathpazo}
\usepackage{helvet}
@@ -9,7 +9,7 @@
\usepackage[T2A,T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[paperwidth=7.444in,paperheight=9.68in]{geometry}
-\geometry{verbose,tmargin=1.3cm,bmargin=1.5cm,lmargin=2.4cm,rmargin=1.4cm,headsep=0.5cm,footskip=0.8cm}
+\geometry{verbose,tmargin=1.3cm,bmargin=1.5cm,lmargin=2.5cm,rmargin=1.3cm,headsep=0.5cm,footskip=0.8cm}
\setcounter{secnumdepth}{3}
\usepackage{xcolor}
\usepackage{babel}
@@ -106,7 +106,7 @@
%\usepackage{microtype}
% Fix the numbering of exercises: subsubsections appear as paragraphs but are numbered.
-%\usepackage{titlesec} % Incompatible with komascript\textsf{'}s later versions.
+%\usepackage{titlesec} % Incompatible with komascript's later versions.
% See https://tex.stackexchange.com/questions/7627/how-to-reference-paragraph
% See the `titlesec` package documentation at http://www.ctex.org/documents/packages/layout/titlesec.pdf
%\titleformat{\subsubsection}[runin]{\normalfont\normalsize\bfseries}{}{0pt}{}
@@ -244,12 +244,12 @@
%\renewenvironment{align}{%
%\begin{empheq}[box=\mymathbgbox]{align}}{%
%\endalign\end{empheq}}
-% Run a command such as LC_ALL=C sed -i bak -e \textsf{'}s|\\begin{align}|\\begin{empheq}[box=\\mymathbgbox]{align}|; s|\\end{align}|\\end{empheq}|' sofp-filterable.tex
+% Run a command such as LC_ALL=C sed -i bak -e 's|\\begin{align}|\\begin{empheq}[box=\\mymathbgbox]{align}|; s|\\end{align}|\\end{empheq}|' sofp-filterable.tex
% This is not used now because the results are not great.
% Better text quotes.
-\renewcommand\textquotedblleft{\textsf{``}}
-\renewcommand\textquotedblright{\textsf{''}}
+\renewcommand\textquotedblleft{``}
+\renewcommand\textquotedblright{''}
% Better symbol for the pair mapper instead of \ogreaterthan and \varogreaterthan.
\newcommand{\boxrightarrow}{\mathbin{\ensuremath{%
@@ -306,8 +306,8 @@
\renewcommand{\lstlistingname}{\inputencoding{latin9}Listing}
\begin{document}
-\extratitle{\input{sofp-cover-page}\hfill{}\thispagestyle{empty}The Science
-of Functional Programming\hspace{1in}}
+\extratitle{\input{sofp-cover-for-main-pdf}\hfill{}\thispagestyle{empty}The
+Science of Functional Programming\hspace{1in}}
\title{The Science of Functional Programming}
\subtitle{A tutorial, with examples in Scala}
\author{by Sergei Winitzki, Ph.D.}
@@ -320,23 +320,23 @@
{\footnotesize{}ISBN (e-book): 978-0-359-76877-6}\\
{\footnotesize{}ISBN: 978-0-359-76877-6}\\
\\
-{\scriptsize{}Source hash (sha256): 95955e7292d5e9d345cf3eabf587f153e515088c3257f8e8f6aba6aa82b6d06e}\\
-{\scriptsize{}Git commit: fe671df9443835d39affe466973489329986244f}\\
-{\scriptsize{}PDF file built on Fri, 29 Mar 2024 19:02:53 +0100 by pdfTeX 3.141592653-2.6-1.40.25 (TeX Live 2023) on Darwin}\\
+{\scriptsize{}Source hash (sha256): eea6a95a28d4fc3ae6c2cfcfbb5a1bdb4afb1aaa74a77d19b502300413ffcdca}\\
+{\scriptsize{}Git commit: 39991b324fcd9fc36af6a61aaa4ff96148949956}\\
+{\scriptsize{}PDF file built on Sat, 30 Mar 2024 14:12:48 +0100 by pdfTeX 3.141592653-2.6-1.40.25 (TeX Live 2023) on Darwin}\\
~\\
{\scriptsize{}Permission is granted to copy, distribute and/or modify
this document under the terms of the GNU Free Documentation License,
Version 1.2 or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the appendix entitled
-\textsf{``}GNU Free Documentation License\textsf{''} (Appendix~\ref{sec:GFDL} on page~\pageref{sec:GFDL}).}\\
+“GNU Free Documentation License” (Appendix~\ref{sec:GFDL} on page~\pageref{sec:GFDL}).}\\
{\scriptsize{}~}\\
{\scriptsize{}A }\emph{\scriptsize{}Transparent}{\scriptsize{} copy
of the source code for the book is available at }\texttt{\scriptsize{}\href{https://github.com/winitzki/sofp}{https://github.com/winitzki/sofp}}{\scriptsize{}
and includes LyX, LaTeX, graphics source files, and build scripts.
A full-color hyperlinked PDF file is available at }\texttt{\scriptsize{}\href{https://github.com/winitzki/sofp/releases}{https://github.com/winitzki/sofp/releases}}{\scriptsize{}
-under \textsf{``}Assets\textsf{''}. The source code may be also included as a \textsf{``}file
-attachment\textsf{''} named }\texttt{\scriptsize{}sofp-src.tar.bz2}{\scriptsize{}
+under ``Assets''. The source code may be also included as a ``file
+attachment'' named }\texttt{\scriptsize{}sofp-src.tar.bz2}{\scriptsize{}
within a PDF file. To extract, run }\texttt{\scriptsize{}`pdftk sofp.pdf
unpack\_files output .`}{\scriptsize{} and then }\texttt{\scriptsize{}`tar
jxvf sofp-src.tar.bz2`}{\scriptsize{}. See the file }\texttt{\scriptsize{}README\_build.md}{\scriptsize{}
@@ -349,7 +349,7 @@
and code. Examples are given in Scala, but most of the material applies
equally to other FP languages.}\\
{\scriptsize{}}\\
-{\scriptsize{}The book\textsf{'}s topics include working with FP-style collections;
+{\scriptsize{}The book's topics include working with FP-style collections;
reasoning about recursive functions and types; the Curry-Howard correspondence;
laws, structural analysis, and code for functors, monads, and other
typeclasses based on exponential-polynomial data types; techniques
@@ -361,7 +361,7 @@
code snippets, 191 statements with step-by-step derivations,
103 diagrams, 218 examples with tested Scala
code, and 297 exercises. Discussions build upon each
-chapter\textsf{'}s material further.}\\
+chapter's material further.}\\
{\scriptsize{}}\\
{\scriptsize{}Beginners in FP will find tutorials about the map/reduce
programming style, type parameters, disjunctive types, and higher-order
@@ -376,7 +376,7 @@
{\scriptsize{}}\\
{\scriptsize{}Readers should have a working knowledge of programming;
e.g., be able to write code that prints the number of distinct words
-in a sentence. The difficulty of this book\textsf{'}s mathematical derivations
+in a sentence. The difficulty of this book's mathematical derivations
is at the level of undergraduate multivariate calculus, similar to
that of multiplying matrices or simplifying the expressions:
\[
@@ -405,8 +405,8 @@
is faster. It is not necessary (but harmless) to copy the LaTeX preamble
from sofp.lyx to all chapter files.
-+ No separate chapter for recursive types unless this is about \textsf{``}open\textsf{''}
-co-products and \textsf{``}open\textsf{''} products. Recursive types are already covered
++ No separate chapter for recursive types unless this is about ``open''
+co-products and ``open'' products. Recursive types are already covered
sufficiently. Perhaps this is too much and should be left for a future
edition.
@@ -451,5 +451,5 @@ \part{Advanced level}
\printindex{}
-\input{sofp-back-cover-page}
+\input{sofp-back-cover-for-main-pdf}
\end{document}
diff --git a/sofp-src/tex/type-error.jpg b/sofp-src/tex/type-error.jpg
new file mode 100644
index 000000000..5da3564c6
Binary files /dev/null and b/sofp-src/tex/type-error.jpg differ
diff --git a/sofp-src/user_bind_copy.sh b/sofp-src/user_bind_copy.sh
deleted file mode 100644
index d6de01928..000000000
--- a/sofp-src/user_bind_copy.sh
+++ /dev/null
@@ -1 +0,0 @@
-cp $HOME/Library/Application\ Support/LyX-2.3/bind/user.bind .
diff --git a/sofp-src/Clean architecture - sample page.png b/talk_slides/Clean architecture - sample page.png
similarity index 100%
rename from sofp-src/Clean architecture - sample page.png
rename to talk_slides/Clean architecture - sample page.png
diff --git a/sofp-src/Code Complete - another sample page.png b/talk_slides/Code Complete - another sample page.png
similarity index 100%
rename from sofp-src/Code Complete - another sample page.png
rename to talk_slides/Code Complete - another sample page.png
diff --git a/sofp-src/Code Complete - sample page.png b/talk_slides/Code Complete - sample page.png
similarity index 100%
rename from sofp-src/Code Complete - sample page.png
rename to talk_slides/Code Complete - sample page.png
diff --git a/sofp-src/Ellingson - Electromagnetics vol. 2, sample page.png b/talk_slides/Ellingson - Electromagnetics vol. 2, sample page.png
similarity index 100%
rename from sofp-src/Ellingson - Electromagnetics vol. 2, sample page.png
rename to talk_slides/Ellingson - Electromagnetics vol. 2, sample page.png
diff --git a/sofp-src/Jazar. Theory of Applied Robotics 2nd edition - sample page.png b/talk_slides/Jazar. Theory of Applied Robotics 2nd edition - sample page.png
similarity index 100%
rename from sofp-src/Jazar. Theory of Applied Robotics 2nd edition - sample page.png
rename to talk_slides/Jazar. Theory of Applied Robotics 2nd edition - sample page.png
diff --git a/sofp-src/Properties of natural transformations 2020-05-31.pdf b/talk_slides/Properties of natural transformations 2020-05-31.pdf
similarity index 100%
rename from sofp-src/Properties of natural transformations 2020-05-31.pdf
rename to talk_slides/Properties of natural transformations 2020-05-31.pdf
diff --git a/sofp-src/SBTB-2021-what-I-learned-in-FP.lyx b/talk_slides/SBTB-2021-what-I-learned-in-FP.lyx
similarity index 100%
rename from sofp-src/SBTB-2021-what-I-learned-in-FP.lyx
rename to talk_slides/SBTB-2021-what-I-learned-in-FP.lyx
diff --git a/sofp-src/SBTB-2021-what-I-learned-in-FP.pdf b/talk_slides/SBTB-2021-what-I-learned-in-FP.pdf
similarity index 100%
rename from sofp-src/SBTB-2021-what-I-learned-in-FP.pdf
rename to talk_slides/SBTB-2021-what-I-learned-in-FP.pdf
diff --git a/sofp-src/SBTB-2021-what-I-learned-in-FP.tex b/talk_slides/SBTB-2021-what-I-learned-in-FP.tex
similarity index 100%
rename from sofp-src/SBTB-2021-what-I-learned-in-FP.tex
rename to talk_slides/SBTB-2021-what-I-learned-in-FP.tex
diff --git a/sofp-src/Schaum's outline of electric curcuits, 4th edition - sample page.png b/talk_slides/Schaum's outline of electric curcuits, 4th edition - sample page.png
similarity index 100%
rename from sofp-src/Schaum's outline of electric curcuits, 4th edition - sample page.png
rename to talk_slides/Schaum's outline of electric curcuits, 4th edition - sample page.png
diff --git a/sofp-src/Sinnott, Tower. Chemical Engineering Design 5th edition - sample page.png b/talk_slides/Sinnott, Tower. Chemical Engineering Design 5th edition - sample page.png
similarity index 100%
rename from sofp-src/Sinnott, Tower. Chemical Engineering Design 5th edition - sample page.png
rename to talk_slides/Sinnott, Tower. Chemical Engineering Design 5th edition - sample page.png
diff --git a/sofp-src/Solid software design architecture handbook - sample page.png b/talk_slides/Solid software design architecture handbook - sample page.png
similarity index 100%
rename from sofp-src/Solid software design architecture handbook - sample page.png
rename to talk_slides/Solid software design architecture handbook - sample page.png
diff --git a/sofp-src/Vorobieff-lemma.eps b/talk_slides/Vorobieff-lemma.eps
similarity index 100%
rename from sofp-src/Vorobieff-lemma.eps
rename to talk_slides/Vorobieff-lemma.eps
diff --git a/sofp-src/Vorobieff-lemma.png b/talk_slides/Vorobieff-lemma.png
similarity index 100%
rename from sofp-src/Vorobieff-lemma.png
rename to talk_slides/Vorobieff-lemma.png
diff --git a/sofp-src/Winitzki - conformal diagrams - sample page.png b/talk_slides/Winitzki - conformal diagrams - sample page.png
similarity index 100%
rename from sofp-src/Winitzki - conformal diagrams - sample page.png
rename to talk_slides/Winitzki - conformal diagrams - sample page.png
diff --git a/sofp-src/Winitzki - eibook - sample page.png b/talk_slides/Winitzki - eibook - sample page.png
similarity index 100%
rename from sofp-src/Winitzki - eibook - sample page.png
rename to talk_slides/Winitzki - eibook - sample page.png
diff --git a/sofp-src/Winitzki - physics paper - sample page.png b/talk_slides/Winitzki - physics paper - sample page.png
similarity index 100%
rename from sofp-src/Winitzki - physics paper - sample page.png
rename to talk_slides/Winitzki - physics paper - sample page.png
diff --git a/talk_slides/book-draft-cover.png b/talk_slides/book-draft-cover.png
new file mode 100644
index 000000000..226c5cf08
Binary files /dev/null and b/talk_slides/book-draft-cover.png differ
diff --git a/sofp-src/curryhoward-2020-short.lyx b/talk_slides/curryhoward-2020-short.lyx
similarity index 100%
rename from sofp-src/curryhoward-2020-short.lyx
rename to talk_slides/curryhoward-2020-short.lyx
diff --git a/sofp-src/curryhoward-2020-short.pdf b/talk_slides/curryhoward-2020-short.pdf
similarity index 100%
rename from sofp-src/curryhoward-2020-short.pdf
rename to talk_slides/curryhoward-2020-short.pdf
diff --git a/sofp-src/curryhoward-2020-short.tex b/talk_slides/curryhoward-2020-short.tex
similarity index 100%
rename from sofp-src/curryhoward-2020-short.tex
rename to talk_slides/curryhoward-2020-short.tex
diff --git a/sofp-src/equivalence-under-laws.lyx b/talk_slides/equivalence-under-laws.lyx
similarity index 100%
rename from sofp-src/equivalence-under-laws.lyx
rename to talk_slides/equivalence-under-laws.lyx
diff --git a/sofp-src/equivalence-under-laws.pdf b/talk_slides/equivalence-under-laws.pdf
similarity index 100%
rename from sofp-src/equivalence-under-laws.pdf
rename to talk_slides/equivalence-under-laws.pdf
diff --git a/sofp-src/equivalence-under-laws.tex b/talk_slides/equivalence-under-laws.tex
similarity index 100%
rename from sofp-src/equivalence-under-laws.tex
rename to talk_slides/equivalence-under-laws.tex
diff --git a/sofp-src/explaining-theorems-for-free.lyx b/talk_slides/explaining-theorems-for-free.lyx
similarity index 100%
rename from sofp-src/explaining-theorems-for-free.lyx
rename to talk_slides/explaining-theorems-for-free.lyx
diff --git a/sofp-src/explaining-theorems-for-free.pdf b/talk_slides/explaining-theorems-for-free.pdf
similarity index 100%
rename from sofp-src/explaining-theorems-for-free.pdf
rename to talk_slides/explaining-theorems-for-free.pdf
diff --git a/sofp-src/explaining-theorems-for-free.tex b/talk_slides/explaining-theorems-for-free.tex
similarity index 100%
rename from sofp-src/explaining-theorems-for-free.tex
rename to talk_slides/explaining-theorems-for-free.tex
diff --git a/sofp-src/fpis-excerpt.png b/talk_slides/fpis-excerpt.png
similarity index 100%
rename from sofp-src/fpis-excerpt.png
rename to talk_slides/fpis-excerpt.png
diff --git a/sofp-src/functional-programming-advantages.lyx b/talk_slides/functional-programming-advantages.lyx
similarity index 100%
rename from sofp-src/functional-programming-advantages.lyx
rename to talk_slides/functional-programming-advantages.lyx
diff --git a/sofp-src/functional-programming-advantages.pdf b/talk_slides/functional-programming-advantages.pdf
similarity index 100%
rename from sofp-src/functional-programming-advantages.pdf
rename to talk_slides/functional-programming-advantages.pdf
diff --git a/sofp-src/functional-programming-advantages.tex b/talk_slides/functional-programming-advantages.tex
similarity index 100%
rename from sofp-src/functional-programming-advantages.tex
rename to talk_slides/functional-programming-advantages.tex
diff --git a/sofp-src/parametricity-1-for-bifunctors.lyx b/talk_slides/parametricity-1-for-bifunctors.lyx
similarity index 100%
rename from sofp-src/parametricity-1-for-bifunctors.lyx
rename to talk_slides/parametricity-1-for-bifunctors.lyx
diff --git a/sofp-src/parametricity-1-for-bifunctors.pdf b/talk_slides/parametricity-1-for-bifunctors.pdf
similarity index 100%
rename from sofp-src/parametricity-1-for-bifunctors.pdf
rename to talk_slides/parametricity-1-for-bifunctors.pdf
diff --git a/sofp-src/parametricity-1-for-bifunctors.tex b/talk_slides/parametricity-1-for-bifunctors.tex
similarity index 100%
rename from sofp-src/parametricity-1-for-bifunctors.tex
rename to talk_slides/parametricity-1-for-bifunctors.tex
diff --git a/sofp-src/parametricity-meetup-talk.lyx b/talk_slides/parametricity-meetup-talk.lyx
similarity index 100%
rename from sofp-src/parametricity-meetup-talk.lyx
rename to talk_slides/parametricity-meetup-talk.lyx
diff --git a/sofp-src/parametricity-meetup-talk.pdf b/talk_slides/parametricity-meetup-talk.pdf
similarity index 100%
rename from sofp-src/parametricity-meetup-talk.pdf
rename to talk_slides/parametricity-meetup-talk.pdf
diff --git a/sofp-src/parametricity-meetup-talk.tex b/talk_slides/parametricity-meetup-talk.tex
similarity index 100%
rename from sofp-src/parametricity-meetup-talk.tex
rename to talk_slides/parametricity-meetup-talk.tex
diff --git a/sofp-src/reasoning-natural-transformations.lyx b/talk_slides/reasoning-natural-transformations.lyx
similarity index 100%
rename from sofp-src/reasoning-natural-transformations.lyx
rename to talk_slides/reasoning-natural-transformations.lyx
diff --git a/sofp-src/reasoning-natural-transformations.pdf b/talk_slides/reasoning-natural-transformations.pdf
similarity index 100%
rename from sofp-src/reasoning-natural-transformations.pdf
rename to talk_slides/reasoning-natural-transformations.pdf
diff --git a/sofp-src/reasoning-natural-transformations.tex b/talk_slides/reasoning-natural-transformations.tex
similarity index 100%
rename from sofp-src/reasoning-natural-transformations.tex
rename to talk_slides/reasoning-natural-transformations.tex
diff --git a/sofp-src/reasoning-types-code-lectures.lyx b/talk_slides/reasoning-types-code-lectures.lyx
similarity index 100%
rename from sofp-src/reasoning-types-code-lectures.lyx
rename to talk_slides/reasoning-types-code-lectures.lyx
diff --git a/sofp-src/reasoning-types-code-sf-scala.lyx b/talk_slides/reasoning-types-code-sf-scala.lyx
similarity index 100%
rename from sofp-src/reasoning-types-code-sf-scala.lyx
rename to talk_slides/reasoning-types-code-sf-scala.lyx
diff --git a/sofp-src/reasoning-types-code-sf-scala.pdf b/talk_slides/reasoning-types-code-sf-scala.pdf
similarity index 100%
rename from sofp-src/reasoning-types-code-sf-scala.pdf
rename to talk_slides/reasoning-types-code-sf-scala.pdf
diff --git a/sofp-src/reasoning-types-code.lyx b/talk_slides/reasoning-types-code.lyx
similarity index 100%
rename from sofp-src/reasoning-types-code.lyx
rename to talk_slides/reasoning-types-code.lyx
diff --git a/sofp-src/reasoning-types-code.pdf b/talk_slides/reasoning-types-code.pdf
similarity index 100%
rename from sofp-src/reasoning-types-code.pdf
rename to talk_slides/reasoning-types-code.pdf
diff --git a/sofp-src/relational-parametricity-lectures.lyx b/talk_slides/relational-parametricity-lectures.lyx
similarity index 100%
rename from sofp-src/relational-parametricity-lectures.lyx
rename to talk_slides/relational-parametricity-lectures.lyx
diff --git a/sofp-src/relational-parametricity-lectures.pdf b/talk_slides/relational-parametricity-lectures.pdf
similarity index 100%
rename from sofp-src/relational-parametricity-lectures.pdf
rename to talk_slides/relational-parametricity-lectures.pdf
diff --git a/sofp-src/relational-parametricity-lectures.tex b/talk_slides/relational-parametricity-lectures.tex
similarity index 100%
rename from sofp-src/relational-parametricity-lectures.tex
rename to talk_slides/relational-parametricity-lectures.tex
diff --git a/sofp-src/relational-parametricity-tutorial.lyx b/talk_slides/relational-parametricity-tutorial.lyx
similarity index 100%
rename from sofp-src/relational-parametricity-tutorial.lyx
rename to talk_slides/relational-parametricity-tutorial.lyx
diff --git a/sofp-src/relational-parametricity-tutorial.pdf b/talk_slides/relational-parametricity-tutorial.pdf
similarity index 100%
rename from sofp-src/relational-parametricity-tutorial.pdf
rename to talk_slides/relational-parametricity-tutorial.pdf
diff --git a/sofp-src/relational-parametricity-tutorial.tex b/talk_slides/relational-parametricity-tutorial.tex
similarity index 100%
rename from sofp-src/relational-parametricity-tutorial.tex
rename to talk_slides/relational-parametricity-tutorial.tex
diff --git a/sofp-src/wadler-excerpt.png b/talk_slides/wadler-excerpt.png
similarity index 100%
rename from sofp-src/wadler-excerpt.png
rename to talk_slides/wadler-excerpt.png
diff --git a/sofp-src/what-I-learned-in-FP.lyx b/talk_slides/what-I-learned-in-FP.lyx
similarity index 100%
rename from sofp-src/what-I-learned-in-FP.lyx
rename to talk_slides/what-I-learned-in-FP.lyx
diff --git a/sofp-src/what-I-learned-in-FP.pdf b/talk_slides/what-I-learned-in-FP.pdf
similarity index 100%
rename from sofp-src/what-I-learned-in-FP.pdf
rename to talk_slides/what-I-learned-in-FP.pdf
diff --git a/sofp-src/what-I-learned-in-FP.tex b/talk_slides/what-I-learned-in-FP.tex
similarity index 100%
rename from sofp-src/what-I-learned-in-FP.tex
rename to talk_slides/what-I-learned-in-FP.tex
diff --git a/sofp-src/what-did-category-theory-do-for-us.lyx b/talk_slides/what-did-category-theory-do-for-us.lyx
similarity index 100%
rename from sofp-src/what-did-category-theory-do-for-us.lyx
rename to talk_slides/what-did-category-theory-do-for-us.lyx
diff --git a/sofp-src/what-did-category-theory-do-for-us.pdf b/talk_slides/what-did-category-theory-do-for-us.pdf
similarity index 100%
rename from sofp-src/what-did-category-theory-do-for-us.pdf
rename to talk_slides/what-did-category-theory-do-for-us.pdf