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_. -Book cover +Book cover 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