diff --git a/sofp-src/book_cover/sofp-cover-parameters.tex b/sofp-src/book_cover/sofp-cover-parameters.tex index 76c421af6..df37b5846 100644 --- a/sofp-src/book_cover/sofp-cover-parameters.tex +++ b/sofp-src/book_cover/sofp-cover-parameters.tex @@ -18,7 +18,7 @@ % -- 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{1258}% Must be manually entered +\pgfmathsetmacro\TotalPageCount{1293}% Must be manually entered \pgfmathsetmacro\PaperWidthPt{7.444in}% \pgfmathsetmacro\PaperHeightPt{9.68in}% diff --git a/sofp-src/book_cover/sofp-make-cover.sh b/sofp-src/book_cover/sofp-make-cover.sh index 471442b19..fcd8fd6cd 100644 --- a/sofp-src/book_cover/sofp-make-cover.sh +++ b/sofp-src/book_cover/sofp-make-cover.sh @@ -1,9 +1,9 @@ #!/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/excluded_words b/sofp-src/excluded_words index c0d99a6cb..867f60f11 100644 --- a/sofp-src/excluded_words +++ b/sofp-src/excluded_words @@ -4,8 +4,10 @@ ^(res(ult)?)[0-9]+$ ^116772449ClassicalMechanics$ ^18pt$ +^1980s$ ^1990s$ ^1[abc]$ +^2000s$ ^25pt$ ^48pt$ ^4ac$ @@ -49,6 +51,7 @@ ^BigDecimal$ ^BigM$ ^Bjarnason$ +^Bloomberg$ ^Boehm$ ^Booleans$ ^Bornat$ @@ -98,6 +101,7 @@ ^Disjunction$ ^Doel$ ^Dyckhoff$ +^EDSL$ ^Either3$ ^EitherMonadOps$ ^EitherT$ @@ -134,6 +138,7 @@ ^FoldOpScan$ ^FoldOpSyntax$ ^FoldOpZip$ +^Fortran$ ^Frac$ ^FracBD$ ^FracD$ @@ -159,6 +164,7 @@ ^GADTs$ ^GC$ ^GPUs$ +^GUIs$ ^GeneratorDrivenPropertyChecks$ ^Gentzen$ ^Gliebe$ @@ -216,6 +222,7 @@ ^LaTeX$ ^Lagrangians$ ^Lataillade$ +^Lem$ ^Lempty$ ^Liftings$ ^Lindley$ @@ -275,6 +282,7 @@ ^NaN$ ^Naturality$ ^Netflix$ +^Ngtrks$ ^NioMonad$ ^NoRealRoots$ ^NoRoots$ @@ -286,6 +294,8 @@ ^Num$ ^NumberFormatException$ ^OCaml$ +^OOP$ +^OOUI$ ^Oliveira$ ^OneRoot$ ^OneRootQ$ @@ -302,6 +312,7 @@ ^PLPT$ ^PNG$ ^PQ$ +^PROLOG$ ^PTVF$ ^PTVFs$ ^PTree$ @@ -314,6 +325,7 @@ ^PaymentTuple$ ^Peirce$ ^Peyton$ +^Pgvdrk$ ^Ph$ ^Poincar$ ^PostScript$ @@ -327,6 +339,7 @@ ^ProcessIO$ ^Profunctor$ ^Profunctors$ +^Prolog$ ^PropTree$ ^PureScript$ ^QEqu$ @@ -351,7 +364,9 @@ ^RunnerM$ ^RunnerTry$ ^Rypacek$ +^SIMULA$ ^SOO$ +^SWI$ ^Scala$ ^Schwarz$ ^SearchResult$ @@ -536,6 +551,7 @@ ^bdca$ ^benchmarking$ ^bfs$ +^biapplicative$ ^bifunctor$ ^bifunctorQ$ ^bifunctors$ @@ -670,6 +686,7 @@ ^dcba$ ^de$ ^declaratively$ +^declarativeness$ ^defaultDouble$ ^defaultFunc$ ^defaultInt$ @@ -737,6 +754,7 @@ ^expr$ ^expr1$ ^expr2$ +^expressivity$ ^extendedchars$ ^extensibility$ ^extractorEither$ @@ -1090,9 +1108,11 @@ ^p2q$ ^packagename$ ^pairProduct$ +^parallelizability$ ^parallelizable$ ^parallelize$ ^parallelized$ +^parallelizes$ ^parameterize$ ^parameterized$ ^parametrically$ @@ -1377,6 +1397,7 @@ ^typeclasses$ ^typedef$ ^typelevel$ +^uber$ ^unary$ ^uncommented$ ^uncu$ diff --git a/sofp-src/make_sofp_pdf.sh b/sofp-src/make_sofp_pdf.sh index cc2c90910..2d3a19917 100644 --- a/sofp-src/make_sofp_pdf.sh +++ b/sofp-src/make_sofp_pdf.sh @@ -31,6 +31,7 @@ function source_hash { # 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" @@ -88,7 +89,7 @@ function insert_examples_exercises_count { # This is replaced in the root file o 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 -rs` + 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" } @@ -104,12 +105,9 @@ function add_lulu { } function assemble_sources { - rm -rf "$srcbase" - mkdir "$srcbase" - # Copy the required source files to "$srcbase"/. Include graphics files referenced as images. - cp ../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 "$srcbase"/ - tar jcf "$name-src.tar.bz2" "$srcbase"/* - rm -rf "$srcbase"/ + # 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. @@ -162,7 +160,8 @@ assemble_sources & echo "Creating a full PDF file..." -make_pdf_with_index "$name" # Output is $name.pdf, main file is $name.tex, and other .tex files are \include'd. +# 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 @@ -214,7 +213,7 @@ 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 + make_pdf_with_index "$name" fast >& /dev/null create_draft $name $draft-nolulu.pdf # The main file "$name".pdf has lulu.com information. diff --git a/sofp-src/prepare_10point.sh b/sofp-src/prepare_10point.sh index 56414567b..a6bec7032 100644 --- a/sofp-src/prepare_10point.sh +++ b/sofp-src/prepare_10point.sh @@ -17,14 +17,15 @@ 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_volume.sh b/sofp-src/prepare_volume.sh index 0286aaddc..652b3c6da 100644 --- a/sofp-src/prepare_volume.sh +++ b/sofp-src/prepare_volume.sh @@ -32,9 +32,6 @@ cd $dir tar jxf ../sofp-src.tar.bz2 mv sofp-src/* . -# Special handling for random-pages files. -mkdir random-pages -mv random-pages*png random-pages/ cp ../sofp*.tex ../sofp.* . cp ../book_cover/* ./book_cover/ @@ -129,11 +126,12 @@ mv $name.tex 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 echo "Starting to prepare volume $v" -pdflatex --interaction=batchmode sofp -makeindex sofp.idx +( +pdflatex --interaction=batchmode sofp /dev/null +makeindex sofp.idx cp ../*.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" diff --git a/sofp-src/sofp-appendices.lyx b/sofp-src/sofp-appendices.lyx index 292ca243a..03b522969 100644 --- a/sofp-src/sofp-appendices.lyx +++ b/sofp-src/sofp-appendices.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false diff --git a/sofp-src/sofp-applicative.lyx b/sofp-src/sofp-applicative.lyx index 18623b6c0..7a7d3fc83 100644 --- a/sofp-src/sofp-applicative.lyx +++ b/sofp-src/sofp-applicative.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -1490,21 +1490,6 @@ A \end_inset is defined by: -\end_layout - -\begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "50col%" -status open - -\begin_layout Plain Layout -\begin_inset VSpace -85baselineskip% -\end_inset - - \begin_inset listings inline false status open @@ -1517,26 +1502,6 @@ type L[A] = (A, (A, A) => A) \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset VSpace -25baselineskip% -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\noindent -\begin_inset VSpace -50baselineskip% -\end_inset - - \begin_inset Formula \[ L^{A}\triangleq A\times\left(A\times A\rightarrow A\right)\quad. @@ -1544,11 +1509,6 @@ L^{A}\triangleq A\times\left(A\times A\rightarrow A\right)\quad. \end_inset - -\end_layout - -\begin_layout Standard -\noindent We can write a function that creates a monoid typeclass instance for the type \begin_inset Formula $A\times B$ @@ -1962,8 +1922,7 @@ scala> for { \begin_layout Plain Layout - p <- map2(div(1,0), div(2,0)) { (x, y) => (x, y) } // Create - a tuple (x, y). + p <- map2(div(1,0), div(2,0)) { (x, y) => (x, y) } \end_layout \begin_layout Plain Layout @@ -2144,15 +2103,16 @@ zipE function is written like this: \begin_inset Formula -\[ -\text{zip}_{E}:(E+A)\times(E+B)\rightarrow E+A\times B\quad,\quad\quad\text{zip}_{E}\triangleq\,\begin{array}{|c||cc|} +\begin{align*} + & \text{zip}_{E}:(E+A)\times(E+B)\rightarrow E+A\times B\quad,\\ + & \text{zip}_{E}\triangleq\,\begin{array}{|c||cc|} & E & A\times B\\ \hline E\times E & e_{1}\times e_{2}\rightarrow e_{1}\oplus e_{2} & \bbnum 0\\ A\times E & \_\times e_{2}\rightarrow e_{2} & \bbnum 0\\ E\times B & e_{1}\times\_\rightarrow e_{2} & \bbnum 0\\ A\times B & \bbnum 0 & \text{id} \end{array}\quad. -\] +\end{align*} \end_inset @@ -3234,15 +3194,16 @@ heads . Consider the test example shown above: \begin_inset Formula -\[ -\left|\begin{array}{cc} +\begin{align*} + & \left|\begin{array}{cc} 1 & 2\\ 3 & 4\\ 5 & 6 \end{array}\right|\,\triangleright\text{transpose}=\,\left|\begin{array}{ccc} 1 & 3 & 5\\ 2 & 4 & 6 -\end{array}\right|\quad,\,\,\quad\left|\begin{array}{cc} +\end{array}\right|\quad,\\ + & \,\left|\begin{array}{cc} 1 & 2\\ 3 & 4\\ 5 & 6 @@ -3255,7 +3216,7 @@ heads 3 & 4\\ 5 & 6 \end{array}\right|\quad. -\] +\end{align*} \end_inset @@ -3526,8 +3487,8 @@ validated \end_layout \begin_layout Standard -To simplify the reasoning, assume that the required data structure is a - case class, such as: +For simplicity, assume that the required data structure is a case class, + e.g.: \begin_inset listings inline false status open @@ -3568,11 +3529,7 @@ final case class MyData[A, B, C](a: A, b: B, c: C) \end_inset - -\end_layout - -\begin_layout Standard -We assume that the validation functions will return values of types +Suppose that the validation functions will return values of type \begin_inset listings inline true status open @@ -3585,21 +3542,6 @@ F[A] \end_inset defined by: -\end_layout - -\begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "50col%" -status open - -\begin_layout Plain Layout -\begin_inset VSpace -85baselineskip% -\end_inset - - \begin_inset listings inline false status open @@ -3612,26 +3554,6 @@ type F[A] = Either[E, A] \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset VSpace -25baselineskip% -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\noindent -\begin_inset VSpace -50baselineskip% -\end_inset - - \begin_inset Formula \[ F^{A}\triangleq E+A\quad. @@ -3639,10 +3561,6 @@ F^{A}\triangleq E+A\quad. \end_inset - -\end_layout - -\begin_layout Standard Here, \begin_inset listings inline true @@ -3655,7 +3573,7 @@ A \end_inset - is the type of a successfully validated value, while the fixed type + is the type of a successfully validated value; the fixed type \begin_inset listings inline true status open @@ -6631,11 +6549,11 @@ To enable this kind of code, status open \begin_layout Plain Layout -A more fully featured library using this approach is +The library \family typewriter scala-fold \family default -, see + (see \family typewriter \begin_inset CommandInset href @@ -6647,7 +6565,7 @@ literal "false" \family default - +) implements this approach with additional features. \end_layout \end_inset @@ -6781,19 +6699,7 @@ pdate)) \end_layout \begin_layout Standard -How can we combine two -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -fold -\end_layout - -\end_inset - --like operations of types +How can we combine two operations of types \begin_inset Formula $\text{FoldOp}^{Z,R,A}$ \end_inset @@ -9226,8 +9132,7 @@ implicit class ParserCombineOps[A](p: P[A]) { \begin_layout Plain Layout - def or(q: => P[A]): P[A] = P { s => // Important: the argument - `q` must be lazy. + def or(q: => P[A]): P[A] = P { s => // Important: `q` must be lazy. \end_layout \begin_layout Plain Layout @@ -9237,19 +9142,18 @@ implicit class ParserCombineOps[A](p: P[A]) { \begin_layout Plain Layout - result match { // If `p` failed to parse the - string `s`, + result match { // If `p` failed to parse the string + `s`, \end_layout \begin_layout Plain Layout - case Left(err) => q.run(s) // ignore the error from `p` - and run `q`. + case Left(err) => q.run(s) // ignore the error from `p` and run `q`. \end_layout \begin_layout Plain Layout - case Right(x) => (Right(x), rest) // Otherwise, use the result + case Right(x) => (Right(x), rest) // Otherwise, use the result of running `p`. \end_layout @@ -9307,8 +9211,7 @@ p \begin_layout Standard Using these combinators, we write a first attempt at parsing the toy language. - Since the language allows us to have arbitrarily deep nesting of the tags - + Since the language permits arbitrarily deep nesting of the tags \begin_inset listings inline true status open @@ -11269,7 +11172,8 @@ Then we need to show that to arbitrary arguments and write: \begin_inset Formula \begin{align*} - & \text{map}_{2}^{\prime}\,(p\times q)(f)=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}=\text{map}_{2}\,(p\times q)(\text{id})\,\gunderline{\triangleright\,f^{\uparrow L}}\\ + & \text{map}_{2}^{\prime}\,(p\times q)(f)=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\\ + & =\text{map}_{2}\,(p\times q)(\text{id})\,\gunderline{\triangleright\,f^{\uparrow L}}\\ \text{naturality law of }\text{map}_{2}:\quad & =\text{map}_{2}\,(p\times q)(\text{id}\bef f)=\text{map}_{2}\,(p\times q)(f)\quad. \end{align*} @@ -11362,9 +11266,10 @@ Then we need to show that and write: \begin_inset Formula -\[ -\text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{map}_{2}\,(p\times q)(\text{id}^{:A\times B\rightarrow A\times B})=(p\times q)\triangleright\text{zip}\triangleright\text{id}^{\uparrow L}=(p\times q)\triangleright\text{zip}=\text{zip}\,(p\times q)\quad. -\] +\begin{align*} + & \text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{map}_{2}\,(p\times q)(\text{id}^{:A\times B\rightarrow A\times B})=(p\times q)\triangleright\text{zip}\triangleright\text{id}^{\uparrow L}\\ + & \quad=(p\times q)\triangleright\text{zip}=\text{zip}\,(p\times q)\quad. +\end{align*} \end_inset @@ -11399,7 +11304,8 @@ zip : \begin_inset Formula \begin{align*} - & \gunderline{\text{map}_{2}\,(p\times q)(f)}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright(f\bef g)^{\uparrow L}\\ + & \gunderline{\text{map}_{2}\,(p\times q)(f)}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\triangleright g^{\uparrow L}\\ + & =(p\times q)\triangleright\text{zip}\triangleright(f\bef g)^{\uparrow L}\\ \text{definition of }\text{map}_{2}\text{ via }\text{zip}:\quad & =\text{map}_{2}\,(p\times q)(f\bef g)\quad. \end{align*} @@ -11682,8 +11588,7 @@ F^{A}\ar[ru]\sp(0.45){f^{\uparrow L}}\ar[rr]\sb(0.43){\text{fmap}_{2}\,(f^{:A\ri \begin_inset Formula \begin{align*} - & \text{fmap}_{2}\,(f^{:A\rightarrow B\rightarrow C})=f^{\uparrow L}\bef\text{ap}^{B,C}\quad,\\ - & \text{ap}^{A,B}=\text{fmap}_{2}\,(\text{id}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow B})\quad. + & \text{fmap}_{2}\,(f^{:A\rightarrow B\rightarrow C})=f^{\uparrow L}\bef\text{ap}^{B,C}\quad,\quad\quad\text{ap}^{A,B}=\text{fmap}_{2}\,(\text{id}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow B})\quad. \end{align*} \end_inset @@ -11961,7 +11866,8 @@ Then we need to show that to arbitrary arguments and write: \begin_inset Formula \begin{align*} - & \text{fmap}_{2}^{\prime}\,(f^{:A\rightarrow B\rightarrow C})(p^{:L^{A}})=p\triangleright f^{\uparrow L}\triangleright\text{ap}=\text{fmap}_{2}\,(\text{id})(p\triangleright f^{\uparrow L})\\ + & \text{fmap}_{2}^{\prime}\,(f^{:A\rightarrow B\rightarrow C})(p^{:L^{A}})=p\triangleright f^{\uparrow L}\triangleright\text{ap}\\ + & =\text{fmap}_{2}\,(\text{id})(p\triangleright f^{\uparrow L})\\ \text{naturality law of }\text{fmap}_{2}:\quad & =\text{fmap}_{2}\,(f\bef\text{id})(p)=\text{fmap}_{2}\,(f)(p)\quad. \end{align*} @@ -12274,9 +12180,10 @@ ap are equivalent assuming the following naturality laws: \begin_inset Formula -\[ -(f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\bef(f\boxtimes\text{id})^{\uparrow L}\quad,\quad\big(\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})\big)\triangleright(f^{:B\rightarrow C})^{\uparrow L}=\text{ap}\big(r\triangleright(x^{:A\rightarrow B}\rightarrow x\bef f)^{\uparrow L}\big)(p)\quad. -\] +\begin{align*} + & (f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\bef(f\boxtimes\text{id})^{\uparrow L}\quad,\\ + & \big(\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})\big)\triangleright(f^{:B\rightarrow C})^{\uparrow L}=\text{ap}\big(r\triangleright(x^{:A\rightarrow B}\rightarrow x\bef f)^{\uparrow L}\big)(p)\quad. +\end{align*} \end_inset @@ -12372,9 +12279,10 @@ eval The code of these fully parametric functions follows from their types. Then we can write: \begin_inset Formula -\[ -\text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\quad,\quad\quad\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\quad. -\] +\begin{align*} + & \text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\quad,\\ + & \text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\quad. +\end{align*} \end_inset @@ -12507,7 +12415,8 @@ Then we need to show that \begin_inset Formula \begin{align*} \text{expect to equal }\text{zip}\,(p\times q):\quad & \text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\\ -\text{definition of }\text{ap}:\quad & =\big((p\triangleright\text{pair}^{\uparrow L})\times q\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}=(p\times q)\triangleright\gunderline{(\text{pair}^{\uparrow L}\times\text{id})\bef\text{zip}}\bef\text{eval}^{\uparrow L}\\ +\text{definition of }\text{ap}:\quad & =\big((p\triangleright\text{pair}^{\uparrow L})\times q\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ + & =(p\times q)\triangleright\gunderline{(\text{pair}^{\uparrow L}\times\text{id})\bef\text{zip}}\bef\text{eval}^{\uparrow L}\\ \text{naturality law of }\text{zip}:\quad & =(p\times q)\triangleright\text{zip}\bef\gunderline{(\text{pair}\boxtimes\text{id})^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ \text{use Eq.~(\ref{eq:pair-and-eval-property-derivation1})}:\quad & =(p\times q)\triangleright\text{zip}\bef\text{id}^{\uparrow L}=(p\times q)\triangleright\text{zip}\quad. \end{align*} @@ -12538,11 +12447,12 @@ zip \end_inset - will satisfy its required naturality law: + will obey its naturality law: \begin_inset Formula \begin{align*} \text{left-hand side}:\quad & \big(\text{ap}\,(r)(p)\big)\triangleright f^{\uparrow L}=(r\times p)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\bef f^{\uparrow L}\quad,\\ -\text{right-hand side}:\quad & \text{ap}\big(r\triangleright(x\rightarrow x\bef f)^{\uparrow L}\big)(p)=\big((r\triangleright(x\rightarrow x\bef f)^{\uparrow L})\times p\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ +\text{right-hand side}:\quad & \text{ap}\big(r\triangleright(x\rightarrow x\bef f)^{\uparrow L}\big)(p)\\ + & \quad=\big((r\triangleright(x\rightarrow x\bef f)^{\uparrow L})\times p\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ \text{naturality law of }\text{zip}:\quad & \quad=(r\times p)\triangleright\text{zip}\bef\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)^{\uparrow L}\bef\text{eval}^{\uparrow L}\quad. \end{align*} @@ -12569,8 +12479,9 @@ Apply both sides to an arbitrary pair \begin_inset Formula \begin{align*} \text{left-hand side}:\quad & (g^{:A\rightarrow B}\times a^{:A})\triangleright\text{eval}\bef f=(g\times a)\triangleright\text{eval}\triangleright f=g(a)\triangleright f=a\triangleright g\triangleright f\quad,\\ -\text{right-hand side}:\quad & (g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\bef\text{eval}=(g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\triangleright\text{eval}\\ - & \quad=\big((g\bef f)\times a\big)\triangleright\text{eval}=a\triangleright g\bef f=a\triangleright g\bef f\quad. +\text{right-hand side}:\quad & (g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\bef\text{eval}\\ + & \quad=(g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\triangleright\text{eval}=\big((g\bef f)\times a\big)\triangleright\text{eval}\\ + & \quad=a\triangleright g\bef f=a\triangleright g\triangleright f\quad. \end{align*} \end_inset @@ -12651,7 +12562,8 @@ Then we need to show that We write: \begin_inset Formula \begin{align*} - & \text{ap}^{\prime}\,(r)(p)=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}=\big(\text{ap}\,(r\triangleright\text{pair}^{\uparrow L})(p)\gunderline{\big)\triangleright\text{eval}^{\uparrow L}}\quad.\\ + & \text{ap}^{\prime}\,(r)(p)=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\\ + & =\big(\text{ap}\,(r\triangleright\text{pair}^{\uparrow L})(p)\gunderline{\big)\triangleright\text{eval}^{\uparrow L}}\\ \text{naturality law of }\text{ap}:\quad & =\text{ap}\big(r\,\gunderline{\triangleright\,\text{pair}^{\uparrow L}\triangleright(x^{:A\rightarrow\left(A\rightarrow B\right)\times A}\rightarrow x\bef\text{eval})^{\uparrow L}}\big)(p)\\ \text{composition under }^{\uparrow L}:\quad & =\text{ap}\big(r\triangleright(\text{pair}\bef(x\rightarrow x\bef\text{eval}))^{\uparrow L}\big)(p)\quad. \end{align*} @@ -12686,7 +12598,8 @@ To see this, apply both sides to an arbitrary value \begin_inset Formula \begin{align*} \text{expect to equal }f:\quad & f^{:A\rightarrow B}\triangleright\text{pair}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow\left(A\rightarrow B\right)\times A}\bef(x^{:A\rightarrow\left(A\rightarrow B\right)\times A}\rightarrow x\bef\text{eval})\\ - & =(a^{:A}\rightarrow f\times a)\bef(x\rightarrow x\bef\text{eval})=a^{:A}\rightarrow(f\times a)\triangleright\text{eval}=a^{:A}\rightarrow f(a)=f\quad. + & =(a^{:A}\rightarrow f\times a)\bef(x\rightarrow x\bef\text{eval})=a^{:A}\rightarrow(f\times a)\triangleright\text{eval}\\ + & =a^{:A}\rightarrow f(a)=f\quad. \end{align*} \end_inset @@ -12695,7 +12608,7 @@ To see this, apply both sides to an arbitrary value \end_layout \begin_layout Standard -Finally, we show that the +Finally, we show that \begin_inset listings inline true status open @@ -12707,7 +12620,7 @@ zip \end_inset - method will satisfy its naturality law if defined via + will obey its naturality law if defined via \begin_inset listings inline true status open @@ -12724,7 +12637,8 @@ ap \begin{align*} \text{left-hand side}:\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright(f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\big((p\triangleright f^{\uparrow L})\times q\big)\\ \text{express }\text{zip}\text{ via }\text{ap}:\quad & \quad=\text{ap}\big(p\triangleright f^{\uparrow L}\triangleright\text{pair}^{\uparrow L})(q)=\text{ap}\big(p\triangleright(f\bef\text{pair})^{\uparrow L})(q)\quad,\\ -\text{right-hand side}:\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright\text{zip}\triangleright(f\boxtimes\text{id})^{\uparrow L}=\big(\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\gunderline{\big)\triangleright(f\boxtimes\text{id})^{\uparrow L}}\\ +\text{right-hand side}:\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright\text{zip}\triangleright(f\boxtimes\text{id})^{\uparrow L}\\ + & \quad=\big(\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\gunderline{\big)\triangleright(f\boxtimes\text{id})^{\uparrow L}}\\ \text{naturality law of }\text{ap}:\quad & \quad=\text{ap}\big(p\triangleright\text{pair}^{\uparrow L}\triangleright(x\rightarrow x\bef(f\boxtimes\text{id}))^{\uparrow L}\big)(q)\quad. \end{align*} @@ -12757,9 +12671,12 @@ pair into both sides: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & f\bef\text{pair}=(z^{:Z}\rightarrow f(z))\bef(a^{:A}\rightarrow b^{:B}\rightarrow a\times b)=z\rightarrow b\rightarrow f(z)\times b\quad,\\ -\text{right-hand side}:\quad & \text{pair}\bef(x\rightarrow x\bef(f\boxtimes\text{id}))=(z^{:Z}\rightarrow b^{:B}\rightarrow z\times b)\bef(x^{:B\rightarrow Z\times B}\rightarrow x\bef(f\boxtimes\text{id}))\\ -\text{compute composition}:\quad & \quad=z\rightarrow(b\rightarrow z\times b)\bef(f\boxtimes\text{id})=z\rightarrow b\rightarrow f(z)\times b\quad. +\text{left-hand side}:\quad & f\bef\text{pair}=(z^{:Z}\rightarrow f(z))\bef(a^{:A}\rightarrow b^{:B}\rightarrow a\times b)\\ + & \quad=z\rightarrow b\rightarrow f(z)\times b\quad,\\ +\text{right-hand side}:\quad & \text{pair}\bef(x\rightarrow x\bef(f\boxtimes\text{id}))\\ + & \quad=(z^{:Z}\rightarrow b^{:B}\rightarrow z\times b)\bef(x^{:B\rightarrow Z\times B}\rightarrow x\bef(f\boxtimes\text{id}))\\ +\text{compute composition}:\quad & \quad=z\rightarrow(b\rightarrow z\times b)\bef(f\boxtimes\text{id})\\ + & \quad=z\rightarrow b\rightarrow f(z)\times b\quad. \end{align*} \end_inset @@ -14331,9 +14248,11 @@ zip Begin with the associativity law and write its two sides separately: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{map}_{2}\,(p^{:L^{A}}\times\text{map}_{2}\,(q^{:L^{B}}\times r^{:L^{C}})(\text{id}^{:B\times C\rightarrow B\times C}))\big(a^{:A}\times(b^{:B}\times c^{:C})\rightarrow g(a\times b\times c)\big)\\ + & \quad\text{left-hand side}:\quad\\ + & \text{map}_{2}\,(p^{:L^{A}}\times\text{map}_{2}\,(q^{:L^{B}}\times r^{:L^{C}})(\text{id}^{:B\times C\rightarrow B\times C}))\big(a^{:A}\times(b^{:B}\times c^{:C})\rightarrow g(a\times b\times c)\big)\\ & \quad=\text{zip}\,(p\times\text{zip}\,(q\times r))\triangleright(a\times(b\times c)\rightarrow g(a\times b\times c))^{\uparrow L}\\ -\text{right-hand side}:\quad & \overset{!}{=}\text{map}_{2}\,(\text{map}_{2}\,(p\times q)(\text{id})\times r)\big((a^{:A}\times b^{:B})\times c^{:C}\rightarrow g(a\times b\times c)\big)\\ + & \quad\text{right-hand side}:\quad\\ + & \overset{!}{=}\text{map}_{2}\,(\text{map}_{2}\,(p\times q)(\text{id})\times r)\big((a^{:A}\times b^{:B})\times c^{:C}\rightarrow g(a\times b\times c)\big)\\ & \quad=\text{zip}\,(\text{zip}\,(p\times q)\times r)\triangleright((a\times b)\times c)\rightarrow g(a\times b\times c))^{\uparrow L}\quad. \end{align*} @@ -14401,17 +14320,25 @@ noprefix "false" \end_inset A type diagram illustrating this law is shown below: +\begin_inset Preview + +\begin_layout Standard \begin_inset Formula \[ -\xymatrix{\xyScaleY{1.4pc}\xyScaleX{1.7pc} & L^{A\times B}\times L^{C}\ar[r]\sp(0.5){\text{zip}} & L^{(A\times B)\times C}\ar[rd]\sp(0.5){\varepsilon_{12,3}^{\uparrow L}} & & L^{A\times(B\times C)}\ar[ld]\sb(0.5){\varepsilon_{1,23}^{\uparrow L}} & L^{A}\times L^{B\times C}\ar[l]\sb(0.5){\text{zip}}\\ -L^{A}\times L^{B}\ar[r]\sp(0.55){\text{zip}} & L^{A\times B}\ar[u] & & L^{A\times B\times C} & & L^{B\times C}\ar[u] & L^{B}\times L^{C}\ar[l]\sb(0.5){\text{zip}}\\ - & & p:L^{A}\ar[llu]\ar[rrruu] & q:L^{B}\ar[lllu]\ar[rrru] & r:L^{C}\ar[rru]\ar[llluu] +\xymatrix{\xyScaleY{1.4pc}\xyScaleX{1.7pc}L^{A\times B}\times L^{C}\ar[r]\sp(0.5){\text{zip}} & L^{(A\times B)\times C}\ar[rd]\sp(0.5){\varepsilon_{12,3}^{\uparrow L}} & & L^{A\times(B\times C)}\ar[ld]\sb(0.5){\varepsilon_{1,23}^{\uparrow L}} & L^{A}\times L^{B\times C}\ar[l]\sb(0.5){\text{zip}}\\ +L^{A}\times L^{B}\ar[r]\sp(0.55){\text{zip}} & L^{A\times B}\ar[lu] & L^{A\times B\times C} & L^{B\times C}\ar[ru] & L^{B}\times L^{C}\ar[l]\sb(0.5){\text{zip}}\\ + & p:L^{A}\ar[lu]\ar[rrruu] & q:L^{B}\ar[llu]\ar[rru] & r:L^{C}\ar[ru]\ar[llluu] } \] \end_inset +\end_layout + +\end_inset + + \end_layout \begin_layout Standard @@ -14579,7 +14506,7 @@ noprefix "false" \end_layout \begin_layout Standard -We now turn to the identity laws. +Turn to the identity laws. Substitute Eq. \begin_inset space ~ \end_inset @@ -14615,7 +14542,7 @@ map2 \end_inset -We may remove the common function +Remove the common function \begin_inset Formula $g^{\uparrow L}$ \end_inset @@ -14627,7 +14554,7 @@ We may remove the common function \end_inset -We express +Express \begin_inset listings inline true status open @@ -15510,9 +15437,10 @@ zip (in addition to the standard applicative laws): \begin_inset Formula -\begin{equation} -\text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{zip}\,(q\times p)\triangleright(b^{:B}\times a^{:A}\rightarrow a\times b)^{\uparrow L}\quad\text{or equivalently}:\quad\text{swap}\bef\text{zip}=\text{zip}\bef\text{swap}^{\uparrow L}\quad.\label{eq:commutativity-law-of-zip} -\end{equation} +\begin{align} + & \text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{zip}\,(q\times p)\triangleright(b^{:B}\times a^{:A}\rightarrow a\times b)^{\uparrow L}\nonumber \\ +\text{or equivalently}:\quad & \text{swap}\bef\text{zip}=\text{zip}\bef\text{swap}^{\uparrow L}\quad.\label{eq:commutativity-law-of-zip} +\end{align} \end_inset @@ -15590,11 +15518,7 @@ p\,\,\text{zip}\,\,q\cong q\,\,\text{zip}\,\,p\quad. \end_inset - -\end_layout - -\begin_layout Standard -This definition agrees with that of the commutative monad (see Exercise +This definition agrees with that of the commutative monad (Exercise \begin_inset space ~ \end_inset @@ -15609,7 +15533,8 @@ noprefix "false" \end_inset ). - A monad's commutativity is defined via code that is equivalent to the + A monad's commutativity property is defined via code that is equivalent + to the \begin_inset listings inline true status open @@ -15692,7 +15617,7 @@ flatMap \end_inset -) must satisfy the following commutativity property: +) must satisfy the commutativity property: \begin_inset Formula \[ \text{map}_{2}(p\times q)(f)=\text{map}_{2}(q\times p)\big(b\times a\rightarrow f(a\times b)\big)\quad. @@ -16195,18 +16120,41 @@ zip functions differ by the permutation of the effects: \begin_inset Formula -\[ -\text{zip}\left(p\times q\right)\triangleq p\triangleright\text{flm}_{L}(a\rightarrow q\triangleright(b\rightarrow a\times b)^{\uparrow L})\quad,\quad\quad\text{zip}^{\prime}\left(p\times q\right)=\text{zip}\left(q\times p\right)\triangleright\text{swap}^{\uparrow L}\quad. -\] +\begin{align*} + & \text{zip}\left(p\times q\right)\triangleq p\triangleright\text{flm}_{L}(a\rightarrow q\triangleright(b\rightarrow a\times b)^{\uparrow L})\quad,\\ + & \text{zip}^{\prime}\left(p\times q\right)\triangleq q\triangleright\text{flm}_{L}(b\rightarrow p\triangleright(a\rightarrow a\times b)^{\uparrow L})=\text{zip}\left(q\times p\right)\triangleright\text{swap}^{\uparrow L}\quad. +\end{align*} \end_inset For commutative monads, there will be no difference between -\begin_inset Formula $\text{zip}^{\prime}$ +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +zip +\end_layout + +\end_inset + + +\begin_inset Formula $^{\prime}$ \end_inset and -\begin_inset Formula $\text{zip}$ +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +zip +\end_layout + \end_inset . @@ -16379,7 +16327,7 @@ noprefix "false" \begin_inset Formula \begin{align*} & p\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,r)\cong\gunderline{(p\,\,\text{zip}\,\,q)}\,\,\text{zip}\,\,\gunderline r\\ -\text{twice use the commutativity law of }\text{zip}:\quad & \cong r\,\,\text{zip}\,\,(\gunderline p\,\,\text{zip}\,\,\gunderline q)\cong r\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,p)\quad. +\text{use the commutativity law of }\text{zip}:\quad & \cong r\,\,\text{zip}\,\,(\gunderline p\,\,\text{zip}\,\,\gunderline q)\cong r\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,p)\quad. \end{align*} \end_inset @@ -16465,11 +16413,7 @@ zip \end_inset if we know that the commutativity law holds. - We just need to write the code for -\begin_inset Formula $\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)$ -\end_inset - - and swap + We just need to swap \begin_inset Formula $p^{:L^{A}}$ \end_inset @@ -16477,8 +16421,13 @@ zip \begin_inset Formula $r^{:L^{C}}$ \end_inset - in that code. - The result must be the same up to swapping the result values of types + in the code for +\begin_inset Formula $\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)$ +\end_inset + +. + The result must be the same as when swapping the result values of types + \begin_inset Formula $A$ \end_inset @@ -17114,7 +17063,8 @@ To verify the right identity law: \begin_inset Formula \begin{align*} \text{expect to equal }p\triangleright\text{iru}^{\uparrow L}:\quad & \text{zip}_{L}(p^{:F^{G^{A}}}\times\text{wu}_{L})=(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\\ -\text{right identity law of }\text{zip}_{F}:\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}=p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})}\big)^{\uparrow F}\\ +\text{right identity law of }\text{zip}_{F}:\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}\\ + & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})}\big)^{\uparrow F}\\ \text{right identity law of }\text{zip}_{G}:\quad & =p\triangleright(\gunderline{g\rightarrow g\,\triangleright}\,\text{iru}^{\uparrow G})^{\uparrow F}=p\triangleright(\text{iru}^{\uparrow G})^{\uparrow F}=p\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} @@ -17131,10 +17081,14 @@ To verify the associativity law, first substitute the definition of into one side: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{L}\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\varepsilon_{1,23}^{\uparrow L}=\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ -\text{definition of }^{\uparrow L}:\quad & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}\\ -\text{naturality law of }\text{zip}_{F}:\quad & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}}\\ -\text{composition under }^{\uparrow F}:\quad & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\varepsilon_{1,23}^{\uparrow G}\big)^{\uparrow F}\quad. + & \quad\text{left-hand side}:\quad\\ + & \text{zip}_{L}\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\varepsilon_{1,23}^{\uparrow L}=\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ + & \quad\text{definition of }^{\uparrow L}:\quad\\ + & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}\\ + & \quad\text{naturality law of }\text{zip}_{F}:\quad\\ + & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}}\\ + & \quad\text{composition under }^{\uparrow F}:\quad\\ + & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\varepsilon_{1,23}^{\uparrow G}\big)^{\uparrow F}\quad. \end{align*} \end_inset @@ -17142,10 +17096,14 @@ To verify the associativity law, first substitute the definition of Now rewrite the right-hand side in a similar way: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & \text{zip}_{L}\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\varepsilon_{12,3}^{\uparrow L}=\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow L}\\ -\text{definition of }^{\uparrow L}:\quad & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}\\ -\text{naturality law of }\text{zip}_{F}:\quad & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}}\\ -\text{composition under }^{\uparrow F}:\quad & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\varepsilon_{12,3}^{\uparrow G}\big)^{\uparrow F}\quad. + & \quad\text{right-hand side}:\quad\\ + & \text{zip}_{L}\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\varepsilon_{12,3}^{\uparrow L}=\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow L}\\ + & \quad\text{definition of }^{\uparrow L}:\quad\\ + & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}\\ + & \quad\text{naturality law of }\text{zip}_{F}:\quad\\ + & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}}\\ + & \quad\text{composition under }^{\uparrow F}:\quad\\ + & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\varepsilon_{12,3}^{\uparrow G}\big)^{\uparrow F}\quad. \end{align*} \end_inset @@ -17202,7 +17160,7 @@ noprefix "false" \begin{align*} \text{expect to equal }(\text{zip}_{L}\bef\text{swap}^{\uparrow L}):\quad & \text{swap}\bef\text{zip}_{L}=\gunderline{\text{swap}\bef\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\\ \text{commutativity law of }F:\quad & =\text{zip}_{F}\bef\gunderline{\text{swap}^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}=\text{zip}_{F}\bef(\gunderline{\text{swap}\bef\text{zip}_{G}})^{\uparrow F}\\ -\text{commutativity law of }G\text{ under }^{\uparrow F}:\quad & =\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{swap}^{\uparrow G\uparrow F}=\text{zip}_{L}\bef\text{swap}^{\uparrow L}\quad. +\text{commutativity law of }G\text{ under }^{\uparrow F}:\quad & =\gunderline{\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}}\bef\text{swap}^{\gunderline{\uparrow G\uparrow F}}=\text{zip}_{L}\bef\text{swap}^{\uparrow L}\quad. \end{align*} \end_inset @@ -17331,10 +17289,14 @@ To verify the left identity law of : \begin_inset Formula \begin{align*} -\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow L}:\quad & \text{zip}_{L}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{L}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ -\text{definition of }\text{zip}_{L}:\quad & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ -\text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad & =(p\triangleright\text{ilu}^{\uparrow F})\times(q\triangleright\text{ilu}^{\uparrow G})=(p\times q)\triangleright(\text{ilu}^{\uparrow F}\boxtimes\text{ilu}^{\uparrow G})\\ -\text{definition of }^{\uparrow L}:\quad & =(p\times q)\triangleright\text{ilu}^{\uparrow L}\quad. + & \quad\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow L}:\quad\\ + & \text{zip}_{L}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{L}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ + & \quad\text{definition of }\text{zip}_{L}:\quad\\ + & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ + & \quad\text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad\\ + & =(p\triangleright\text{ilu}^{\uparrow F})\times(q\triangleright\text{ilu}^{\uparrow G})=(p\times q)\triangleright(\text{ilu}^{\uparrow F}\boxtimes\text{ilu}^{\uparrow G})\\ + & \quad\text{definition of }^{\uparrow L}:\quad\\ + & =(p\times q)\triangleright\text{ilu}^{\uparrow L}\quad. \end{align*} \end_inset @@ -17350,10 +17312,14 @@ To verify the right identity law of : \begin_inset Formula \begin{align*} -\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow L}:\quad & \text{zip}_{L}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{L}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ -\text{definition of }\text{zip}_{L}:\quad & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ -\text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad & =(p\triangleright\text{iru}^{\uparrow F})\times(q\triangleright\text{iru}^{\uparrow G})=(p\times q)\triangleright(\text{iru}^{\uparrow F}\boxtimes\text{iru}^{\uparrow G})\\ -\text{definition of }^{\uparrow L}:\quad & =(p\times q)\triangleright\text{iru}^{\uparrow L}\quad. + & \quad\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow L}:\quad\\ + & \text{zip}_{L}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{L}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ + & \quad\text{definition of }\text{zip}_{L}:\quad\\ + & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ + & \quad\text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad\\ + & =(p\triangleright\text{iru}^{\uparrow F})\times(q\triangleright\text{iru}^{\uparrow G})=(p\times q)\triangleright(\text{iru}^{\uparrow F}\boxtimes\text{iru}^{\uparrow G})\\ + & \quad\text{definition of }^{\uparrow L}:\quad\\ + & =(p\times q)\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} \end_inset @@ -17370,7 +17336,7 @@ To verify the associativity law, begin with its left-hand side and use the : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times\text{zip}_{L}\big((q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\big)\triangleright\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ + & \text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times\text{zip}_{L}\big((q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\big)\triangleright\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ & =\text{zip}_{L}\big((p_{1}\times p_{2})\times\big(\text{zip}_{F}(q_{1}\times r_{1})\times\text{zip}_{G}(q_{2}\times r_{2})\big)\big)\triangleright\big(\varepsilon_{1,23}^{\uparrow F}\boxtimes\varepsilon_{1,23}^{\uparrow G}\big)\\ & =\big(\gunderline{\text{zip}_{F}\big(p_{1}\times\text{zip}_{F}(q_{1}\times r_{1})\big)\triangleright\varepsilon_{1,23}^{\uparrow F}}\big)\times\big(\gunderline{\text{zip}_{G}\big(p_{2}\times\text{zip}_{G}(q_{2}\times r_{2})\big)\triangleright\varepsilon_{1,23}^{\uparrow G}}\big)\quad. \end{align*} @@ -17380,7 +17346,7 @@ To verify the associativity law, begin with its left-hand side and use the The right-hand side is rewritten in a similar way: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & \text{zip}_{L}\big(\text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times(q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\big)\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\triangleright\gunderline{\varepsilon_{12,3}^{\uparrow L}}\\ + & \text{zip}_{L}\big(\text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times(q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\big)\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\triangleright\gunderline{\varepsilon_{12,3}^{\uparrow L}}\\ & =\text{zip}_{L}\big(\big(\text{zip}_{F}(p_{1}\times q_{1})\times\text{zip}_{G}(p_{2}\times q_{2})\big)\times(r_{1}\times r_{2})\big)\big)\triangleright\big(\varepsilon_{12,3}^{\uparrow F}\boxtimes\varepsilon_{12,3}^{\uparrow G}\big)\\ & =\big(\gunderline{\text{zip}_{F}\big(\text{zip}_{F}(p_{1}\times q_{1})\times r_{1}\big)\triangleright\varepsilon_{12,3}^{\uparrow F}}\big)\times\big(\gunderline{\text{zip}_{G}\big(\text{zip}_{G}(p_{2}\times q_{2})\times r_{2}\big)\triangleright\varepsilon_{12,3}^{\uparrow G}}\big)\quad. \end{align*} @@ -17415,10 +17381,14 @@ To verify the commutativity law of : \begin_inset Formula \begin{align*} -\text{expect to equal }\text{zip}_{L}\big((p\times q)\times(m\times n)\big):\quad & \text{zip}_{L}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow L}\\ -\text{definitions of }\text{zip}_{L}\text{ and }^{\uparrow L}:\quad & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright(\text{swap}^{\uparrow F}\boxtimes\text{swap}^{\uparrow G})\\ -\text{definition of }\boxtimes:\quad & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\big)\\ -\text{commutativity laws of }F\text{ and }G:\quad & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{L}\big((p\times q)\times(m\times n)\big)\quad. + & \quad\text{expect to equal }\text{zip}_{L}\big((p\times q)\times(m\times n)\big):\quad\\ + & \text{zip}_{L}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow L}\\ + & \quad\text{definitions of }\text{zip}_{L}\text{ and }^{\uparrow L}:\quad\\ + & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright(\text{swap}^{\uparrow F}\boxtimes\text{swap}^{\uparrow G})\\ + & \quad\text{definition of }\boxtimes:\quad\\ + & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\big)\\ + & \quad\text{commutativity laws of }F\text{ and }G:\quad\\ + & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{L}\big((p\times q)\times(m\times n)\big)\quad. \end{align*} \end_inset @@ -17528,7 +17498,8 @@ If is applicative: \begin_inset Formula \begin{align*} - & \text{zip}_{L}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\quad\quad\text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{L}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\\ + & \text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} & Z & F^{A\times B}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{A}\times Z & \_^{:F^{A}}\times z\rightarrow z & \bbnum 0\\ @@ -17619,7 +17590,8 @@ To verify the left identity law, we use the left identity law of : \begin_inset Formula \begin{align*} - & \text{zip}_{L}(\text{wu}_{L}\times p^{:Z+F^{B}})=\text{zip}_{L}((\bbnum 0+\text{wu}_{F})\times p)=(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(\text{wu}_{L}\times p^{:Z+F^{B}})=\text{zip}_{L}((\bbnum 0+\text{wu}_{F})\times p)\\ + & =(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} & Z & F^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times Z & \_^{:F^{\bbnum 1}}\times z\rightarrow z & \bbnum 0\\ F^{\bbnum 1}\times F^{B} & \bbnum 0 & \text{zip}_{F} @@ -17632,7 +17604,8 @@ F^{B} & \bbnum 0 & k^{:F^{B}}\rightarrow\gunderline{\text{zip}_{F}(\text{wu}_{F} & Z & F^{\bbnum 1\times B}\\ \hline Z & \text{id} & \bbnum 0\\ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F} -\end{array}\,=p\triangleright\text{ilu}^{\uparrow L}\quad. +\end{array}\\ + & =p\triangleright\text{ilu}^{\uparrow L}\quad. \end{align*} \end_inset @@ -17644,7 +17617,8 @@ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F} To verify the right identity law, we write a similar calculation: \begin_inset Formula \begin{align*} - & \text{zip}_{L}(p^{:Z+F^{A}}\times\text{wu}_{L})=\text{zip}_{L}(p\times(\bbnum 0+\text{wu}_{F}))=(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(p^{:Z+F^{A}}\times\text{wu}_{L})=\text{zip}_{L}(p\times(\bbnum 0+\text{wu}_{F}))\\ + & =(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z\times F^{\bbnum 1} & z\times\_^{:F^{\bbnum 1}}\rightarrow z & \bbnum 0\\ F^{A}\times F^{\bbnum 1} & \bbnum 0 & \text{zip}_{F} @@ -17657,7 +17631,8 @@ F^{A} & \bbnum 0 & k^{:F^{A}}\rightarrow\gunderline{\text{zip}_{F}(k\times\text{ & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & k\rightarrow k\triangleright\text{iru}^{\uparrow F} -\end{array}\,=p\triangleright\text{iru}^{\uparrow L}\quad. +\end{array}\\ + & =p\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} \end_inset @@ -17945,13 +17920,14 @@ swap with the relevant types: \begin_inset Formula \begin{align*} - & \text{swap}\bef\text{zip}_{L}=\,\begin{array}{|c||cccc|} +\text{swap}\bef\text{zip}_{L} & =\,\begin{array}{|c||cccc|} & Z\times Z & F^{B}\times Z & Z\times F^{A} & F^{B}\times F^{A}\\ \hline Z\times Z & \text{swap} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ F^{A}\times Z & \bbnum 0 & \bbnum 0 & \text{swap} & \bbnum 0\\ Z\times F^{B} & \bbnum 0 & \text{swap} & \bbnum 0 & \bbnum 0\\ F^{A}\times F^{B} & \bbnum 0 & \bbnum 0 & \bbnum 0 & \text{swap} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{B}\times Z & \_\times z\rightarrow z & \bbnum 0\\ @@ -18053,7 +18029,8 @@ If is also applicative: \begin_inset Formula \begin{align*} - & \text{zip}_{L}:(A+F^{A})\times(B+F^{B})\rightarrow A\times B+F^{A\times B}\quad,\quad\quad\text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{L}:(A+F^{A})\times(B+F^{B})\rightarrow A\times B+F^{A\times B}\quad,\\ + & \text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} & A\times B & F^{A\times B}\\ \hline A\times B & \text{id} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes\text{pu}_{F})\bef\text{zip}_{F}\\ @@ -18853,9 +18830,10 @@ zip : \begin_inset Formula -\begin{equation} -\text{ex}_{H}(\text{zip}_{H}(p^{:H^{A}}\times q^{:H^{B}}))=\text{ex}_{H}(p)\times\text{ex}_{H}(q)\quad,\quad\text{or equivalently}:\quad\text{zip}_{H}\bef\text{ex}_{H}=\text{ex}_{H}\boxtimes\text{ex}_{H}\quad.\label{eq:compatibility-law-of-extract-and-zip} -\end{equation} +\begin{align} + & \text{ex}_{H}(\text{zip}_{H}(p^{:H^{A}}\times q^{:H^{B}}))=\text{ex}_{H}(p)\times\text{ex}_{H}(q)\quad,\nonumber \\ +\text{or equivalently}:\quad & \text{zip}_{H}\bef\text{ex}_{H}=\text{ex}_{H}\boxtimes\text{ex}_{H}\quad.\label{eq:compatibility-law-of-extract-and-zip} +\end{align} \end_inset @@ -19226,7 +19204,8 @@ noprefix "false" ) holds: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{ex}_{F}\big(\text{zip}_{F}\big((z_{1}\times r_{1})\times(z_{2}\times r_{2})\big)\big)=\text{ex}_{F}\big((z_{1}\oplus z_{2})\times(z^{:Z}\rightarrow r_{1}(z)\times r_{2}(z))\big)\\ +\text{left-hand side}:\quad & \text{ex}_{F}\big(\text{zip}_{F}\big((z_{1}\times r_{1})\times(z_{2}\times r_{2})\big)\big)\\ + & \quad=\text{ex}_{F}\big((z_{1}\oplus z_{2})\times(z^{:Z}\rightarrow r_{1}(z)\times r_{2}(z))\big)\\ & \quad=r_{1}(z_{1}\oplus z_{2})\times r_{2}(z_{1}\oplus z_{2})\quad,\\ \text{right-hand side}:\quad & \text{ex}_{F}(z_{1}\times r_{1})\times\text{ex}_{F}(z_{2}\times r_{2})=r_{1}(z_{1})\times r_{2}(z_{2})\quad. \end{align*} @@ -19378,7 +19357,8 @@ F^{A} & \bbnum 0 & f^{\uparrow F} To verify the left identity law, we begin with its left-hand side: \begin_inset Formula \begin{align*} - & \text{zip}_{L}(\text{wu}_{L}\times p)=\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(\text{wu}_{L}\times p)\\ + & =\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{\bbnum 1}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ H^{\bbnum 1}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ @@ -19450,17 +19430,18 @@ Since the identity laws of are assumed to hold, we can transform the last matrix as: \begin_inset Formula -\[ -\begin{array}{|c||cc|} +\begin{align*} + & \begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & h\rightarrow\text{zip}_{H}(\text{wu}_{H}\times h) & \bbnum 0\\ F^{B} & \bbnum 0 & f\rightarrow\text{zip}_{F}((\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})\times f) -\end{array}\,=\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad=\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & \text{ilu}^{\uparrow H} & \bbnum 0\\ F^{B} & \bbnum 0 & \text{ilu}^{\uparrow F} \end{array}\,=\text{ilu}^{\uparrow L}\quad. -\] +\end{align*} \end_inset @@ -19480,14 +19461,7 @@ The right identity law is verified in a similar way: & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & h\rightarrow\text{zip}_{H}(h\times\text{wu}_{H}) & \bbnum 0\\ F^{A} & \bbnum 0 & f\rightarrow\text{zip}_{F}(f\times(\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})) -\end{array} -\end{align*} - -\end_inset - - -\begin_inset Formula -\begin{align*} +\end{array}\\ & =p\triangleright\,\,\begin{array}{|c||cc|} & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & \text{iru}^{\uparrow H} & \bbnum 0\\ @@ -19656,9 +19630,10 @@ If then we have: \begin_inset Formula -\[ -\text{zip}_{L}(p\times q)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\quad,\quad\quad\text{zip}_{L}(q\times r)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\quad. -\] +\begin{align*} + & \text{zip}_{L}(p\times q)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\quad,\\ + & \text{zip}_{L}(q\times r)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\quad. +\end{align*} \end_inset @@ -19673,8 +19648,10 @@ Now the associativity law of : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad,\\ -\text{right-hand side}:\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. +\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & \quad=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad,\\ +\text{right-hand side}:\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}\\ + & \quad=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. \end{align*} \end_inset @@ -19719,7 +19696,8 @@ The two sides are equal due to the associativity law of The two situations are symmetric, so let us consider the first one: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\,(p)\times\text{toF}\,(\text{zip}_{H}(b\times c)+\bbnum 0)\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad. +\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & =\bbnum 0+\text{zip}_{F}\big(\text{toF}\,(p)\times\text{toF}\,(\text{zip}_{H}(b\times c)+\bbnum 0)\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad. \end{align*} \end_inset @@ -19749,7 +19727,8 @@ toF So, we can rewrite the left-hand side as: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\\ +\text{left-hand side}:\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\\ \text{identity law of }\text{zip}_{F}:\quad & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)^{\uparrow F}\triangleright\varepsilon_{1,23}^{\uparrow F}\\ & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\quad. \end{align*} @@ -19771,7 +19750,8 @@ toF on all arguments: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\\ +\text{right-hand side}:\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}\\ + & =\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\\ & =\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\text{toF}\left(r+\bbnum 0\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. \end{align*} @@ -19886,7 +19866,8 @@ The right-hand side is rewritten to the same code after using the laws of : \begin_inset Formula \begin{align*} - & \text{zip}_{L}\bef\text{swap}^{\uparrow L}=\,\begin{array}{|c||cc|} + & \text{zip}_{L}\bef\text{swap}^{\uparrow L}\\ + & =\,\begin{array}{|c||cc|} & H^{A\times B} & F^{A\times B}\\ \hline H^{A}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ F^{A}\times H^{B} & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{zip}_{F}\\ @@ -19897,7 +19878,7 @@ F^{A}\times F^{B} & \bbnum 0 & \text{zip}_{F} \hline H^{A\times B} & \text{swap}^{\uparrow H} & \bbnum 0\\ F^{A\times B} & \bbnum 0 & \text{swap}^{\uparrow F} \end{array}\\ - & =\,\begin{array}{|c||cc|} + & =\,\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline A\times B & \text{swap}\bef\text{zip}_{H} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{swap}\bef\text{zip}_{F}\\ @@ -20059,7 +20040,11 @@ Here, the fixed types \end_inset are all monoids by assumption. - Statements + To make +\begin_inset Formula $L$ +\end_inset + + into a lawful applicative functor, it remains to use Statements \begin_inset space ~ \end_inset @@ -20087,11 +20072,7 @@ noprefix "false" \end_inset - are then sufficient to make -\begin_inset Formula $L$ -\end_inset - - into a lawful applicative functor. +. \end_layout @@ -21582,13 +21563,14 @@ wrapped unit are defined by: \begin_inset Formula -\[ -(f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} +\begin{align*} + & (f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} & B & N^{B}\\ \hline A & \text{id} & \bbnum 0\\ N^{A} & \bbnum 0 & f^{\uparrow N} -\end{array}\quad,\quad\quad f^{\uparrow N}=f^{\uparrow H}\times f^{\overline{\uparrow L}\uparrow F}=h^{:H^{A}}\times k^{:F^{L^{A}}}\rightarrow(h\triangleright f^{\uparrow H})\times(k\triangleright f^{\overline{\uparrow L}\uparrow F})\quad. -\] +\end{array}\quad,\\ + & f^{\uparrow N}=f^{\uparrow H}\times f^{\overline{\uparrow L}\uparrow F}=h^{:H^{A}}\times k^{:F^{L^{A}}}\rightarrow(h\triangleright f^{\uparrow H})\times(k\triangleright f^{\overline{\uparrow L}\uparrow F})\quad. +\end{align*} \end_inset @@ -23501,8 +23483,10 @@ wu \begin_inset Formula \begin{align} & \text{zip}_{C}:C^{A}\times C^{B}\rightarrow C^{A\times B}\quad,\quad\quad\text{wu}_{C}:C^{\bbnum 1}\quad,\nonumber \\ -\text{associativity law}:\quad & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}\quad,\label{eq:applicative-contrafunctor-associativity-law}\\ -\text{left and right identity laws}:\quad & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=p\quad,\quad\quad\text{zip}_{C}(p\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=p\quad.\label{eq:applicative-contrafunctor-identity-laws} + & \quad\text{associativity law}:\quad\\ + & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}\quad,\label{eq:applicative-contrafunctor-associativity-law}\\ + & \quad\text{left and right identity laws}:\quad\\ + & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=p\quad,\quad\quad\text{zip}_{C}(p\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=p\quad.\label{eq:applicative-contrafunctor-identity-laws} \end{align} \end_inset @@ -23696,9 +23680,10 @@ cmap2 The commutativity law is formulated for applicative contrafunctors like this: \begin_inset Formula -\[ -\text{zip}_{C}(q\times p)=\text{zip}_{C}(p\times q)\triangleright\text{swap}^{\downarrow C}\quad,\quad\quad\text{or equivalently}:\quad\text{swap}\bef\text{zip}_{C}=\text{zip}_{C}\bef\text{swap}^{\downarrow C}\quad. -\] +\begin{align*} + & \text{zip}_{C}(q\times p)=\text{zip}_{C}(p\times q)\triangleright\text{swap}^{\downarrow C}\quad,\\ +\text{or equivalently}:\quad & \text{swap}\bef\text{zip}_{C}=\text{zip}_{C}\bef\text{swap}^{\downarrow C}\quad. +\end{align*} \end_inset @@ -23865,7 +23850,8 @@ noprefix "false" ): \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & \text{zip}_{C}(\text{wu}_{C}\times p^{:F^{G^{A}}})\triangleright\text{ilu}^{\downarrow C}=(\gunderline{\text{pu}_{F}(\text{wu}_{G})}\times p)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}\\ +\text{expect to equal }p:\quad & \text{zip}_{C}(\text{wu}_{C}\times p^{:F^{G^{A}}})\triangleright\text{ilu}^{\downarrow C}\\ + & =(\gunderline{\text{pu}_{F}(\text{wu}_{G})}\times p)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}\\ \text{left identity law of }\text{zip}_{F}:\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{\text{wu}_{G}\times g)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}}\\ \text{composition under }^{\uparrow F}:\quad & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(\text{wu}_{G}\times g)\triangleright\text{ilu}^{\downarrow G}}\big)^{\uparrow F}\\ \text{left identity law of }\text{zip}_{G}:\quad & =p\triangleright(\gunderline{g\rightarrow g})^{\uparrow F}=p\triangleright\text{id}^{\uparrow F}=p\quad. @@ -23880,7 +23866,8 @@ noprefix "false" To verify the right identity law: \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & \text{zip}_{C}(p^{:F^{G^{A}}}\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}\\ +\text{expect to equal }p:\quad & \text{zip}_{C}(p^{:F^{G^{A}}}\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}\\ + & =(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}\\ \text{right identity law of }\text{zip}_{F}:\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}}\\ \text{composition under }^{\uparrow F}:\quad & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})\triangleright\text{iru}^{\downarrow G}}\big)^{\uparrow F}\\ \text{right identity law of }\text{zip}_{G}:\quad & =p\triangleright(\gunderline{g\rightarrow g})^{\uparrow F}=p\triangleright\text{id}^{\uparrow F}=p\quad. @@ -23896,13 +23883,15 @@ To verify the associativity law, first substitute the definition of \begin_inset Formula $\text{zip}_{C}$ \end_inset - into one side: + into the left-hand side: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{C}\big(p\times\text{zip}_{C}(q\times r)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\big(p\times\gunderline{\text{zip}_{C}(q\times r)}\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow C}\\ + & \text{zip}_{C}\big(p\times\text{zip}_{C}(q\times r)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\big(p\times\gunderline{\text{zip}_{C}(q\times r)}\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow C}\\ & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}\\ -\text{naturality law of }\text{zip}_{F}:\quad & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}}\\ -\text{composition under }^{\uparrow F}:\quad & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\big)^{\uparrow F}\quad. + & \quad\text{naturality law of }\text{zip}_{F}:\quad\\ + & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}}\\ + & \quad\text{composition under }^{\uparrow F}:\quad\\ + & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\big)^{\uparrow F}\quad. \end{align*} \end_inset @@ -23910,10 +23899,12 @@ To verify the associativity law, first substitute the definition of Rewrite the right-hand side of the associativity law in a similar way: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & \text{zip}_{C}\big(\text{zip}_{C}(p\times q)\times r\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}=\big(\gunderline{\text{zip}_{C}(p\times q)}\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow C}\\ + & \text{zip}_{C}\big(\text{zip}_{C}(p\times q)\times r\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}=\big(\gunderline{\text{zip}_{C}(p\times q)}\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow C}\\ & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}\\ -\text{naturality law of }\text{zip}_{F}:\quad & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}}\\ -\text{composition under }^{\uparrow F}:\quad & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\big)^{\uparrow F}\quad. + & \quad\text{naturality law of }\text{zip}_{F}:\quad\\ + & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}}\\ + & \quad\text{composition under }^{\uparrow F}:\quad\\ + & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\big)^{\uparrow F}\quad. \end{align*} \end_inset @@ -23973,7 +23964,8 @@ Products \end_layout \begin_layout Standard -This construction for applicative contrafunctors is similar to Statement +This construction for applicative contrafunctors is similar to that shown + in Statement \begin_inset space ~ \end_inset @@ -24374,7 +24366,8 @@ We know that With this choice, we can now verify the left identity law: \begin_inset Formula \begin{align*} - & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=\big((\bbnum 0^{:F^{\bbnum 1}}+\text{wu}_{G})\times p\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}\\ + & =\big((\bbnum 0^{:F^{\bbnum 1}}+\text{wu}_{G})\times p\big)\triangleright\,\begin{array}{|c||cc|} & F^{\bbnum 1\times B} & G^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times F^{B} & \text{zip}_{F} & \bbnum 0\\ F^{\bbnum 1}\times G^{B} & p\times\_^{:G^{B}}\rightarrow p\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ @@ -24389,7 +24382,14 @@ G^{B} & \bbnum 0 & g\rightarrow\text{zip}_{G}(\text{wu}_{G}\times g) & F^{B} & G^{B}\\ \hline F^{\bbnum 1\times B} & \text{ilu}^{\downarrow F} & \bbnum 0\\ G^{\bbnum 1\times B} & \bbnum 0 & \text{ilu}^{\downarrow G} -\end{array}\\ +\end{array} +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} & =p\triangleright\,\,\begin{array}{|c||cc|} & F^{B} & G^{B}\\ \hline F^{B} & \gunderline{\pi_{2}^{\downarrow F}\bef\text{ilu}^{\downarrow F}} & \bbnum 0\\ @@ -24398,7 +24398,8 @@ G^{B} & \bbnum 0 & g\rightarrow\gunderline{\text{zip}_{G}(\text{wu}_{G}\times g) & F^{B} & G^{B}\\ \hline F^{B} & \text{id} & \bbnum 0\\ G^{B} & \bbnum 0 & g\rightarrow g -\end{array}\,=p\triangleright\text{id}=p\quad. +\end{array}\\ + & =p\triangleright\text{id}=p\quad. \end{align*} \end_inset @@ -24704,7 +24705,15 @@ To verify the associativity law in the remaining cases, write separately: \begin_inset Formula \begin{align*} - & p\times\text{zip}_{C}(q\times r)=(q\times r)\triangleright\,\begin{array}{|c||cc|} + & p\times\text{zip}_{C}(q\times r) +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} + & =(q\times r)\triangleright\,\begin{array}{|c||cc|} & C^{A}\times F^{B\times C} & C^{A}\times G^{B\times C}\\ \hline F^{B}\times F^{C} & g\times h\rightarrow p\times\text{zip}_{F}(g\times h) & \bbnum 0\\ F^{B}\times G^{C} & f\times\_\rightarrow p\times(f\triangleright\pi_{1}^{\downarrow F}) & \bbnum 0\\ @@ -24726,7 +24735,8 @@ We can now compute : \begin_inset Formula \begin{align*} - & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))=(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\\ + & =(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} & F^{A\times(B\times C)} & G^{A\times(B\times C)}\\ \hline F^{A}\times F^{B}\times G^{C} & f\times g\times\_\rightarrow\text{zip}_{F}(f\times(g\triangleright\pi_{1}^{\downarrow F})) & \bbnum 0\\ F^{A}\times G^{B}\times F^{C} & f\times\_\times h\rightarrow\text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F})) & \bbnum 0\\ @@ -24746,7 +24756,8 @@ The expression in the right-hand side of the associativity law is written as: \begin_inset Formula \begin{align*} - & \text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)=(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\\ + & =(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} & F^{(A\times B)\times C} & G^{(A\times B)\times C}\\ \hline F^{A}\times F^{B}\times G^{C} & f\times g\times\_\rightarrow\text{zip}_{F}(f\times g)\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ F^{A}\times G^{B}\times F^{C} & f\times\_\times h\rightarrow\text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h) & \bbnum 0\\ @@ -24780,9 +24791,11 @@ and to apply the tuple-rearranging isomorphisms. we get: \begin_inset Formula \begin{align*} - & \text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F}))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow F}=\text{zip}_{F}(f\times h)\triangleright(a\times(b\times c)\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow a\times(b\times c))^{\downarrow F}\\ + & \text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F}))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ + & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times(b\times c)\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow a\times(b\times c))^{\downarrow F}\\ & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times b\times c\rightarrow a\times c)^{\downarrow F}\quad.\\ - & \text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow F}=\text{zip}_{F}(f\times h)\triangleright((a\times b)\times c\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow(a\times b)\times c)^{\downarrow F}\\ + & \text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad=\text{zip}_{F}(f\times h)\triangleright((a\times b)\times c\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow(a\times b)\times c)^{\downarrow F}\\ & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times b\times c\rightarrow a\times c)^{\downarrow F}\quad. \end{align*} @@ -24815,7 +24828,8 @@ F^{A}\times G^{B} & p^{:F^{A}}\times\_^{:G^{B}}\rightarrow p\triangleright\pi_{2 G^{A}\times F^{B} & \_^{:G^{A}}\times q^{:F^{B}}\rightarrow q\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ G^{A}\times G^{B} & \bbnum 0 & \text{swap}\bef\text{zip}_{G} \end{array}\quad,\\ -\text{right-hand side}:\quad & \text{zip}_{C}\bef\text{swap}^{\downarrow C}=\,\begin{array}{|c||cc|} +\text{right-hand side}:\quad & \text{zip}_{C}\bef\text{swap}^{\downarrow C}\\ + & =\,\begin{array}{|c||cc|} & F^{B\times A} & G^{B\times A}\\ \hline F^{A}\times F^{B} & \text{zip}_{F}\bef\text{swap}^{\downarrow F} & \bbnum 0\\ F^{A}\times G^{B} & p^{:F^{A}}\times\_^{:G^{B}}\rightarrow p\triangleright\pi_{1}^{\downarrow F}\bef\text{swap}^{\downarrow F} & \bbnum 0\\ @@ -24834,7 +24848,7 @@ The two sides are equal due to the commutativity laws of \begin_inset Formula $\text{zip}_{G}$ \end_inset -, and due to the properties +, and due to the properties: \begin_inset Formula \[ \text{swap}\bef\pi_{1}=(a\times b\rightarrow b\times a)\bef(c\times d\rightarrow c)=a\times b\rightarrow b=\pi_{2}\quad,\quad\quad\text{swap}\bef\pi_{2}=\pi_{1}\quad. @@ -25023,7 +25037,8 @@ We use the properties such as and compute: \begin_inset Formula \begin{align*} - & h\triangleright\text{ilu}^{\uparrow H}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p)\triangleright\text{ilu}^{\downarrow G}=\text{zip}_{G}\big(\text{wu}_{P}(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times p(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H})\big)\triangleright\text{ilu}^{\downarrow G}\\ + & h\triangleright\text{ilu}^{\uparrow H}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p)\triangleright\text{ilu}^{\downarrow G}\\ + & =\text{zip}_{G}\big(\text{wu}_{P}(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times p(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H})\big)\triangleright\text{ilu}^{\downarrow G}\\ & =\text{zip}_{G}(\text{wu}_{G}\times p(h))\triangleright\text{ilu}^{\downarrow G}=p(h)\quad. \end{align*} @@ -25036,7 +25051,8 @@ We use the properties such as The right identity law is verified by a similar calculation: \begin_inset Formula \begin{align*} - & h\triangleright\text{iru}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{wu}_{P})\triangleright\text{iru}^{\downarrow G}=\text{zip}_{G}(p(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H}))\triangleright\text{iru}^{\downarrow G}\\ + & h\triangleright\text{iru}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{wu}_{P})\triangleright\text{iru}^{\downarrow G}\\ + & =\text{zip}_{G}(p(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H}))\triangleright\text{iru}^{\downarrow G}\\ & =\text{zip}_{G}(p(h)\times\text{wu}_{G})\triangleright\text{iru}^{\downarrow G}=p(h)\quad. \end{align*} @@ -25053,9 +25069,11 @@ To verify the associativity law, we use properties such as and so on: \begin_inset Formula \begin{align*} - & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ + & \quad=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{zip}_{G}\big(q(h\triangleright\pi_{2}^{\uparrow H})\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\quad,\\ - & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times r(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & \quad=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times r(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times q(h\triangleright\pi_{2}^{\uparrow H})\big)\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\quad. \end{align*} @@ -25265,7 +25283,7 @@ status open \begin_layout Plain Layout -sealed trait U[A] // Unfunctor. +sealed trait U[A] // The type constructor U is a GADT. \end_layout \begin_layout Plain Layout @@ -25874,7 +25892,7 @@ A\rightarrow P^{A}=A\rightarrow\left(A\rightarrow A\right)\rightarrow A\cong\lef \end_inset -Examples of functions of this type are +Examples of functions of this type are: \begin_inset Formula \[ f_{1}\triangleq k^{:A\rightarrow A}\rightarrow k\quad,\quad\quad f_{2}\triangleq k^{:A\rightarrow A}\rightarrow(k\bef k)\quad, @@ -26190,10 +26208,12 @@ To verify the left identity law of : \begin_inset Formula \begin{align*} -\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}:\quad & \text{zip}_{P}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{P}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ +\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}:\quad & \text{zip}_{P}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)\\ + & =\gunderline{\text{zip}_{P}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ \text{definition of }\text{zip}_{P}:\quad & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ \text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad & =(p\triangleright\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\times(q\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\\ -\text{definition of }\boxtimes:\quad & =(p\times q)\triangleright\big((\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\boxtimes(\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\big)=(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +\text{definition of }\boxtimes:\quad & =(p\times q)\triangleright\big((\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\boxtimes(\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\big)\\ + & =(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} \end_inset @@ -26209,10 +26229,12 @@ To verify the right identity law of : \begin_inset Formula \begin{align*} -\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}:\quad & \text{zip}_{P}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{P}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ +\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}:\quad & \text{zip}_{P}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)\\ + & =\gunderline{\text{zip}_{P}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ \text{definition of }\text{zip}_{P}:\quad & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ \text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:\quad & =(p\triangleright\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\times(q\triangleright\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\\ -\text{definition of }\boxtimes:\quad & =(p\times q)\triangleright\big((\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\boxtimes(\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\big)=(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. +\text{definition of }\boxtimes:\quad & =(p\times q)\triangleright\big((\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\boxtimes(\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\big)\\ + & =(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. \end{align*} \end_inset @@ -26274,10 +26296,14 @@ To verify the commutativity law of : \begin_inset Formula \begin{align*} -\text{expect }\text{zip}_{P}\big((p\times q)\times(m\times n)\big):\quad & \text{zip}_{P}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ -\text{definitions of }\text{zip}_{P}\text{ and }^{\uparrow P}:\quad & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright\big((\text{swap}^{\uparrow F}\text{swap}^{\downarrow F})\boxtimes(\text{swap}^{\uparrow G}\text{swap}^{\downarrow G})\big)\\ -\text{definition of }\boxtimes:\quad & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\text{swap}^{\downarrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}\big)\\ -\text{commutativity of }F\text{ and }G:\quad & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{P}\big((p\times q)\times(m\times n)\big)\quad. + & \quad\text{expect to equal }\text{zip}_{P}\big((p\times q)\times(m\times n)\big):\quad\\ + & \text{zip}_{P}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ + & \quad\text{definitions of }\text{zip}_{P}\text{ and }^{\uparrow P}:\quad\\ + & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright\big((\text{swap}^{\uparrow F}\text{swap}^{\downarrow F})\boxtimes(\text{swap}^{\uparrow G}\text{swap}^{\downarrow G})\big)\\ + & \quad\text{definition of }\boxtimes:\quad\\ + & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\text{swap}^{\downarrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}\big)\\ + & \quad\text{commutativity of }F\text{ and }G:\quad\\ + & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{P}\big((p\times q)\times(m\times n)\big)\quad. \end{align*} \end_inset @@ -26326,7 +26352,8 @@ If is also applicative: \begin_inset Formula \begin{align*} - & \text{zip}_{P}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\quad\quad\text{zip}_{P}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{P}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\\ + & \text{zip}_{P}\triangleq\,\begin{array}{|c||cc|} & Z & F^{A\times B}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{A}\times Z & \_^{:F^{A}}\times z\rightarrow z & \bbnum 0\\ @@ -26415,7 +26442,8 @@ To verify the left identity law, we use the left identity law of : \begin_inset Formula \begin{align*} - & \text{zip}_{P}(\text{wu}_{P}\times p^{:Z+F^{B}})=\text{zip}_{P}((\bbnum 0+\text{wu}_{F})\times p)=(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(\text{wu}_{P}\times p^{:Z+F^{B}})=\text{zip}_{P}((\bbnum 0+\text{wu}_{F})\times p)\\ + & =(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} & Z & F^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times Z & \_^{:F^{\bbnum 1}}\times z\rightarrow z & \bbnum 0\\ F^{\bbnum 1}\times F^{B} & \bbnum 0 & \text{zip}_{F} @@ -26428,7 +26456,8 @@ F^{B} & \bbnum 0 & k^{:F^{B}}\rightarrow\gunderline{\text{zip}_{F}(\text{wu}_{F} & Z & F^{\bbnum 1\times B}\\ \hline Z & \text{id} & \bbnum 0\\ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F} -\end{array}\,=p\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +\end{array}\\ + & =p\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} \end_inset @@ -26440,11 +26469,19 @@ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F}\pi_{2}^{\ To verify the right identity law, we write a similar calculation: \begin_inset Formula \begin{align*} - & \text{zip}_{P}(p^{:Z+F^{A}}\times\text{wu}_{P})=\text{zip}_{P}(p\times(\bbnum 0+\text{wu}_{F}))=(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(p^{:Z+F^{A}}\times\text{wu}_{P})=\text{zip}_{P}(p\times(\bbnum 0+\text{wu}_{F}))\\ + & =(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z\times F^{\bbnum 1} & z\times\_^{:F^{\bbnum 1}}\rightarrow z & \bbnum 0\\ F^{A}\times F^{\bbnum 1} & \bbnum 0 & \text{zip}_{F} -\end{array}\\ +\end{array} +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} & =p\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ @@ -26453,7 +26490,8 @@ F^{A} & \bbnum 0 & k^{:F^{A}}\rightarrow\gunderline{\text{zip}_{F}(k\times\text{ & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & k\rightarrow k\triangleright\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F} -\end{array}\,=p\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. +\end{array}\\ + & =p\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. \end{align*} \end_inset @@ -26728,14 +26766,21 @@ swap F^{A}\times Z & \bbnum 0 & \bbnum 0 & \text{swap} & \bbnum 0\\ Z\times F^{B} & \bbnum 0 & \text{swap} & \bbnum 0 & \bbnum 0\\ F^{A}\times F^{B} & \bbnum 0 & \bbnum 0 & \bbnum 0 & \text{swap} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array} +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} + & \bef\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{B}\times Z & \_\times z\rightarrow z & \bbnum 0\\ Z\times F^{A} & z\times\_\rightarrow z & \bbnum 0\\ F^{B}\times F^{A} & \bbnum 0 & \text{zip}_{F} -\end{array}\\ - & =\,\begin{array}{|c||cc|} +\end{array}\,=\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{2}\oplus z_{1} & \bbnum 0\\ F^{A}\times Z & \_\times z\rightarrow z & \bbnum 0\\ @@ -26935,7 +26980,8 @@ F^{A} & \bbnum 0 & f^{\uparrow F}g^{\downarrow F} To verify the left identity law, we begin with its left-hand side: \begin_inset Formula \begin{align*} - & \text{zip}_{P}(\text{wu}_{P}\times p)=\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(\text{wu}_{P}\times p)\\ + & =\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{\bbnum 1}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ H^{\bbnum 1}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ @@ -27012,12 +27058,12 @@ Since the identity laws of & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & h\rightarrow\text{zip}_{H}(\text{wu}_{H}\times h) & \bbnum 0\\ F^{B} & \bbnum 0 & f\rightarrow\text{zip}_{F}((\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})\times f) -\end{array}\,=\,\begin{array}{|c||cc|} +\end{array}\\ + & =\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & \text{ilu}^{\uparrow H}\pi_{2}^{\downarrow H} & \bbnum 0\\ F^{B} & \bbnum 0 & \text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F} -\end{array}\\ - & =\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +\end{array}\,=\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} \end_inset @@ -27038,14 +27084,7 @@ The right identity law is verified in a similar way: & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & h\rightarrow\text{zip}_{H}(h\times\text{wu}_{H}) & \bbnum 0\\ F^{A} & \bbnum 0 & f\rightarrow\text{zip}_{F}(f\times(\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})) -\end{array} -\end{align*} - -\end_inset - - -\begin_inset Formula -\begin{align*} +\end{array}\\ & =p\triangleright\,\,\begin{array}{|c||cc|} & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & \text{iru}^{\uparrow H}\pi_{1}^{\downarrow H} & \bbnum 0\\ @@ -27065,9 +27104,10 @@ The associativity law is an equation between values of type : \begin_inset Formula -\[ -\text{zip}_{P}(p^{:H^{A}+F^{A}}\times\text{zip}_{P}(q^{:H^{B}+F^{B}}\times r^{:H^{C}+F^{C}}))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\quad. -\] +\begin{align*} + & \text{zip}_{P}(p^{:H^{A}+F^{A}}\times\text{zip}_{P}(q^{:H^{B}+F^{B}}\times r^{:H^{C}+F^{C}}))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\quad. +\end{align*} \end_inset @@ -27136,8 +27176,10 @@ Otherwise, : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\text{zip}_{H}\big(a\times\text{zip}_{H}(b\times c)\big)\triangleright\varepsilon_{1,23}^{\uparrow H}\tilde{\varepsilon}_{1,23}^{\downarrow H}+\bbnum 0\quad,\\ -\text{right-hand side}:\quad & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}=\text{zip}_{H}\big(\text{zip}_{H}(a\times b)\times c\big)\triangleright\varepsilon_{12,3}^{\uparrow H}\tilde{\varepsilon}_{12,3}^{\downarrow H}+\bbnum 0\quad. +\text{left-hand side}:\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\text{zip}_{H}\big(a\times\text{zip}_{H}(b\times c)\big)\triangleright\varepsilon_{1,23}^{\uparrow H}\tilde{\varepsilon}_{1,23}^{\downarrow H}+\bbnum 0\quad,\\ +\text{right-hand side}:\quad & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\\ + & \quad=\text{zip}_{H}\big(\text{zip}_{H}(a\times b)\times c\big)\triangleright\varepsilon_{12,3}^{\uparrow H}\tilde{\varepsilon}_{12,3}^{\downarrow H}+\bbnum 0\quad. \end{align*} \end_inset @@ -27218,8 +27260,10 @@ noprefix "false" : \begin_inset Formula \begin{align*} - & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\quad,\\ - & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\quad. + & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\quad,\\ + & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\\ + & \quad=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\quad. \end{align*} \end_inset @@ -27327,7 +27371,8 @@ pure So, we can rewrite the left-hand side of the associativity law like this: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ +\text{left-hand side}:\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ \text{identity law of }\text{zip}_{F}:\quad & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. \end{align*} @@ -27371,10 +27416,13 @@ Simplify the sub-expressions of the form Using this formula, we continue to transform the right-hand side: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & \bbnum 0+\gunderline{\text{zip}_{F}}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\gunderline{\text{toF}\left(c+\bbnum 0\right)})\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:\quad & =\bbnum 0+\gunderline{\text{zip}_{F}}(a\times\gunderline{\text{toF}\left(b+\bbnum 0\right)})\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:\quad & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -\text{compute composition}:\quad & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. + & \bbnum 0+\gunderline{\text{zip}_{F}}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\gunderline{\text{toF}\left(c+\bbnum 0\right)})\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:\quad\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}(a\times\gunderline{\text{toF}\left(b+\bbnum 0\right)})\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:\quad\\ + & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad\text{compute composition}:\quad\\ + & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. \end{align*} \end_inset @@ -27465,19 +27513,19 @@ The right-hand side is rewritten to the same code after using the laws of : \begin_inset Formula \begin{align*} - & \text{zip}_{P}\bef\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ - & =\,\begin{array}{|c||cc|} +\text{zip}_{P}\bef\text{swap}^{\uparrow P}\text{swap}^{\downarrow P} & =\,\begin{array}{|c||cc|} & H^{A\times B} & F^{A\times B}\\ \hline H^{A}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ F^{A}\times H^{B} & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{zip}_{F}\\ H^{A}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ F^{A}\times F^{B} & \bbnum 0 & \text{zip}_{F} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline H^{A\times B} & \text{swap}^{\uparrow H}\text{swap}^{\downarrow H} & \bbnum 0\\ F^{A\times B} & \bbnum 0 & \text{swap}^{\uparrow F}\text{swap}^{\downarrow F} \end{array}\\ - & =\,\,\begin{array}{|c||cc|} + & =\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline A\times B & \text{swap}\bef\text{zip}_{H} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{swap}\bef\text{zip}_{F}\\ @@ -27642,9 +27690,11 @@ To verify the left identity law of : \begin_inset Formula \begin{align*} - & h^{:H^{\bbnum 1\times A}}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p^{:H^{A}\rightarrow G^{A}})=\text{zip}_{G}\big(\gunderline{\text{wu}_{P}(h\triangleright\pi_{1}^{\uparrow H})}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ -\text{definition of }\text{wu}_{P}:\quad & =\text{zip}_{G}\big(\text{wu}_{G}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ -\text{left identity law of }G:\quad & =p(h\triangleright\pi_{2}^{\uparrow H})\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}=h\triangleright\gunderline{\pi_{2}^{\uparrow H}\bef p\bef\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}}=h\triangleright(p\bef\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P})\quad. + & h^{:H^{\bbnum 1\times A}}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p^{:H^{A}\rightarrow G^{A}})\\ + & =\text{zip}_{G}\big(\gunderline{\text{wu}_{P}(h\triangleright\pi_{1}^{\uparrow H})}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ +\text{definition of }\text{wu}_{P}:\quad & =\gunderline{\text{zip}_{G}\big(\text{wu}_{G}}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ +\text{left identity law of }G:\quad & =\gunderline{p(h\triangleright\pi_{2}^{\uparrow H})}\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}\\ + & =h\triangleright\gunderline{\pi_{2}^{\uparrow H}\bef p\bef\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}}=h\triangleright(p\bef\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P})\quad. \end{align*} \end_inset @@ -27657,10 +27707,11 @@ To verify the right identity law of \begin_inset Formula $P$ \end_inset -: +, we use a similar calculation: \begin_inset Formula \begin{align*} - & h^{:H^{A\times\bbnum 1}}\triangleright\text{zip}_{P}(p^{:H^{A}\rightarrow G^{A}}\times\text{wu}_{P})=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\pi_{2}^{\uparrow H})\big)=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{G}\big)\\ + & h^{:H^{A\times\bbnum 1}}\triangleright\text{zip}_{P}(p^{:H^{A}\rightarrow G^{A}}\times\text{wu}_{P})=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\pi_{2}^{\uparrow H})\big)\\ + & =\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{G}\big)\\ & =p(h\triangleright\pi_{1}^{\uparrow H})\triangleright\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G}=h\triangleright\gunderline{\pi_{1}^{\uparrow H}\bef p\bef\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G}}=h\triangleright(p\bef\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P})\quad. \end{align*} @@ -27677,11 +27728,13 @@ To verify the associativity law, we use the definition of : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & h^{:H^{A\times B\times C}}\triangleright\big(\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\,\gunderline{\triangleright\,\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}}\big)\\ + & \quad\text{left-hand side}:\quad\\ + & h^{:H^{A\times B\times C}}\triangleright\big(\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\,\gunderline{\triangleright\,\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}}\big)\\ & \quad=h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H})\big)\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{zip}_{G}\big(q(h\triangleright\pi_{2}^{\uparrow H})\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\big)\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\quad,\\ -\text{right-hand side}:\quad & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & \quad\text{right-hand side}:\quad\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H})\times r(h\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H})\big)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times q(h\triangleright\pi_{2}^{\uparrow H})\big)\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\quad. \end{align*} @@ -27700,11 +27753,12 @@ It remains to verify the commutativity law, assuming that \begin_inset Formula $\text{zip}_{G}$ \end_inset - satisfies that law: + obeys that law: \begin_inset Formula \begin{align*} & \text{zip}_{P}(q\times p)=\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(q\boxtimes p)\bef\text{zip}_{G}\quad,\\ - & \text{zip}_{P}(p\times q)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}=\text{swap}^{\uparrow H}\bef\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(p\boxtimes q)\bef\gunderline{\text{zip}_{G}\bef\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}}\\ + & \text{zip}_{P}(p\times q)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ + & \quad=\text{swap}^{\uparrow H}\bef\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(p\boxtimes q)\bef\gunderline{\text{zip}_{G}\bef\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}}\\ & \quad=\Delta\bef\gunderline{(\text{swap}^{\uparrow H}\boxtimes\text{swap}^{\uparrow H})\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})}\bef\gunderline{(p\boxtimes q)\bef\text{swap}}\bef\text{zip}_{G}\\ & \quad=\gunderline{\Delta\bef(\pi_{2}^{\uparrow H}\boxtimes\pi_{1}^{\uparrow H})\bef\text{swap}}\bef(q\boxtimes p)\bef\text{zip}_{G}=\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(q\boxtimes p)\bef\text{zip}_{G}\quad. \end{align*} @@ -27995,15 +28049,8 @@ noprefix "false" \end_layout \begin_layout Standard -After seeing those detailed proofs, we can now clarify the meaning of -\begin_inset Quotes eld -\end_inset - -equivalence under laws -\begin_inset Quotes erd -\end_inset - -. +After seeing those detailed proofs, we can now clarify the meaning of equivalenc +e of typeclass methods when we require some laws to hold. The goal of this subsection is to find a rigorous formulation of that equivalen ce. \end_layout @@ -29284,10 +29331,17 @@ Monad \begin_layout Subsection Applicative morphisms +\begin_inset CommandInset label +LatexCommand label +name "subsec:Applicative-morphisms" + +\end_inset + + \end_layout \begin_layout Standard -One of the applicative constructions (Statement +The construction in Statement \begin_inset space ~ \end_inset @@ -29301,7 +29355,7 @@ noprefix "false" \end_inset -) needs a compatibility law + needs a compatibility law \begin_inset space ~ \end_inset @@ -29428,9 +29482,10 @@ noprefix "false" ): \begin_inset Formula -\[ -\phi\big(\text{zip}_{H}(p\times q)\big)=\text{zip}_{K}(\phi(p)\times\phi(q))\quad,\quad\text{or equivalently}:\quad\text{zip}_{H}\bef\phi=(\phi\boxtimes\phi)\bef\text{zip}_{K}\quad. -\] +\begin{align*} + & \phi\big(\text{zip}_{H}(p\times q)\big)=\text{zip}_{K}(\phi(p)\times\phi(q))\quad,\\ +\text{or equivalently}:\quad & \text{zip}_{H}\bef\phi=(\phi\boxtimes\phi)\bef\text{zip}_{K}\quad. +\end{align*} \end_inset @@ -30135,7 +30190,8 @@ We will prove the laws separately for the definitions (a) and (b). : \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p=(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ +\text{expect to equal }p:\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p\\ + & =(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ \text{left identity law of }\text{zip}:\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow\text{id}\times s)^{\uparrow L}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ \text{function composition under }^{\uparrow L}:\quad & =p\triangleright(\gunderline{s\rightarrow\text{id}\bef s})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} @@ -30149,7 +30205,8 @@ We will prove the laws separately for the definitions (a) and (b). To verify the right identity law: \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})=(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ +\text{expect to equal }p:\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})\\ + & =(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ \text{right identity law of }\text{zip}:\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow s\times\text{id})^{\uparrow L}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ \text{function composition under }^{\uparrow L}:\quad & =p\triangleright(\gunderline{s\rightarrow s\bef\text{id}})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} @@ -30176,10 +30233,13 @@ zip functions to the left of the expression: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & (p\odot q)\odot r=\big((p\times q)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ + & \quad\text{left-hand side}:\quad\\ + & (p\odot q)\odot r=\big((p\times q)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ & =\big(\big(\text{zip}\left(p\times q\right)\triangleright\gunderline{(f\times g\rightarrow f\bef g)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}\\ -\text{naturality law of }\text{zip}:\quad & =(\text{zip}\left(p\times q\right)\times r)\triangleright\text{zip}\bef\gunderline{((f\times g)\times h\rightarrow(f\bef g)\times h)^{\uparrow L}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}}\\ -\text{composition under }^{\uparrow L}:\quad & =\text{zip}\left(\text{zip}\left(p\times q\right)\times r\right)\triangleright((f\times g)\times h\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad\text{naturality law of }\text{zip}:\quad\\ + & =(\text{zip}\left(p\times q\right)\times r)\triangleright\text{zip}\bef\gunderline{((f\times g)\times h\rightarrow(f\bef g)\times h)^{\uparrow L}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}}\\ + & \quad\text{composition under }^{\uparrow L}:\quad\\ + & =\text{zip}\left(\text{zip}\left(p\times q\right)\times r\right)\triangleright((f\times g)\times h\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} \end_inset @@ -30187,10 +30247,13 @@ zip The right-hand side is rewritten similarly: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\\ + & \quad\text{right-hand side}:\quad\\ + & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\\ & =\big(p\times\big(\text{zip}\left(q\times r\right)\triangleright\gunderline{(g\times h\rightarrow g\bef h)^{\uparrow L}}\big)\big)\triangleright\gunderline{\text{zip}}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}\\ -\text{naturality law of }\text{zip}:\quad & =(p\times\text{zip}\left(q\times r\right))\triangleright\text{zip}\bef\gunderline{(f\times(g\times h)\rightarrow f\times(g\bef h))^{\uparrow L}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}}\\ -\text{composition under }^{\uparrow L}:\quad & =\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)\triangleright(f\times(g\times h)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad\text{naturality law of }\text{zip}:\quad\\ + & =(p\times\text{zip}\left(q\times r\right))\triangleright\text{zip}\bef\gunderline{(f\times(g\times h)\rightarrow f\times(g\bef h))^{\uparrow L}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}}\\ + & \quad\text{composition under }^{\uparrow L}:\quad\\ + & =\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)\triangleright(f\times(g\times h)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} \end_inset @@ -30302,7 +30365,8 @@ zip : \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p=(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ +\text{expect to equal }p:\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p\\ + & =(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ \text{right identity law of }\text{zip}:\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow s\times\text{id})^{\uparrow L}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ \text{function composition under }^{\uparrow L}:\quad & =p\triangleright(\gunderline{s\rightarrow\text{id}\bef s})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} @@ -30316,7 +30380,8 @@ zip To verify the right identity law: \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})=(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ +\text{expect to equal }p:\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})\\ + & =(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ \text{left identity law of }\text{zip}:\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow\text{id}\times s)^{\uparrow L}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ \text{function composition under }^{\uparrow L}:\quad & =p\triangleright(\gunderline{s\rightarrow s\bef\text{id}})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} @@ -30330,10 +30395,12 @@ To verify the right identity law: To verify the composition law, begin rewriting its left-hand side: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & (p\odot q)\odot r=\big((q\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ + & (p\odot q)\odot r=\big((q\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ & =\big(r\times\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(g\times f\rightarrow f\bef g)^{\uparrow L}}\big)\big)\triangleright\gunderline{\text{zip}}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}\\ -\text{naturality law of }\text{zip}:\quad & =(r\times\text{zip}\left(q\times p\right))\triangleright\text{zip}\bef\gunderline{(h\times(g\times f)\rightarrow h\times(f\bef g))^{\uparrow L}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}}\\ -\text{composition under }^{\uparrow L}:\quad & =\text{zip}\left(r\times\text{zip}\left(q\times p\right)\right)\triangleright(h\times(g\times f)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad\text{naturality law of }\text{zip}:\quad\\ + & =(r\times\text{zip}\left(q\times p\right))\triangleright\text{zip}\bef\gunderline{(h\times(g\times f)\rightarrow h\times(f\bef g))^{\uparrow L}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}}\\ + & \quad\text{composition under }^{\uparrow L}:\quad\\ + & =\text{zip}\left(r\times\text{zip}\left(q\times p\right)\right)\triangleright(h\times(g\times f)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} \end_inset @@ -30341,10 +30408,12 @@ To verify the composition law, begin rewriting its left-hand side: The right-hand side is rewritten similarly: \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\\ + & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\\ & =\big(\big(\text{zip}\left(q\times r\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times p\big)\triangleright\gunderline{\text{zip}}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}\\ -\text{naturality law of }\text{zip}:\quad & =(\text{zip}\left(q\times r\right)\times p)\triangleright\text{zip}\bef\gunderline{((h\times g)\times f\rightarrow(g\bef h)\times f)^{\uparrow L}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}}\\ -\text{composition under }^{\uparrow L}:\quad & =\text{zip}\left(\text{zip}\left(q\times r\right)\times p\right)\triangleright((h\times g)\times f\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad\text{naturality law of }\text{zip}:\quad\\ + & =(\text{zip}\left(q\times r\right)\times p)\triangleright\text{zip}\bef\gunderline{((h\times g)\times f\rightarrow(g\bef h)\times f)^{\uparrow L}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}}\\ + & \quad\text{composition under }^{\uparrow L}:\quad\\ + & =\text{zip}\left(\text{zip}\left(q\times r\right)\times p\right)\triangleright((h\times g)\times f\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} \end_inset @@ -30430,16 +30499,60 @@ The laws of the composition operation ( \begin_inset Formula $L$ \end_inset --applicative +-ap \begin_inset Quotes erd \end_inset - the category with those morphisms. + the category with those morphisms, which we will call +\begin_inset Formula $L$ +\end_inset + +-ap morphisms. +\begin_inset Foot +status open + +\begin_layout Plain Layout +They are quite different from +\emph on +applicative morphisms +\emph default + defined in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Applicative-morphisms" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + Applicative morphisms have type +\begin_inset Formula $L^{A}\rightarrow M^{A}$ +\end_inset + +, while +\begin_inset Formula $L$ +\end_inset + +-ap morphisms have type +\begin_inset Formula $L^{A\rightarrow B}$ +\end_inset + +. +\end_layout + +\end_inset + We may now write the laws of a (categorical) functor between the \begin_inset Formula $L$ \end_inset --applicative and the +-ap and the \begin_inset Formula $L$ \end_inset @@ -30457,7 +30570,7 @@ The laws of the composition operation ( \begin_inset Formula $L$ \end_inset --applicative morphism +-ap morphism \begin_inset Formula $f:L^{A\rightarrow B}$ \end_inset @@ -30483,7 +30596,7 @@ ap \end_inset to play the role of the morphism mapping of that functor. - This mapping must obey the laws of identity and composition. + So, we expect that this mapping must obey the laws of identity and composition. \end_layout \begin_layout Standard @@ -30503,7 +30616,7 @@ ap \begin_inset Formula $L$ \end_inset --applicative category into the identity morphism of the +-ap category into the identity morphism of the \begin_inset Formula $L$ \end_inset @@ -30531,20 +30644,20 @@ ap \end_layout \begin_layout Standard -The composition law says that the composition -\begin_inset Formula $p\odot q$ -\end_inset - - of any two +The composition law says that for any two \begin_inset Formula $L$ \end_inset --applicative morphisms +-ap morphisms \begin_inset Formula $p^{:L^{A\rightarrow B}}$ \end_inset and \begin_inset Formula $q^{:L^{B\rightarrow C}}$ +\end_inset + +, the operation +\begin_inset Formula $p\odot q$ \end_inset must be mapped by @@ -30566,7 +30679,7 @@ ap : \begin_inset Formula \begin{align} -\text{composition law of }\text{ap}:\quad & \text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad.\label{eq:composition-law-of-ap} +\text{composition law of }\text{ap}:\quad & \text{ap}\,\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad.\label{eq:composition-law-of-ap} \end{align} \end_inset @@ -30629,7 +30742,7 @@ ap : \begin_inset Formula \[ -\text{ap}\big(\text{ap}\big(q^{:L^{B\rightarrow C}}\triangleright(g^{:B\rightarrow C}\rightarrow f^{:A\rightarrow B}\rightarrow f\bef g)^{\uparrow L}\big)(p^{:L^{A\rightarrow B}})\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad. +\text{ap}\,\big(\text{ap}\,\big(q^{:L^{B\rightarrow C}}\triangleright(g^{:B\rightarrow C}\rightarrow f^{:A\rightarrow B}\rightarrow f\bef g)^{\uparrow L}\big)(p^{:L^{A\rightarrow B}})\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad. \] \end_inset @@ -30819,7 +30932,8 @@ noprefix "false" : \begin_inset Formula \begin{align*} -\text{expect to equal }p:\quad & \text{ap}\,(\text{pu}_{L}(\text{id}))(p^{:L^{A}})=(\gunderline{\text{pu}_{L}(\text{id})}\times p)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}\\ +\text{expect to equal }p:\quad & \text{ap}\,(\text{pu}_{L}(\text{id}))(p^{:L^{A}})\\ + & =(\gunderline{\text{pu}_{L}(\text{id})}\times p)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}\\ \text{left identity law of }\text{zip}:\quad & =p\triangleright\gunderline{(a^{:A}\rightarrow\text{id}\times a)^{\uparrow L}\bef(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}}\\ \text{composition under }^{\uparrow L}:\quad & =p\triangleright(a^{:A}\rightarrow\text{id}\,(a))^{\uparrow L}=p\triangleright(a\rightarrow a)^{\uparrow L}=p\triangleright\text{id}=p\quad. \end{align*} @@ -30851,10 +30965,21 @@ noprefix "false" : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & r\triangleright\text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\,(p\odot q)(r)=((p\odot q)\times r)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ -\text{definition (b) of }\odot:\quad & =\big(\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}\\ -\text{naturality law of }\text{zip}:\quad & =\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright\text{zip}\triangleright\gunderline{((h\times g)\times a\rightarrow(g\bef h)\times a)^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ -\text{composition under }^{\uparrow L}:\quad & =\text{zip}\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright((h\times g)\times a\rightarrow a\triangleright g\bef h)^{\uparrow L}\quad. +\quad\text{left-hand side}:\quad & r\triangleright\text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\,(p\odot q)(r)\\ + & =((p\odot q)\times r)\triangleright\text{zip}\bef\text{eval}^{\uparrow L} +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} + & \quad\text{definition (b) of }\odot:\quad\\ + & =\big(\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}\\ + & \quad\text{naturality law of }\text{zip}:\quad\\ + & =\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright\text{zip}\triangleright\gunderline{((h\times g)\times a\rightarrow(g\bef h)\times a)^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ + & \quad\text{composition under }^{\uparrow L}:\quad\\ + & =\text{zip}\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright((h\times g)\times a\rightarrow a\triangleright g\bef h)^{\uparrow L}\quad. \end{align*} \end_inset @@ -30880,7 +31005,8 @@ noprefix "false" : \begin_inset Formula \begin{align*} -\text{right-hand side}:\quad & r\triangleright\text{ap}\,(p)\bef\text{ap}\,(q)=\text{ap}\,(q)\big(\text{ap}\,(p)(r)\big)=\text{zip}\big(q\times\text{ap}\,(p)(r)\big)\triangleright\text{eval}^{\uparrow L}\\ +\text{right-hand side}:\quad & r\triangleright\text{ap}\,(p)\bef\text{ap}\,(q)=\text{ap}\,(q)\big(\text{ap}\,(p)(r)\big)\\ + & =\text{zip}\big(q\times\text{ap}\,(p)(r)\big)\triangleright\text{eval}^{\uparrow L}\\ & =\gunderline{\text{zip}}\big(q\times\big(\text{zip}\,(p\times r)\triangleright\gunderline{\text{eval}^{\uparrow L}}\big)\big)\triangleright\text{eval}^{\uparrow L}\\ \text{naturality law of }\text{zip}:\quad & =\text{zip}\big(q\times\text{zip}\left(p\times r\right)\big)\triangleright\gunderline{(h\times(g\times a)\rightarrow h\times g(a))^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ \text{composition under }^{\uparrow L}:\quad & =\text{zip}\big(q\times\text{zip}\left(p\times r\right)\big)\triangleright\big(h\times(g\times a)\rightarrow h(g(a))\big)^{\uparrow L}\quad. @@ -30993,7 +31119,7 @@ ap \begin_inset Formula $L$ \end_inset --applicative +-ap \begin_inset Quotes erd \end_inset @@ -31038,11 +31164,11 @@ ap \begin_inset Formula $L$ \end_inset --applicative category together with the laws of a functor from the +-ap category together with the laws of a functor from the \begin_inset Formula $L$ \end_inset --applicative to the +-ap to the \begin_inset Formula $L$ \end_inset @@ -31825,7 +31951,7 @@ Let us go through this pattern for the applicative functor typeclass studied \begin_inset Formula $F$ \end_inset --applicative and +-ap and \begin_inset Formula $F$ \end_inset @@ -31834,7 +31960,7 @@ Let us go through this pattern for the applicative functor typeclass studied \begin_inset Formula $F$ \end_inset --applicative category are values of type +-ap category are values of type \begin_inset Formula $F^{A\rightarrow B}$ \end_inset @@ -31883,7 +32009,7 @@ The first step is to define the \begin_inset Formula $F$ \end_inset --applicative category's morphisms. +-ap category's morphisms. We define identity morphisms ( \begin_inset listings inline true @@ -32104,7 +32230,8 @@ noprefix "false" \end_inset ) are not functorial typeclasses. - Their laws must be motivated by other considerations. + Their laws must be motivated by considerations other than referring to + the functor laws. \end_layout \begin_layout Subsection @@ -32143,8 +32270,20 @@ noprefix "false" \end_layout \begin_layout Standard -Implement an applicative instance for -\begin_inset Formula $F^{A}=\bbnum 1+\text{Int}\times A+A\times A\times A$ +Implement an +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Applicative +\end_layout + +\end_inset + + instance for +\begin_inset Formula $F^{A}=\bbnum 1+\text{Int}\times A+A\times A\times A\times A$ \end_inset . @@ -32173,7 +32312,7 @@ noprefix "false" \begin_layout Standard Show that the following functors -\begin_inset Formula $F^{\bullet}$ +\begin_inset Formula $F$ \end_inset @@ -32812,7 +32951,7 @@ noprefix "false" \end_layout \begin_layout Standard -Prove the following statements (which complement Statement +To complement Statement \begin_inset space ~ \end_inset @@ -32826,7 +32965,7 @@ noprefix "false" \end_inset -): +, prove that: \end_layout \begin_layout Standard @@ -32835,11 +32974,11 @@ noprefix "false" (a) \series default If -\begin_inset Formula $F^{\bullet}$ +\begin_inset Formula $F$ \end_inset is an applicative functor and -\begin_inset Formula $G^{\bullet}$ +\begin_inset Formula $G$ \end_inset is an applicative contrafunctor then the contrafunctor @@ -32855,11 +32994,11 @@ noprefix "false" (b) \series default If -\begin_inset Formula $F^{\bullet}$ +\begin_inset Formula $F$ \end_inset and -\begin_inset Formula $G^{\bullet}$ +\begin_inset Formula $G$ \end_inset are both applicative contrafunctors then @@ -32887,15 +33026,15 @@ functor (b) \series default , if -\begin_inset Formula $F^{\bullet}$ +\begin_inset Formula $F$ \end_inset and -\begin_inset Formula $G^{\bullet}$ +\begin_inset Formula $G$ \end_inset are commutative then -\begin_inset Formula $L^{\bullet}$ +\begin_inset Formula $L$ \end_inset is also commutative. @@ -32995,7 +33134,7 @@ noprefix "false" \end_layout \begin_layout Standard -Explicitly prove the laws in the construction of Statement +Prove the laws in the construction of Statement \begin_inset space ~ \end_inset @@ -33116,7 +33255,7 @@ noprefix "false" \begin_layout Standard The type constructor -\begin_inset Formula $Q^{\bullet}$ +\begin_inset Formula $Q$ \end_inset is defined by: diff --git a/sofp-src/sofp-applicative.tex b/sofp-src/sofp-applicative.tex index 9432b0144..8f458a6db 100644 --- a/sofp-src/sofp-applicative.tex +++ b/sofp-src/sofp-applicative.tex @@ -148,25 +148,16 @@ \subsubsection{Example \label{subsec:Example-applicative-profunctor}\ref{subsec: typeclass instance for a type \lstinline!A! can be represented by a value of type $L^{A}$, where the type constructor $L$ is defined by: - -\begin{wrapfigure}{l}{0.5\columnwidth}% -\vspace{-0.85\baselineskip} \begin{lstlisting} type L[A] = (A, (A, A) => A) \end{lstlisting} - -\vspace{-0.25\baselineskip} -\end{wrapfigure}% - -\noindent \vspace{-0.5\baselineskip} \[ L^{A}\triangleq A\times\left(A\times A\rightarrow A\right)\quad. \] - -\noindent We can write a function that creates a monoid typeclass -instance for the type $A\times B$ when $A$ and $B$ are monoids. -That function has the type signature of a \lstinline!zip! method -for the type constructor $L$: +We can write a function that creates a monoid typeclass instance for +the type $A\times B$ when $A$ and $B$ are monoids. That function +has the type signature of a \lstinline!zip! method for the type constructor +$L$: \begin{lstlisting} def zip[A, B](la: L[A], lb: L[B]): L[(A, B)] = ( (la._1, lb._1), // The result has type ((A, B), { case ((a1, b1), (a2, b2)) => (la._2(a1, a2), lb._2(b1, b2)) } // ((A, B), (A, B)) => (A, B)). @@ -226,7 +217,7 @@ \subsection{Gathering all errors during computations\label{subsec:Programs-that- \lstinline!div! operations and gather the errors: \begin{lstlisting} scala> for { - p <- map2(div(1,0), div(2,0)) { (x, y) => (x, y) } // Create a tuple (x, y). + p <- map2(div(1,0), div(2,0)) { (x, y) => (x, y) } z <- add(p._1, p._2) } yield z res1: Either[String, Int] = Left(error: 1 / 0 @@ -252,15 +243,16 @@ \subsection{Gathering all errors during computations\label{subsec:Programs-that- \end{lstlisting} In the code notation, the \lstinline!zipE! function is written like this: -\[ -\text{zip}_{E}:(E+A)\times(E+B)\rightarrow E+A\times B\quad,\quad\quad\text{zip}_{E}\triangleq\,\begin{array}{|c||cc|} +\begin{align*} + & \text{zip}_{E}:(E+A)\times(E+B)\rightarrow E+A\times B\quad,\\ + & \text{zip}_{E}\triangleq\,\begin{array}{|c||cc|} & E & A\times B\\ \hline E\times E & e_{1}\times e_{2}\rightarrow e_{1}\oplus e_{2} & \bbnum 0\\ A\times E & \_\times e_{2}\rightarrow e_{2} & \bbnum 0\\ E\times B & e_{1}\times\_\rightarrow e_{2} & \bbnum 0\\ A\times B & \bbnum 0 & \text{id} \end{array}\quad. -\] +\end{align*} When both arguments of \lstinline!zipE! have error messages, the code does not drop one of the errors and return \lstinline!Left(e1)!, @@ -383,15 +375,16 @@ \subsection{Transposing a matrix via \texttt{map2}} For the inductive step, we assume that the \lstinline!tails! sub-matrix is already transposed. So, it remains to combine \lstinline!transpose(tails)! with \lstinline!heads!. Consider the test example shown above: -\[ -\left|\begin{array}{cc} +\begin{align*} + & \left|\begin{array}{cc} 1 & 2\\ 3 & 4\\ 5 & 6 \end{array}\right|\,\triangleright\text{transpose}=\,\left|\begin{array}{ccc} 1 & 3 & 5\\ 2 & 4 & 6 -\end{array}\right|\quad,\,\,\quad\left|\begin{array}{cc} +\end{array}\right|\quad,\\ + & \,\left|\begin{array}{cc} 1 & 2\\ 3 & 4\\ 5 & 6 @@ -404,7 +397,7 @@ \subsection{Transposing a matrix via \texttt{map2}} 3 & 4\\ 5 & 6 \end{array}\right|\quad. -\] +\end{align*} Splitting this matrix into the first row (\lstinline!heads!) and the rest (\lstinline!tails!), we will obtain \lstinline!heads == List(1, 2)! and \lstinline!tails == List(List(3, 4), List(5, 6))!. The inductive @@ -447,8 +440,8 @@ \subsection{Data validation with error reporting} JSON). We would like to report all errors to the user, rather than stopping at the first error. -To simplify the reasoning, assume that the required data structure -is a case class, such as: +For simplicity, assume that the required data structure is a case +class, e.g.: \begin{lstlisting} final case class MyData(userId: Long, userName: String, userEmails: List[String]) \end{lstlisting} @@ -457,28 +450,18 @@ \subsection{Data validation with error reporting} \begin{lstlisting} final case class MyData[A, B, C](a: A, b: B, c: C) \end{lstlisting} - -We assume that the validation functions will return values of types -\lstinline!F[A]! defined by: - -\begin{wrapfigure}{l}{0.5\columnwidth}% -\vspace{-0.85\baselineskip} +Suppose that the validation functions will return values of type \lstinline!F[A]! +defined by: \begin{lstlisting} type F[A] = Either[E, A] \end{lstlisting} - -\vspace{-0.25\baselineskip} -\end{wrapfigure}% - -\noindent \vspace{-0.5\baselineskip} \[ F^{A}\triangleq E+A\quad. \] - -Here, \lstinline!A! is the type of a successfully validated value, -while the fixed type \lstinline!E! describes the error information. -We will assume that $E$ is a semigroup, so that different pieces -of error information can be combined into a larger value of the same +Here, \lstinline!A! is the type of a successfully validated value; + the fixed type \lstinline!E! describes the error information. We +will assume that $E$ is a semigroup, so that different pieces of +error information can be combined into a larger value of the same type $E$. If some of the validations fail, the result should be a value of type @@ -844,8 +827,8 @@ \subsection{Single-traversal \texttt{fold} operations. I. Applicative \textquote Seq(1.0, 2.0, 3.0).runFold(sum / length) // Should return `2.0` here. \end{lstlisting} -To enable this kind of code,\footnote{A more fully featured library using this approach is \texttt{scala-fold}, -see \texttt{\href{https://github.com/amarpotghan/scala-fold}{https://github.com/amarpotghan/scala-fold}} } we need to add a final transformation to the \lstinline!Fold! type: +To enable this kind of code,\footnote{The library \texttt{scala-fold} (see \texttt{\href{https://github.com/amarpotghan/scala-fold}{https://github.com/amarpotghan/scala-fold}}) +implements this approach with additional features.} we need to add a final transformation to the \lstinline!Fold! type: \begin{lstlisting} final case class FoldOp[Z, R, A](init: R, update: (R, Z) => R, transform: R => A) \end{lstlisting} @@ -861,13 +844,13 @@ \subsection{Single-traversal \texttt{fold} operations. I. Applicative \textquote } \end{lstlisting} -How can we combine two \lstinline!fold!-like operations of types -$\text{FoldOp}^{Z,R,A}$ and $\text{FoldOp}^{Z,S,B}$? The combined -operation must maintain intermediate states of types $R$ and $S$. -Also, we have two result values of types $A$ and $B$. It seems that -the combined operation needs an intermediate state of type $R\times S$ -and a final result of type $A\times B$. So, let us implement a \lstinline!zip! -extension method by using those types: +How can we combine two operations of types $\text{FoldOp}^{Z,R,A}$ +and $\text{FoldOp}^{Z,S,B}$? The combined operation must maintain +intermediate states of types $R$ and $S$. Also, we have two result +values of types $A$ and $B$. It seems that the combined operation +needs an intermediate state of type $R\times S$ and a final result +of type $A\times B$. So, let us implement a \lstinline!zip! extension +method by using those types: \begin{lstlisting} implicit class FoldOpZip[Z, R, A](op: FoldOp[Z, R, A]) { def zip[S, B](other: FoldOp[Z, S, B]): FoldOp[Z, (R, S), (A, B)] = implement @@ -1198,11 +1181,11 @@ \subsection{Parsing with applicative and monadic combinators\label{subsec:Parsin parser \lstinline!p! is tried first): \begin{lstlisting} implicit class ParserCombineOps[A](p: P[A]) { - def or(q: => P[A]): P[A] = P { s => // Important: the argument `q` must be lazy. + def or(q: => P[A]): P[A] = P { s => // Important: `q` must be lazy. val (result, rest) = p.run(s) - result match { // If `p` failed to parse the string `s`, - case Left(err) => q.run(s) // ignore the error from `p` and run `q`. - case Right(x) => (Right(x), rest) // Otherwise, use the result of running `p`. + result match { // If `p` failed to parse the string `s`, + case Left(err) => q.run(s) // ignore the error from `p` and run `q`. + case Right(x) => (Right(x), rest) // Otherwise, use the result of running `p`. } } \end{lstlisting} @@ -1211,9 +1194,9 @@ \subsection{Parsing with applicative and monadic combinators\label{subsec:Parsin will help us write recursively defined parsers, as we will see next. Using these combinators, we write a first attempt at parsing the toy -language. Since the language allows us to have arbitrarily deep nesting -of the tags \lstinline!...!, we need to define the parser -as a recursive function (called \lstinline!p2!): +language. Since the language permits arbitrarily deep nesting of the +tags \lstinline!...!, we need to define the parser as +a recursive function (called \lstinline!p2!): \begin{lstlisting} def p2: P[Int] = intP or (openTag zipRight p2 zipLeft closeTag).map { x => math.sqrt(x).toInt } @@ -1447,7 +1430,8 @@ \subsubsection{Statement \label{subsec:Statement-map2-zip-equivalence}\ref{subse Then we need to show that $\text{map}_{2}^{\prime}=\text{map}_{2}$. We apply $\text{map}_{2}^{\prime}$ to arbitrary arguments and write: \begin{align*} - & \text{map}_{2}^{\prime}\,(p\times q)(f)=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}=\text{map}_{2}\,(p\times q)(\text{id})\,\gunderline{\triangleright\,f^{\uparrow L}}\\ + & \text{map}_{2}^{\prime}\,(p\times q)(f)=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\\ + & =\text{map}_{2}\,(p\times q)(\text{id})\,\gunderline{\triangleright\,f^{\uparrow L}}\\ {\color{greenunder}\text{naturality law of }\text{map}_{2}:}\quad & =\text{map}_{2}\,(p\times q)(\text{id}\bef f)=\text{map}_{2}\,(p\times q)(f)\quad. \end{align*} @@ -1463,14 +1447,16 @@ \subsubsection{Statement \label{subsec:Statement-map2-zip-equivalence}\ref{subse \] Then we need to show that $\text{zip}^{\prime}=\text{zip}$. We apply $\text{zip}^{\prime}$ to arbitrary arguments $p$, $q$ and write: -\[ -\text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{map}_{2}\,(p\times q)(\text{id}^{:A\times B\rightarrow A\times B})=(p\times q)\triangleright\text{zip}\triangleright\text{id}^{\uparrow L}=(p\times q)\triangleright\text{zip}=\text{zip}\,(p\times q)\quad. -\] +\begin{align*} + & \text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{map}_{2}\,(p\times q)(\text{id}^{:A\times B\rightarrow A\times B})=(p\times q)\triangleright\text{zip}\triangleright\text{id}^{\uparrow L}\\ + & \quad=(p\times q)\triangleright\text{zip}=\text{zip}\,(p\times q)\quad. +\end{align*} It remains to show that the \lstinline!map2! method will satisfy the naturality law if defined via \lstinline!zip!: \begin{align*} - & \gunderline{\text{map}_{2}\,(p\times q)(f)}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright(f\bef g)^{\uparrow L}\\ + & \gunderline{\text{map}_{2}\,(p\times q)(f)}\triangleright g^{\uparrow L}=(p\times q)\triangleright\text{zip}\triangleright f^{\uparrow L}\triangleright g^{\uparrow L}\\ + & =(p\times q)\triangleright\text{zip}\triangleright(f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{definition of }\text{map}_{2}\text{ via }\text{zip}:}\quad & =\text{map}_{2}\,(p\times q)(f\bef g)\quad. \end{align*} $\square$ @@ -1500,8 +1486,7 @@ \subsubsection{Statement \label{subsec:Statement-map2-zip-equivalence}\ref{subse } \] \begin{align*} - & \text{fmap}_{2}\,(f^{:A\rightarrow B\rightarrow C})=f^{\uparrow L}\bef\text{ap}^{B,C}\quad,\\ - & \text{ap}^{A,B}=\text{fmap}_{2}\,(\text{id}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow B})\quad. + & \text{fmap}_{2}\,(f^{:A\rightarrow B\rightarrow C})=f^{\uparrow L}\bef\text{ap}^{B,C}\quad,\quad\quad\text{ap}^{A,B}=\text{fmap}_{2}\,(\text{id}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow B})\quad. \end{align*} We are now ready to prove the equivalence of \lstinline!ap! and \lstinline!fmap2!: @@ -1539,7 +1524,8 @@ \subsubsection{Statement \label{subsec:Statement-fmap2-equivalence-to-ap}\ref{su Then we need to show that $\text{fmap}_{2}^{\prime}=\text{fmap}_{2}$. We apply $\text{fmap}_{2}^{\prime}$ to arbitrary arguments and write: \begin{align*} - & \text{fmap}_{2}^{\prime}\,(f^{:A\rightarrow B\rightarrow C})(p^{:L^{A}})=p\triangleright f^{\uparrow L}\triangleright\text{ap}=\text{fmap}_{2}\,(\text{id})(p\triangleright f^{\uparrow L})\\ + & \text{fmap}_{2}^{\prime}\,(f^{:A\rightarrow B\rightarrow C})(p^{:L^{A}})=p\triangleright f^{\uparrow L}\triangleright\text{ap}\\ + & =\text{fmap}_{2}\,(\text{id})(p\triangleright f^{\uparrow L})\\ {\color{greenunder}\text{naturality law of }\text{fmap}_{2}:}\quad & =\text{fmap}_{2}\,(f\bef\text{id})(p)=\text{fmap}_{2}\,(f)(p)\quad. \end{align*} @@ -1584,9 +1570,10 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: The functions \lstinline!zip! and \lstinline!ap! are equivalent assuming the following naturality laws: -\[ -(f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\bef(f\boxtimes\text{id})^{\uparrow L}\quad,\quad\big(\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})\big)\triangleright(f^{:B\rightarrow C})^{\uparrow L}=\text{ap}\big(r\triangleright(x^{:A\rightarrow B}\rightarrow x\bef f)^{\uparrow L}\big)(p)\quad. -\] +\begin{align*} + & (f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\bef(f\boxtimes\text{id})^{\uparrow L}\quad,\\ + & \big(\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})\big)\triangleright(f^{:B\rightarrow C})^{\uparrow L}=\text{ap}\big(r\triangleright(x^{:A\rightarrow B}\rightarrow x\bef f)^{\uparrow L}\big)(p)\quad. +\end{align*} \subparagraph{Proof} @@ -1600,9 +1587,10 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: \] The code of these fully parametric functions follows from their types. Then we can write: -\[ -\text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\quad,\quad\quad\text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\quad. -\] +\begin{align*} + & \text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\quad,\\ + & \text{ap}\,(r^{:L^{A\rightarrow B}})(p^{:L^{A}})=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\quad. +\end{align*} The functions \lstinline!pair! and \lstinline!eval! satisfy the following property that we will use in the proof: @@ -1627,15 +1615,17 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: $\text{zip}^{\prime}$ to arbitrary arguments and write: \begin{align*} {\color{greenunder}\text{expect to equal }\text{zip}\,(p\times q):}\quad & \text{zip}^{\prime}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\\ -{\color{greenunder}\text{definition of }\text{ap}:}\quad & =\big((p\triangleright\text{pair}^{\uparrow L})\times q\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}=(p\times q)\triangleright\gunderline{(\text{pair}^{\uparrow L}\times\text{id})\bef\text{zip}}\bef\text{eval}^{\uparrow L}\\ +{\color{greenunder}\text{definition of }\text{ap}:}\quad & =\big((p\triangleright\text{pair}^{\uparrow L})\times q\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ + & =(p\times q)\triangleright\gunderline{(\text{pair}^{\uparrow L}\times\text{id})\bef\text{zip}}\bef\text{eval}^{\uparrow L}\\ {\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =(p\times q)\triangleright\text{zip}\bef\gunderline{(\text{pair}\boxtimes\text{id})^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ {\color{greenunder}\text{use Eq.~(\ref{eq:pair-and-eval-property-derivation1})}:}\quad & =(p\times q)\triangleright\text{zip}\bef\text{id}^{\uparrow L}=(p\times q)\triangleright\text{zip}\quad. \end{align*} It remains to show that the \lstinline!ap! method defined via \lstinline!zip! -will satisfy its required naturality law: +will obey its naturality law: \begin{align*} {\color{greenunder}\text{left-hand side}:}\quad & \big(\text{ap}\,(r)(p)\big)\triangleright f^{\uparrow L}=(r\times p)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\bef f^{\uparrow L}\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \text{ap}\big(r\triangleright(x\rightarrow x\bef f)^{\uparrow L}\big)(p)=\big((r\triangleright(x\rightarrow x\bef f)^{\uparrow L})\times p\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ +{\color{greenunder}\text{right-hand side}:}\quad & \text{ap}\big(r\triangleright(x\rightarrow x\bef f)^{\uparrow L}\big)(p)\\ + & \quad=\big((r\triangleright(x\rightarrow x\bef f)^{\uparrow L})\times p\big)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ {\color{greenunder}\text{naturality law of }\text{zip}:}\quad & \quad=(r\times p)\triangleright\text{zip}\bef\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)^{\uparrow L}\bef\text{eval}^{\uparrow L}\quad. \end{align*} The difference between the two sides of the law will disappear if @@ -1647,8 +1637,9 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: and obtain equal results: \begin{align*} {\color{greenunder}\text{left-hand side}:}\quad & (g^{:A\rightarrow B}\times a^{:A})\triangleright\text{eval}\bef f=(g\times a)\triangleright\text{eval}\triangleright f=g(a)\triangleright f=a\triangleright g\triangleright f\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & (g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\bef\text{eval}=(g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\triangleright\text{eval}\\ - & \quad=\big((g\bef f)\times a\big)\triangleright\text{eval}=a\triangleright g\bef f=a\triangleright g\bef f\quad. +{\color{greenunder}\text{right-hand side}:}\quad & (g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\bef\text{eval}\\ + & \quad=(g\times a)\triangleright\big((x\rightarrow x\bef f)\boxtimes\text{id}\big)\triangleright\text{eval}=\big((g\bef f)\times a\big)\triangleright\text{eval}\\ + & \quad=a\triangleright g\bef f=a\triangleright g\triangleright f\quad. \end{align*} \textbf{(2)} Given any function $\text{ap}:L^{A\rightarrow B}\rightarrow L^{A}\rightarrow L^{A}$, @@ -1663,7 +1654,8 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: \] Then we need to show that $\text{ap}^{\prime}=\text{ap}$. We write: \begin{align*} - & \text{ap}^{\prime}\,(r)(p)=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}=\big(\text{ap}\,(r\triangleright\text{pair}^{\uparrow L})(p)\gunderline{\big)\triangleright\text{eval}^{\uparrow L}}\quad.\\ + & \text{ap}^{\prime}\,(r)(p)=(r\times p)\triangleright\text{zip}\triangleright\text{eval}^{\uparrow L}\\ + & =\big(\text{ap}\,(r\triangleright\text{pair}^{\uparrow L})(p)\gunderline{\big)\triangleright\text{eval}^{\uparrow L}}\\ {\color{greenunder}\text{naturality law of }\text{ap}:}\quad & =\text{ap}\big(r\,\gunderline{\triangleright\,\text{pair}^{\uparrow L}\triangleright(x^{:A\rightarrow\left(A\rightarrow B\right)\times A}\rightarrow x\bef\text{eval})^{\uparrow L}}\big)(p)\\ {\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{ap}\big(r\triangleright(\text{pair}\bef(x\rightarrow x\bef\text{eval}))^{\uparrow L}\big)(p)\quad. \end{align*} @@ -1675,15 +1667,17 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: To see this, apply both sides to an arbitrary value $f$ of type $A\rightarrow B$: \begin{align*} {\color{greenunder}\text{expect to equal }f:}\quad & f^{:A\rightarrow B}\triangleright\text{pair}^{:\left(A\rightarrow B\right)\rightarrow A\rightarrow\left(A\rightarrow B\right)\times A}\bef(x^{:A\rightarrow\left(A\rightarrow B\right)\times A}\rightarrow x\bef\text{eval})\\ - & =(a^{:A}\rightarrow f\times a)\bef(x\rightarrow x\bef\text{eval})=a^{:A}\rightarrow(f\times a)\triangleright\text{eval}=a^{:A}\rightarrow f(a)=f\quad. + & =(a^{:A}\rightarrow f\times a)\bef(x\rightarrow x\bef\text{eval})=a^{:A}\rightarrow(f\times a)\triangleright\text{eval}\\ + & =a^{:A}\rightarrow f(a)=f\quad. \end{align*} -Finally, we show that the \lstinline!zip! method will satisfy its -naturality law if defined via \lstinline!ap!: +Finally, we show that \lstinline!zip! will obey its naturality law +if defined via \lstinline!ap!: \begin{align*} {\color{greenunder}\text{left-hand side}:}\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright(f^{\uparrow L}\boxtimes\text{id})\bef\text{zip}=\text{zip}\big((p\triangleright f^{\uparrow L})\times q\big)\\ {\color{greenunder}\text{express }\text{zip}\text{ via }\text{ap}:}\quad & \quad=\text{ap}\big(p\triangleright f^{\uparrow L}\triangleright\text{pair}^{\uparrow L})(q)=\text{ap}\big(p\triangleright(f\bef\text{pair})^{\uparrow L})(q)\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright\text{zip}\triangleright(f\boxtimes\text{id})^{\uparrow L}=\big(\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\gunderline{\big)\triangleright(f\boxtimes\text{id})^{\uparrow L}}\\ +{\color{greenunder}\text{right-hand side}:}\quad & (p^{:L^{A}}\times q^{:L^{B}})\triangleright\text{zip}\triangleright(f\boxtimes\text{id})^{\uparrow L}\\ + & \quad=\big(\text{ap}\,(p\triangleright\text{pair}^{\uparrow L})(q)\gunderline{\big)\triangleright(f\boxtimes\text{id})^{\uparrow L}}\\ {\color{greenunder}\text{naturality law of }\text{ap}:}\quad & \quad=\text{ap}\big(p\triangleright\text{pair}^{\uparrow L}\triangleright(x\rightarrow x\bef(f\boxtimes\text{id}))^{\uparrow L}\big)(q)\quad. \end{align*} The remaining difference will disappear if for any $f^{:Z\rightarrow A}$, @@ -1694,9 +1688,12 @@ \subsubsection{Statement \label{subsec:Statement-zip-ap-equivalence}\ref{subsec: To verify this equation, substitute the definition of \lstinline!pair! into both sides: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & f\bef\text{pair}=(z^{:Z}\rightarrow f(z))\bef(a^{:A}\rightarrow b^{:B}\rightarrow a\times b)=z\rightarrow b\rightarrow f(z)\times b\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \text{pair}\bef(x\rightarrow x\bef(f\boxtimes\text{id}))=(z^{:Z}\rightarrow b^{:B}\rightarrow z\times b)\bef(x^{:B\rightarrow Z\times B}\rightarrow x\bef(f\boxtimes\text{id}))\\ -{\color{greenunder}\text{compute composition}:}\quad & \quad=z\rightarrow(b\rightarrow z\times b)\bef(f\boxtimes\text{id})=z\rightarrow b\rightarrow f(z)\times b\quad. +{\color{greenunder}\text{left-hand side}:}\quad & f\bef\text{pair}=(z^{:Z}\rightarrow f(z))\bef(a^{:A}\rightarrow b^{:B}\rightarrow a\times b)\\ + & \quad=z\rightarrow b\rightarrow f(z)\times b\quad,\\ +{\color{greenunder}\text{right-hand side}:}\quad & \text{pair}\bef(x\rightarrow x\bef(f\boxtimes\text{id}))\\ + & \quad=(z^{:Z}\rightarrow b^{:B}\rightarrow z\times b)\bef(x^{:B\rightarrow Z\times B}\rightarrow x\bef(f\boxtimes\text{id}))\\ +{\color{greenunder}\text{compute composition}:}\quad & \quad=z\rightarrow(b\rightarrow z\times b)\bef(f\boxtimes\text{id})\\ + & \quad=z\rightarrow b\rightarrow f(z)\times b\quad. \end{align*} Both sides are now equal. $\square$ @@ -1905,9 +1902,11 @@ \subsection{Deriving the laws of \texttt{zip} from the laws of \texttt{map2}\lab Begin with the associativity law and write its two sides separately: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{map}_{2}\,(p^{:L^{A}}\times\text{map}_{2}\,(q^{:L^{B}}\times r^{:L^{C}})(\text{id}^{:B\times C\rightarrow B\times C}))\big(a^{:A}\times(b^{:B}\times c^{:C})\rightarrow g(a\times b\times c)\big)\\ + & \quad{\color{greenunder}\text{left-hand side}:}\quad\\ + & \text{map}_{2}\,(p^{:L^{A}}\times\text{map}_{2}\,(q^{:L^{B}}\times r^{:L^{C}})(\text{id}^{:B\times C\rightarrow B\times C}))\big(a^{:A}\times(b^{:B}\times c^{:C})\rightarrow g(a\times b\times c)\big)\\ & \quad=\text{zip}\,(p\times\text{zip}\,(q\times r))\triangleright(a\times(b\times c)\rightarrow g(a\times b\times c))^{\uparrow L}\\ -{\color{greenunder}\text{right-hand side}:}\quad & \overset{!}{=}\text{map}_{2}\,(\text{map}_{2}\,(p\times q)(\text{id})\times r)\big((a^{:A}\times b^{:B})\times c^{:C}\rightarrow g(a\times b\times c)\big)\\ + & \quad{\color{greenunder}\text{right-hand side}:}\quad\\ + & \overset{!}{=}\text{map}_{2}\,(\text{map}_{2}\,(p\times q)(\text{id})\times r)\big((a^{:A}\times b^{:B})\times c^{:C}\rightarrow g(a\times b\times c)\big)\\ & \quad=\text{zip}\,(\text{zip}\,(p\times q)\times r)\triangleright((a\times b)\times c)\rightarrow g(a\times b\times c))^{\uparrow L}\quad. \end{align*} Both sides now depend on an arbitrary function $g^{:A\times B\times C\rightarrow D}$ @@ -1930,9 +1929,9 @@ \subsection{Deriving the laws of \texttt{zip} from the laws of \texttt{map2}\lab \end{equation} A type diagram illustrating this law is shown below: \[ -\xymatrix{\xyScaleY{1.4pc}\xyScaleX{1.7pc} & L^{A\times B}\times L^{C}\ar[r]\sp(0.5){\text{zip}} & L^{(A\times B)\times C}\ar[rd]\sp(0.5){\varepsilon_{12,3}^{\uparrow L}} & & L^{A\times(B\times C)}\ar[ld]\sb(0.5){\varepsilon_{1,23}^{\uparrow L}} & L^{A}\times L^{B\times C}\ar[l]\sb(0.5){\text{zip}}\\ -L^{A}\times L^{B}\ar[r]\sp(0.55){\text{zip}} & L^{A\times B}\ar[u] & & L^{A\times B\times C} & & L^{B\times C}\ar[u] & L^{B}\times L^{C}\ar[l]\sb(0.5){\text{zip}}\\ - & & p:L^{A}\ar[llu]\ar[rrruu] & q:L^{B}\ar[lllu]\ar[rrru] & r:L^{C}\ar[rru]\ar[llluu] +\xymatrix{\xyScaleY{1.4pc}\xyScaleX{1.7pc}L^{A\times B}\times L^{C}\ar[r]\sp(0.5){\text{zip}} & L^{(A\times B)\times C}\ar[rd]\sp(0.5){\varepsilon_{12,3}^{\uparrow L}} & & L^{A\times(B\times C)}\ar[ld]\sb(0.5){\varepsilon_{1,23}^{\uparrow L}} & L^{A}\times L^{B\times C}\ar[l]\sb(0.5){\text{zip}}\\ +L^{A}\times L^{B}\ar[r]\sp(0.55){\text{zip}} & L^{A\times B}\ar[lu] & L^{A\times B\times C} & L^{B\times C}\ar[ru] & L^{B}\times L^{C}\ar[l]\sb(0.5){\text{zip}}\\ + & p:L^{A}\ar[lu]\ar[rrruu] & q:L^{B}\ar[llu]\ar[rru] & r:L^{C}\ar[ru]\ar[llluu] } \] @@ -1968,18 +1967,18 @@ \subsection{Deriving the laws of \texttt{zip} from the laws of \texttt{map2}\lab To avoid errors, derivations using this technique must first check that all types match up to tuple-swapping isomorphisms. -We now turn to the identity laws. Substitute Eq.~(\ref{eq:express-map2-via-zip}) +Turn to the identity laws. Substitute Eq.~(\ref{eq:express-map2-via-zip}) into \lstinline!map2!\textsf{'}s left identity law: \begin{align*} {\color{greenunder}\text{left-hand side}:}\quad & \text{map}_{2}\,(\text{pu}_{L}(a^{:A})\times q^{:L^{B}})(g)=\text{zip}\,(\text{pu}_{L}(a)\times q)\triangleright g^{\uparrow L}\\ {\color{greenunder}\text{right-hand side}:}\quad & \overset{!}{=}q\triangleright(b^{:B}\rightarrow g(a\times b))^{\uparrow L}=q\triangleright(b^{:B}\rightarrow a\times b)^{\uparrow L}\triangleright g^{\uparrow L}\quad. \end{align*} -We may remove the common function $g^{\uparrow L}$ from both sides -and get an equivalent law: +Remove the common function $g^{\uparrow L}$ from both sides and get +an equivalent law: \[ \text{zip}\,(\text{pu}_{L}(a)\times q)\overset{!}{=}q\triangleright(b\rightarrow a\times b)^{\uparrow L}\quad. \] -We express \lstinline!pure! through the \textsf{``}wrapped unit\textsf{''} value\index{wrapped@\textsf{``}wrapped unit\textsf{''} value} +Express \lstinline!pure! through the \textsf{``}wrapped unit\textsf{''} value\index{wrapped@\textsf{``}wrapped unit\textsf{''} value} (\lstinline!wu!) as we did in Section~\ref{subsec:Pointed-functors-motivation-equivalence}: \[ \text{wu}:L^{\bbnum 1}\quad,\quad\quad\text{pu}_{L}(a)=\text{wu}\triangleright(1\rightarrow a)^{\uparrow L}\quad. @@ -2087,9 +2086,10 @@ \subsubsection{Definition \label{subsec:Definition-commutative-applicative}\ref{ An applicative functor $L^{\bullet}$ is \textbf{commutative}\index{applicative functor!commutative} if its \lstinline!zip! operation satisfies the commutativity law\index{commutativity law!of zip@of \texttt{zip}} (in addition to the standard applicative laws): -\begin{equation} -\text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{zip}\,(q\times p)\triangleright(b^{:B}\times a^{:A}\rightarrow a\times b)^{\uparrow L}\quad\text{or equivalently}:\quad\text{swap}\bef\text{zip}=\text{zip}\bef\text{swap}^{\uparrow L}\quad.\label{eq:commutativity-law-of-zip} -\end{equation} +\begin{align} + & \text{zip}\,(p^{:L^{A}}\times q^{:L^{B}})=\text{zip}\,(q\times p)\triangleright(b^{:B}\times a^{:A}\rightarrow a\times b)^{\uparrow L}\nonumber \\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{swap}\bef\text{zip}=\text{zip}\bef\text{swap}^{\uparrow L}\quad.\label{eq:commutativity-law-of-zip} +\end{align} Here we used the standard Scala function \lstinline!swap! defined by $\text{swap}\triangleq a\times b\rightarrow b\times a$. @@ -2100,10 +2100,9 @@ \subsubsection{Definition \label{subsec:Definition-commutative-applicative}\ref{ \[ p\,\,\text{zip}\,\,q\cong q\,\,\text{zip}\,\,p\quad. \] - -This definition agrees with that of the commutative monad (see Exercise~\ref{subsec:Exercise-1-monads-9-1}). -A monad\textsf{'}s commutativity is defined via code that is equivalent to -the \lstinline!map2! operation:\texttt{\textcolor{blue}{\footnotesize{}}} +This definition agrees with that of the commutative monad (Exercise~\ref{subsec:Exercise-1-monads-9-1}). +A monad\textsf{'}s commutativity property is defined via code that is equivalent +to the \lstinline!map2! operation:\texttt{\textcolor{blue}{\footnotesize{}}} \begin{lstlisting} def map2[A, B, C](p: M[A], q: M[B])(f: (A, B) => C): M[C] = for { x <- p // Effects of p and q are independent of @@ -2112,7 +2111,7 @@ \subsubsection{Definition \label{subsec:Definition-commutative-applicative}\ref{ \end{lstlisting} So, the definition of a commutative monad is that the corresponding \lstinline!map2! operation (defined via \lstinline!map! and \lstinline!flatMap!) -must satisfy the following commutativity property: +must satisfy the commutativity property: \[ \text{map}_{2}(p\times q)(f)=\text{map}_{2}(q\times p)\big(b\times a\rightarrow f(a\times b)\big)\quad. \] @@ -2170,11 +2169,12 @@ \subsubsection{Definition \label{subsec:Definition-commutative-applicative}\ref{ \noindent The difference is only in the order in which the effects of \lstinline!p! and \lstinline!q! are concatenated. The two corresponding \lstinline!zip! functions differ by the permutation of the effects: -\[ -\text{zip}\left(p\times q\right)\triangleq p\triangleright\text{flm}_{L}(a\rightarrow q\triangleright(b\rightarrow a\times b)^{\uparrow L})\quad,\quad\quad\text{zip}^{\prime}\left(p\times q\right)=\text{zip}\left(q\times p\right)\triangleright\text{swap}^{\uparrow L}\quad. -\] -For commutative monads, there will be no difference between $\text{zip}^{\prime}$ -and $\text{zip}$. +\begin{align*} + & \text{zip}\left(p\times q\right)\triangleq p\triangleright\text{flm}_{L}(a\rightarrow q\triangleright(b\rightarrow a\times b)^{\uparrow L})\quad,\\ + & \text{zip}^{\prime}\left(p\times q\right)\triangleq q\triangleright\text{flm}_{L}(b\rightarrow p\triangleright(a\rightarrow a\times b)^{\uparrow L})=\text{zip}\left(q\times p\right)\triangleright\text{swap}^{\uparrow L}\quad. +\end{align*} +For commutative monads, there will be no difference between \lstinline!zip!$^{\prime}$ +and \lstinline!zip!. When an applicative functor is commutative, its associativity law has a simplified form: @@ -2208,7 +2208,7 @@ \subsubsection{Statement \label{subsec:Statement-associativity-law-of-zip-with-c and apply Eq.~(\ref{eq:zip-associativity-law}): \begin{align*} & p\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,r)\cong\gunderline{(p\,\,\text{zip}\,\,q)}\,\,\text{zip}\,\,\gunderline r\\ -{\color{greenunder}\text{twice use the commutativity law of }\text{zip}:}\quad & \cong r\,\,\text{zip}\,\,(\gunderline p\,\,\text{zip}\,\,\gunderline q)\cong r\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,p)\quad. +{\color{greenunder}\text{use the commutativity law of }\text{zip}:}\quad & \cong r\,\,\text{zip}\,\,(\gunderline p\,\,\text{zip}\,\,\gunderline q)\cong r\,\,\text{zip}\,\,(q\,\,\text{zip}\,\,p)\quad. \end{align*} This is the right-hand side of Eq.~(\ref{eq:associativity-law-of-zip-commutative-short}) @@ -2221,11 +2221,10 @@ \subsubsection{Statement \label{subsec:Statement-associativity-law-of-zip-with-c We have derived Eq.~(\ref{eq:zip-associativity-law}). $\square$ This statement makes it easier to check the associativity law of \lstinline!zip! -if we know that the commutativity law holds. We just need to write -the code for $\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)$ -and swap $p^{:L^{A}}$ and $r^{:L^{C}}$ in that code. The result -must be the same up to swapping the result values of types $A$ and -$C$. +if we know that the commutativity law holds. We just need to swap +$p^{:L^{A}}$ and $r^{:L^{C}}$ in the code for $\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)$. +The result must be the same as when swapping the result values of +types $A$ and $C$. For commutative applicative functors, it is also sufficient to check only \emph{one} of the identity laws: @@ -2329,24 +2328,33 @@ \subsubsection{Statement \label{subsec:Statement-applicative-composition}\ref{su To verify the right identity law: \begin{align*} {\color{greenunder}\text{expect to equal }p\triangleright\text{iru}^{\uparrow L}:}\quad & \text{zip}_{L}(p^{:F^{G^{A}}}\times\text{wu}_{L})=(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\\ -{\color{greenunder}\text{right identity law of }\text{zip}_{F}:}\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}=p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})}\big)^{\uparrow F}\\ +{\color{greenunder}\text{right identity law of }\text{zip}_{F}:}\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}\\ + & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})}\big)^{\uparrow F}\\ {\color{greenunder}\text{right identity law of }\text{zip}_{G}:}\quad & =p\triangleright(\gunderline{g\rightarrow g\,\triangleright}\,\text{iru}^{\uparrow G})^{\uparrow F}=p\triangleright(\text{iru}^{\uparrow G})^{\uparrow F}=p\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} To verify the associativity law, first substitute the definition of $\text{zip}_{L}$ into one side: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\varepsilon_{1,23}^{\uparrow L}=\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ -{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}\\ -{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}}\\ -{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\varepsilon_{1,23}^{\uparrow G}\big)^{\uparrow F}\quad. + & \quad{\color{greenunder}\text{left-hand side}:}\quad\\ + & \text{zip}_{L}\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\varepsilon_{1,23}^{\uparrow L}=\big(p\times\text{zip}_{L}(q\times r)\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad\\ + & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}\\ + & \quad{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad\\ + & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{1,23}^{\uparrow G\uparrow F}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad\\ + & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\varepsilon_{1,23}^{\uparrow G}\big)^{\uparrow F}\quad. \end{align*} Now rewrite the right-hand side in a similar way: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\varepsilon_{12,3}^{\uparrow L}=\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow L}\\ -{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}\\ -{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}}\\ -{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\varepsilon_{12,3}^{\uparrow G}\big)^{\uparrow F}\quad. + & \quad{\color{greenunder}\text{right-hand side}:}\quad\\ + & \text{zip}_{L}\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\varepsilon_{12,3}^{\uparrow L}=\big(\text{zip}_{L}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow L}\\ + & \quad{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad\\ + & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}\\ + & \quad{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad\\ + & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\varepsilon_{12,3}^{\uparrow G\uparrow F}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad\\ + & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\varepsilon_{12,3}^{\uparrow G}\big)^{\uparrow F}\quad. \end{align*} The two sides become equal after using the associativity laws of $\text{zip}_{F}$ and $\text{zip}_{G}$: @@ -2360,7 +2368,7 @@ \subsubsection{Statement \label{subsec:Statement-applicative-composition}\ref{su \begin{align*} {\color{greenunder}\text{expect to equal }(\text{zip}_{L}\bef\text{swap}^{\uparrow L}):}\quad & \text{swap}\bef\text{zip}_{L}=\gunderline{\text{swap}\bef\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\\ {\color{greenunder}\text{commutativity law of }F:}\quad & =\text{zip}_{F}\bef\gunderline{\text{swap}^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}}=\text{zip}_{F}\bef(\gunderline{\text{swap}\bef\text{zip}_{G}})^{\uparrow F}\\ -{\color{greenunder}\text{commutativity law of }G\text{ under }^{\uparrow F}:}\quad & =\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{swap}^{\uparrow G\uparrow F}=\text{zip}_{L}\bef\text{swap}^{\uparrow L}\quad. +{\color{greenunder}\text{commutativity law of }G\text{ under }^{\uparrow F}:}\quad & =\gunderline{\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}}\bef\text{swap}^{\gunderline{\uparrow G\uparrow F}}=\text{zip}_{L}\bef\text{swap}^{\uparrow L}\quad. \end{align*} $\square$ @@ -2388,30 +2396,38 @@ \subsubsection{Statement \label{subsec:Statement-applicative-product}\ref{subsec To verify the left identity law of $\text{zip}_{L}$: \begin{align*} -{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow L}:}\quad & \text{zip}_{L}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{L}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ -{\color{greenunder}\text{definition of }\text{zip}_{L}:}\quad & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ -{\color{greenunder}\text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad & =(p\triangleright\text{ilu}^{\uparrow F})\times(q\triangleright\text{ilu}^{\uparrow G})=(p\times q)\triangleright(\text{ilu}^{\uparrow F}\boxtimes\text{ilu}^{\uparrow G})\\ -{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad & =(p\times q)\triangleright\text{ilu}^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow L}:}\quad\\ + & \text{zip}_{L}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{L}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ + & \quad{\color{greenunder}\text{definition of }\text{zip}_{L}:}\quad\\ + & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ + & \quad{\color{greenunder}\text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad\\ + & =(p\triangleright\text{ilu}^{\uparrow F})\times(q\triangleright\text{ilu}^{\uparrow G})=(p\times q)\triangleright(\text{ilu}^{\uparrow F}\boxtimes\text{ilu}^{\uparrow G})\\ + & \quad{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad\\ + & =(p\times q)\triangleright\text{ilu}^{\uparrow L}\quad. \end{align*} To verify the right identity law of $\text{zip}_{L}$: \begin{align*} -{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow L}:}\quad & \text{zip}_{L}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{L}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ -{\color{greenunder}\text{definition of }\text{zip}_{L}:}\quad & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ -{\color{greenunder}\text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad & =(p\triangleright\text{iru}^{\uparrow F})\times(q\triangleright\text{iru}^{\uparrow G})=(p\times q)\triangleright(\text{iru}^{\uparrow F}\boxtimes\text{iru}^{\uparrow G})\\ -{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad & =(p\times q)\triangleright\text{iru}^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow L}:}\quad\\ + & \text{zip}_{L}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{L}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ + & \quad{\color{greenunder}\text{definition of }\text{zip}_{L}:}\quad\\ + & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ + & \quad{\color{greenunder}\text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad\\ + & =(p\triangleright\text{iru}^{\uparrow F})\times(q\triangleright\text{iru}^{\uparrow G})=(p\times q)\triangleright(\text{iru}^{\uparrow F}\boxtimes\text{iru}^{\uparrow G})\\ + & \quad{\color{greenunder}\text{definition of }^{\uparrow L}:}\quad\\ + & =(p\times q)\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} To verify the associativity law, begin with its left-hand side and use the definition of $\text{zip}_{L}$: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times\text{zip}_{L}\big((q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\big)\triangleright\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ + & \text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times\text{zip}_{L}\big((q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\big)\triangleright\gunderline{\varepsilon_{1,23}^{\uparrow L}}\\ & =\text{zip}_{L}\big((p_{1}\times p_{2})\times\big(\text{zip}_{F}(q_{1}\times r_{1})\times\text{zip}_{G}(q_{2}\times r_{2})\big)\big)\triangleright\big(\varepsilon_{1,23}^{\uparrow F}\boxtimes\varepsilon_{1,23}^{\uparrow G}\big)\\ & =\big(\gunderline{\text{zip}_{F}\big(p_{1}\times\text{zip}_{F}(q_{1}\times r_{1})\big)\triangleright\varepsilon_{1,23}^{\uparrow F}}\big)\times\big(\gunderline{\text{zip}_{G}\big(p_{2}\times\text{zip}_{G}(q_{2}\times r_{2})\big)\triangleright\varepsilon_{1,23}^{\uparrow G}}\big)\quad. \end{align*} The right-hand side is rewritten in a similar way: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}\big(\text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times(q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\big)\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\triangleright\gunderline{\varepsilon_{12,3}^{\uparrow L}}\\ + & \text{zip}_{L}\big(\text{zip}_{L}\big((p_{1}^{:F^{A}}\times p_{2}^{:G^{A}})\times(q_{1}^{:F^{B}}\times q_{2}^{:G^{B}})\big)\times(r_{1}^{:F^{C}}\times r_{2}^{:G^{C}})\big)\triangleright\gunderline{\varepsilon_{12,3}^{\uparrow L}}\\ & =\text{zip}_{L}\big(\big(\text{zip}_{F}(p_{1}\times q_{1})\times\text{zip}_{G}(p_{2}\times q_{2})\big)\times(r_{1}\times r_{2})\big)\big)\triangleright\big(\varepsilon_{12,3}^{\uparrow F}\boxtimes\varepsilon_{12,3}^{\uparrow G}\big)\\ & =\big(\gunderline{\text{zip}_{F}\big(\text{zip}_{F}(p_{1}\times q_{1})\times r_{1}\big)\triangleright\varepsilon_{12,3}^{\uparrow F}}\big)\times\big(\gunderline{\text{zip}_{G}\big(\text{zip}_{G}(p_{2}\times q_{2})\times r_{2}\big)\triangleright\varepsilon_{12,3}^{\uparrow G}}\big)\quad. \end{align*} @@ -2421,10 +2437,14 @@ \subsubsection{Statement \label{subsec:Statement-applicative-product}\ref{subsec To verify the commutativity law of $L$ assuming it holds for $F$ and $G$: \begin{align*} -{\color{greenunder}\text{expect to equal }\text{zip}_{L}\big((p\times q)\times(m\times n)\big):}\quad & \text{zip}_{L}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow L}\\ -{\color{greenunder}\text{definitions of }\text{zip}_{L}\text{ and }^{\uparrow L}:}\quad & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright(\text{swap}^{\uparrow F}\boxtimes\text{swap}^{\uparrow G})\\ -{\color{greenunder}\text{definition of }\boxtimes:}\quad & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\big)\\ -{\color{greenunder}\text{commutativity laws of }F\text{ and }G:}\quad & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{L}\big((p\times q)\times(m\times n)\big)\quad. + & \quad{\color{greenunder}\text{expect to equal }\text{zip}_{L}\big((p\times q)\times(m\times n)\big):}\quad\\ + & \text{zip}_{L}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow L}\\ + & \quad{\color{greenunder}\text{definitions of }\text{zip}_{L}\text{ and }^{\uparrow L}:}\quad\\ + & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright(\text{swap}^{\uparrow F}\boxtimes\text{swap}^{\uparrow G})\\ + & \quad{\color{greenunder}\text{definition of }\boxtimes:}\quad\\ + & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\big)\\ + & \quad{\color{greenunder}\text{commutativity laws of }F\text{ and }G:}\quad\\ + & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{L}\big((p\times q)\times(m\times n)\big)\quad. \end{align*} $\square$ @@ -2442,7 +2462,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-constant-functo If $F^{\bullet}$ is applicative and $Z$ is a fixed monoid type then $L^{A}\triangleq Z+F^{A}$ is applicative: \begin{align*} - & \text{zip}_{L}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\quad\quad\text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{L}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\\ + & \text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} & Z & F^{A\times B}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{A}\times Z & \_^{:F^{A}}\times z\rightarrow z & \bbnum 0\\ @@ -2471,7 +2492,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-constant-functo To verify the left identity law, we use the left identity law of $\text{zip}_{F}$: \begin{align*} - & \text{zip}_{L}(\text{wu}_{L}\times p^{:Z+F^{B}})=\text{zip}_{L}((\bbnum 0+\text{wu}_{F})\times p)=(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(\text{wu}_{L}\times p^{:Z+F^{B}})=\text{zip}_{L}((\bbnum 0+\text{wu}_{F})\times p)\\ + & =(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} & Z & F^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times Z & \_^{:F^{\bbnum 1}}\times z\rightarrow z & \bbnum 0\\ F^{\bbnum 1}\times F^{B} & \bbnum 0 & \text{zip}_{F} @@ -2484,12 +2506,14 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-constant-functo & Z & F^{\bbnum 1\times B}\\ \hline Z & \text{id} & \bbnum 0\\ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F} -\end{array}\,=p\triangleright\text{ilu}^{\uparrow L}\quad. +\end{array}\\ + & =p\triangleright\text{ilu}^{\uparrow L}\quad. \end{align*} To verify the right identity law, we write a similar calculation: \begin{align*} - & \text{zip}_{L}(p^{:Z+F^{A}}\times\text{wu}_{L})=\text{zip}_{L}(p\times(\bbnum 0+\text{wu}_{F}))=(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(p^{:Z+F^{A}}\times\text{wu}_{L})=\text{zip}_{L}(p\times(\bbnum 0+\text{wu}_{F}))\\ + & =(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z\times F^{\bbnum 1} & z\times\_^{:F^{\bbnum 1}}\rightarrow z & \bbnum 0\\ F^{A}\times F^{\bbnum 1} & \bbnum 0 & \text{zip}_{F} @@ -2502,7 +2526,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-constant-functo & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & k\rightarrow k\triangleright\text{iru}^{\uparrow F} -\end{array}\,=p\triangleright\text{iru}^{\uparrow L}\quad. +\end{array}\\ + & =p\triangleright\text{iru}^{\uparrow L}\quad. \end{align*} To verify the associativity law, we use a trick to avoid long derivations. @@ -2550,13 +2575,14 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-constant-functo To verify the commutativity law of $L$, use the code matrix for \lstinline!swap! with the relevant types: \begin{align*} - & \text{swap}\bef\text{zip}_{L}=\,\begin{array}{|c||cccc|} +\text{swap}\bef\text{zip}_{L} & =\,\begin{array}{|c||cccc|} & Z\times Z & F^{B}\times Z & Z\times F^{A} & F^{B}\times F^{A}\\ \hline Z\times Z & \text{swap} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ F^{A}\times Z & \bbnum 0 & \bbnum 0 & \text{swap} & \bbnum 0\\ Z\times F^{B} & \bbnum 0 & \text{swap} & \bbnum 0 & \bbnum 0\\ F^{A}\times F^{B} & \bbnum 0 & \bbnum 0 & \bbnum 0 & \text{swap} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{B}\times Z & \_\times z\rightarrow z & \bbnum 0\\ @@ -2598,7 +2624,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-applic If $F^{\bullet}$ is applicative then $L^{A}\triangleq A+F^{A}$ is also applicative: \begin{align*} - & \text{zip}_{L}:(A+F^{A})\times(B+F^{B})\rightarrow A\times B+F^{A\times B}\quad,\quad\quad\text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{L}:(A+F^{A})\times(B+F^{B})\rightarrow A\times B+F^{A\times B}\quad,\\ + & \text{zip}_{L}\triangleq\,\begin{array}{|c||cc|} & A\times B & F^{A\times B}\\ \hline A\times B & \text{id} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes\text{pu}_{F})\bef\text{zip}_{F}\\ @@ -2638,9 +2665,10 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-applic method. The next statement shows that $\text{zip}_{L}$ will obey the applicative laws if a special \textbf{compatibility law}\index{compatibility law!of extract and zip@of \texttt{extract} and \texttt{zip}} holds for \lstinline!extract! and \lstinline!zip!: -\begin{equation} -\text{ex}_{H}(\text{zip}_{H}(p^{:H^{A}}\times q^{:H^{B}}))=\text{ex}_{H}(p)\times\text{ex}_{H}(q)\quad,\quad\text{or equivalently}:\quad\text{zip}_{H}\bef\text{ex}_{H}=\text{ex}_{H}\boxtimes\text{ex}_{H}\quad.\label{eq:compatibility-law-of-extract-and-zip} -\end{equation} +\begin{align} + & \text{ex}_{H}(\text{zip}_{H}(p^{:H^{A}}\times q^{:H^{B}}))=\text{ex}_{H}(p)\times\text{ex}_{H}(q)\quad,\nonumber \\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{zip}_{H}\bef\text{ex}_{H}=\text{ex}_{H}\boxtimes\text{ex}_{H}\quad.\label{eq:compatibility-law-of-extract-and-zip} +\end{align} A simple example of a co-pointed applicative functor is $H^{A}\triangleq A\times G^{A}$: @@ -2697,7 +2725,8 @@ \subsubsection{Statement \label{subsec:Statement-co-pointed-applicative-example- Let us see whether the compatibility law~(\ref{eq:compatibility-law-of-extract-and-zip}) holds: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{ex}_{F}\big(\text{zip}_{F}\big((z_{1}\times r_{1})\times(z_{2}\times r_{2})\big)\big)=\text{ex}_{F}\big((z_{1}\oplus z_{2})\times(z^{:Z}\rightarrow r_{1}(z)\times r_{2}(z))\big)\\ +{\color{greenunder}\text{left-hand side}:}\quad & \text{ex}_{F}\big(\text{zip}_{F}\big((z_{1}\times r_{1})\times(z_{2}\times r_{2})\big)\big)\\ + & \quad=\text{ex}_{F}\big((z_{1}\oplus z_{2})\times(z^{:Z}\rightarrow r_{1}(z)\times r_{2}(z))\big)\\ & \quad=r_{1}(z_{1}\oplus z_{2})\times r_{2}(z_{1}\oplus z_{2})\quad,\\ {\color{greenunder}\text{right-hand side}:}\quad & \text{ex}_{F}(z_{1}\times r_{1})\times\text{ex}_{F}(z_{2}\times r_{2})=r_{1}(z_{1})\times r_{2}(z_{2})\quad. \end{align*} @@ -2741,7 +2770,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl To verify the left identity law, we begin with its left-hand side: \begin{align*} - & \text{zip}_{L}(\text{wu}_{L}\times p)=\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{L}(\text{wu}_{L}\times p)\\ + & =\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{\bbnum 1}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ H^{\bbnum 1}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ @@ -2761,17 +2791,18 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl \] Since the identity laws of $F$ and $H$ are assumed to hold, we can transform the last matrix as: -\[ -\begin{array}{|c||cc|} +\begin{align*} + & \begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & h\rightarrow\text{zip}_{H}(\text{wu}_{H}\times h) & \bbnum 0\\ F^{B} & \bbnum 0 & f\rightarrow\text{zip}_{F}((\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})\times f) -\end{array}\,=\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad=\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & \text{ilu}^{\uparrow H} & \bbnum 0\\ F^{B} & \bbnum 0 & \text{ilu}^{\uparrow F} \end{array}\,=\text{ilu}^{\uparrow L}\quad. -\] +\end{align*} After this simplification, the left-hand side equals $p\triangleright\text{ilu}^{\uparrow L}$, i.e., the right-hand side of the law. @@ -2782,9 +2813,7 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & h\rightarrow\text{zip}_{H}(h\times\text{wu}_{H}) & \bbnum 0\\ F^{A} & \bbnum 0 & f\rightarrow\text{zip}_{F}(f\times(\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})) -\end{array} -\end{align*} -\begin{align*} +\end{array}\\ & =p\triangleright\,\,\begin{array}{|c||cc|} & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & \text{iru}^{\uparrow H} & \bbnum 0\\ @@ -2826,14 +2855,17 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl \end{array}\quad. \end{align*} If $q$ has type $\bbnum 0+F^{B}$ then we have: -\[ -\text{zip}_{L}(p\times q)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\quad,\quad\quad\text{zip}_{L}(q\times r)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\quad. -\] +\begin{align*} + & \text{zip}_{L}(p\times q)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\quad,\\ + & \text{zip}_{L}(q\times r)=\bbnum 0+\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\quad. +\end{align*} Now the associativity law of $\text{zip}_{L}$ is reduced to the same law of $\text{zip}_{F}$: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. +{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & \quad=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad,\\ +{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}\\ + & \quad=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. \end{align*} The two sides are equal due to the associativity law of $\text{zip}_{F}$. @@ -2842,7 +2874,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl and $q=b^{:H^{B}}+\bbnum 0$. The two situations are symmetric, so let us consider the first one: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\,(p)\times\text{toF}\,(\text{zip}_{H}(b\times c)+\bbnum 0)\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad. +{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & =\bbnum 0+\text{zip}_{F}\big(\text{toF}\,(p)\times\text{toF}\,(\text{zip}_{H}(b\times c)+\bbnum 0)\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\quad. \end{align*} Simplify the sub-expressions involving \lstinline!toF! separately: \begin{align*} @@ -2852,14 +2885,16 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl \end{align*} So, we can rewrite the left-hand side as: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}=\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\\ +{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{L}(p\times\text{zip}_{L}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow L}\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\\ {\color{greenunder}\text{identity law of }\text{zip}_{F}:}\quad & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)^{\uparrow F}\triangleright\varepsilon_{1,23}^{\uparrow F}\\ & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\quad. \end{align*} The right-hand side can be transformed by using \lstinline!toF! on all arguments: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\\ +{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{L}(\text{zip}_{L}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow L}\\ + & =\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\\ & =\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\text{toF}\left(r+\bbnum 0\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\quad. \end{align*} Simplify the sub-expressions of the form $\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))$: @@ -2909,7 +2944,8 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl The right-hand side is rewritten to the same code after using the laws of $\text{zip}_{F}$ and $\text{zip}_{H}$: \begin{align*} - & \text{zip}_{L}\bef\text{swap}^{\uparrow L}=\,\begin{array}{|c||cc|} + & \text{zip}_{L}\bef\text{swap}^{\uparrow L}\\ + & =\,\begin{array}{|c||cc|} & H^{A\times B} & F^{A\times B}\\ \hline H^{A}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ F^{A}\times H^{B} & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{zip}_{F}\\ @@ -2920,7 +2956,7 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-co-pointed-appl \hline H^{A\times B} & \text{swap}^{\uparrow H} & \bbnum 0\\ F^{A\times B} & \bbnum 0 & \text{swap}^{\uparrow F} \end{array}\\ - & =\,\begin{array}{|c||cc|} + & =\,\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline A\times B & \text{swap}\bef\text{zip}_{H} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{swap}\bef\text{zip}_{F}\\ @@ -2959,9 +2995,9 @@ \subsubsection{Statement \label{subsec:Statement-polynomial-functor-applicative} \[ L^{A}\cong Z_{0}+A\times(Z_{1}+A\times(...\times(Z_{n-1}+A\times Z_{n})...))\quad. \] -Here, the fixed types $Z_{i}$ are all monoids by assumption. Statements~\ref{subsec:Statement-applicative-product} -and~\ref{subsec:Statement-co-product-with-constant-functor-applicative} -are then sufficient to make $L$ into a lawful applicative functor. +Here, the fixed types $Z_{i}$ are all monoids by assumption. To make +$L$ into a lawful applicative functor, it remains to use Statements~\ref{subsec:Statement-applicative-product} +and~\ref{subsec:Statement-co-product-with-constant-functor-applicative}. \textbf{(b)} We can express $P^{A}$ and $Q^{A}$ equivalently as: \[ @@ -3096,13 +3132,14 @@ \subsubsection{Statement \label{subsec:Statement-applicative-recursive-type}\ref \end{align*} The \textsf{``}wrapped unit\textsf{''} is $\text{wu}_{L}\triangleq1+\bbnum 0^{:N^{\bbnum 1}}$. The liftings to $L$ and $N$ are defined by: -\[ -(f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} +\begin{align*} + & (f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} & B & N^{B}\\ \hline A & \text{id} & \bbnum 0\\ N^{A} & \bbnum 0 & f^{\uparrow N} -\end{array}\quad,\quad\quad f^{\uparrow N}=f^{\uparrow H}\times f^{\overline{\uparrow L}\uparrow F}=h^{:H^{A}}\times k^{:F^{L^{A}}}\rightarrow(h\triangleright f^{\uparrow H})\times(k\triangleright f^{\overline{\uparrow L}\uparrow F})\quad. -\] +\end{array}\quad,\\ + & f^{\uparrow N}=f^{\uparrow H}\times f^{\overline{\uparrow L}\uparrow F}=h^{:H^{A}}\times k^{:F^{L^{A}}}\rightarrow(h\triangleright f^{\uparrow H})\times(k\triangleright f^{\overline{\uparrow L}\uparrow F})\quad. +\end{align*} For brevity, we denoted by $\overline{\text{zip}_{N}}$ the following function: \[ @@ -3448,8 +3485,10 @@ \subsubsection{Definition \label{subsec:Definition-applicative-contrafunctor}\re methods \lstinline!zip! and \lstinline!wu! such that: \begin{align} & \text{zip}_{C}:C^{A}\times C^{B}\rightarrow C^{A\times B}\quad,\quad\quad\text{wu}_{C}:C^{\bbnum 1}\quad,\nonumber \\ -{\color{greenunder}\text{associativity law}:}\quad & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}\quad,\label{eq:applicative-contrafunctor-associativity-law}\\ -{\color{greenunder}\text{left and right identity laws}:}\quad & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=p\quad,\quad\quad\text{zip}_{C}(p\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=p\quad.\label{eq:applicative-contrafunctor-identity-laws} + & \quad{\color{greenunder}\text{associativity law}:}\quad\\ + & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}\quad,\label{eq:applicative-contrafunctor-associativity-law}\\ + & \quad{\color{greenunder}\text{left and right identity laws}:}\quad\\ + & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=p\quad,\quad\quad\text{zip}_{C}(p\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=p\quad.\label{eq:applicative-contrafunctor-identity-laws} \end{align} Here the tuple-rearranging isomorphisms $\tilde{\varepsilon}_{1,23}$, $\tilde{\varepsilon}_{12,3}$, \lstinline!ilu!, and \lstinline!iru! @@ -3480,9 +3519,10 @@ \subsubsection{Definition \label{subsec:Definition-applicative-contrafunctor}\re The commutativity law is formulated for applicative contrafunctors like this: -\[ -\text{zip}_{C}(q\times p)=\text{zip}_{C}(p\times q)\triangleright\text{swap}^{\downarrow C}\quad,\quad\quad\text{or equivalently}:\quad\text{swap}\bef\text{zip}_{C}=\text{zip}_{C}\bef\text{swap}^{\downarrow C}\quad. -\] +\begin{align*} + & \text{zip}_{C}(q\times p)=\text{zip}_{C}(p\times q)\triangleright\text{swap}^{\downarrow C}\quad,\\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{swap}\bef\text{zip}_{C}=\text{zip}_{C}\bef\text{swap}^{\downarrow C}\quad. +\end{align*} The rest of this section proves some constructions that produce lawful applicative contrafunctors. @@ -3514,7 +3554,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-compo To verify the left identity law in Eq.~(\ref{eq:applicative-contrafunctor-identity-laws}): \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & \text{zip}_{C}(\text{wu}_{C}\times p^{:F^{G^{A}}})\triangleright\text{ilu}^{\downarrow C}=(\gunderline{\text{pu}_{F}(\text{wu}_{G})}\times p)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & \text{zip}_{C}(\text{wu}_{C}\times p^{:F^{G^{A}}})\triangleright\text{ilu}^{\downarrow C}\\ + & =(\gunderline{\text{pu}_{F}(\text{wu}_{G})}\times p)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}\\ {\color{greenunder}\text{left identity law of }\text{zip}_{F}:}\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{\text{wu}_{G}\times g)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{ilu}^{\downarrow G\uparrow F}}\\ {\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(\text{wu}_{G}\times g)\triangleright\text{ilu}^{\downarrow G}}\big)^{\uparrow F}\\ {\color{greenunder}\text{left identity law of }\text{zip}_{G}:}\quad & =p\triangleright(\gunderline{g\rightarrow g})^{\uparrow F}=p\triangleright\text{id}^{\uparrow F}=p\quad. @@ -3522,27 +3563,32 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-compo To verify the right identity law: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & \text{zip}_{C}(p^{:F^{G^{A}}}\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}=(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & \text{zip}_{C}(p^{:F^{G^{A}}}\times\text{wu}_{C})\triangleright\text{iru}^{\downarrow C}\\ + & =(p\times\gunderline{\text{pu}_{F}(\text{wu}_{G})})\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}\\ {\color{greenunder}\text{right identity law of }\text{zip}_{F}:}\quad & =p\triangleright(g^{:G^{A}}\rightarrow\gunderline{g\times\text{wu}_{G})^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\text{iru}^{\downarrow G\uparrow F}}\\ {\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =p\triangleright\big(g^{:G^{A}}\rightarrow\gunderline{\text{zip}_{G}(g\times\text{wu}_{G})\triangleright\text{iru}^{\downarrow G}}\big)^{\uparrow F}\\ {\color{greenunder}\text{right identity law of }\text{zip}_{G}:}\quad & =p\triangleright(\gunderline{g\rightarrow g})^{\uparrow F}=p\triangleright\text{id}^{\uparrow F}=p\quad. \end{align*} To verify the associativity law, first substitute the definition of -$\text{zip}_{C}$ into one side: +$\text{zip}_{C}$ into the left-hand side: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{C}\big(p\times\text{zip}_{C}(q\times r)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\big(p\times\gunderline{\text{zip}_{C}(q\times r)}\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow C}\\ + & \text{zip}_{C}\big(p\times\text{zip}_{C}(q\times r)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow C}=\big(p\times\gunderline{\text{zip}_{C}(q\times r)}\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow C}\\ & =\big(p\times\big(\text{zip}_{F}(q\times r)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}\\ -{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}}\\ -{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\big)^{\uparrow F}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad\\ + & =\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\text{zip}_{F}\bef\big(g\times k^{:G^{B}\times G^{C}}\!\rightarrow\gunderline{g\times\text{zip}_{G}(k)\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{1,23}^{\downarrow G\uparrow F}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad\\ + & =\text{zip}_{F}\big(p\times\text{zip}_{F}(q\times r)\big)\triangleright\big(g\times(h\times j)\rightarrow\text{zip}_{G}(g\times\text{zip}_{G}(h\times j))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\big)^{\uparrow F}\quad. \end{align*} Rewrite the right-hand side of the associativity law in a similar way: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{C}\big(\text{zip}_{C}(p\times q)\times r\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}=\big(\gunderline{\text{zip}_{C}(p\times q)}\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow C}\\ + & \text{zip}_{C}\big(\text{zip}_{C}(p\times q)\times r\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow C}=\big(\gunderline{\text{zip}_{C}(p\times q)}\times r\big)\triangleright\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow C}\\ & =\big(\big(\text{zip}_{F}(p\times q)\triangleright\gunderline{\text{zip}_{G}^{\uparrow F}}\big)\times r\big)\triangleright\gunderline{\text{zip}_{F}}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}\\ -{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}}\\ -{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\big)^{\uparrow F}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad\\ + & =\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\text{zip}_{F}\bef\big(k^{:G^{A}\times G^{B}}\!\times j\rightarrow\gunderline{\text{zip}_{G}(k)\times j\big)^{\uparrow F}\bef\text{zip}_{G}^{\uparrow F}\bef\tilde{\varepsilon}_{12,3}^{\downarrow G\uparrow F}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow F}:}\quad\\ + & =\text{zip}_{F}\big(\text{zip}_{F}(p\times q)\times r\big)\triangleright\big((g\times h)\times j\rightarrow\text{zip}_{G}(\text{zip}_{G}(g\times h)\times j)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\big)^{\uparrow F}\quad. \end{align*} The two sides become equal after using the associativity laws of $\text{zip}_{F}$ and $\text{zip}_{G}$: @@ -3562,7 +3608,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-compo \paragraph{Products} -This construction for applicative contrafunctors is similar to Statement~\ref{subsec:Statement-applicative-contrafunctor-product}: +This construction for applicative contrafunctors is similar to that +shown in Statement~\ref{subsec:Statement-applicative-contrafunctor-product}: \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-product}\ref{subsec:Statement-applicative-contrafunctor-product}} @@ -3647,7 +3694,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr With this choice, we can now verify the left identity law: \begin{align*} - & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}=\big((\bbnum 0^{:F^{\bbnum 1}}+\text{wu}_{G})\times p\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(\text{wu}_{C}\times p)\triangleright\text{ilu}^{\downarrow C}\\ + & =\big((\bbnum 0^{:F^{\bbnum 1}}+\text{wu}_{G})\times p\big)\triangleright\,\begin{array}{|c||cc|} & F^{\bbnum 1\times B} & G^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times F^{B} & \text{zip}_{F} & \bbnum 0\\ F^{\bbnum 1}\times G^{B} & p\times\_^{:G^{B}}\rightarrow p\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ @@ -3662,7 +3710,9 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr & F^{B} & G^{B}\\ \hline F^{\bbnum 1\times B} & \text{ilu}^{\downarrow F} & \bbnum 0\\ G^{\bbnum 1\times B} & \bbnum 0 & \text{ilu}^{\downarrow G} -\end{array}\\ +\end{array} +\end{align*} +\begin{align*} & =p\triangleright\,\,\begin{array}{|c||cc|} & F^{B} & G^{B}\\ \hline F^{B} & \gunderline{\pi_{2}^{\downarrow F}\bef\text{ilu}^{\downarrow F}} & \bbnum 0\\ @@ -3671,7 +3721,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr & F^{B} & G^{B}\\ \hline F^{B} & \text{id} & \bbnum 0\\ G^{B} & \bbnum 0 & g\rightarrow g -\end{array}\,=p\triangleright\text{id}=p\quad. +\end{array}\\ + & =p\triangleright\text{id}=p\quad. \end{align*} The right identity law is verified in a similar way: @@ -3723,7 +3774,10 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr To verify the associativity law in the remaining cases, write $p\times\text{zip}_{C}(q\times r)$ separately: \begin{align*} - & p\times\text{zip}_{C}(q\times r)=(q\times r)\triangleright\,\begin{array}{|c||cc|} + & p\times\text{zip}_{C}(q\times r) +\end{align*} +\begin{align*} + & =(q\times r)\triangleright\,\begin{array}{|c||cc|} & C^{A}\times F^{B\times C} & C^{A}\times G^{B\times C}\\ \hline F^{B}\times F^{C} & g\times h\rightarrow p\times\text{zip}_{F}(g\times h) & \bbnum 0\\ F^{B}\times G^{C} & f\times\_\rightarrow p\times(f\triangleright\pi_{1}^{\downarrow F}) & \bbnum 0\\ @@ -3734,7 +3788,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr We can now compute $\text{zip}_{C}(p\times\text{zip}_{C}(q\times r))$, which always returns values of type $F^{\bullet}+\bbnum 0$: \begin{align*} - & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))=(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(p\times\text{zip}_{C}(q\times r))\\ + & =(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} & F^{A\times(B\times C)} & G^{A\times(B\times C)}\\ \hline F^{A}\times F^{B}\times G^{C} & f\times g\times\_\rightarrow\text{zip}_{F}(f\times(g\triangleright\pi_{1}^{\downarrow F})) & \bbnum 0\\ F^{A}\times G^{B}\times F^{C} & f\times\_\times h\rightarrow\text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F})) & \bbnum 0\\ @@ -3747,7 +3802,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr The expression $\text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)$ in the right-hand side of the associativity law is written as: \begin{align*} - & \text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)=(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{C}(\text{zip}_{C}(p\times q)\times r)\\ + & =(p\times q\times r)\triangleright\,\begin{array}{|c||cc|} & F^{(A\times B)\times C} & G^{(A\times B)\times C}\\ \hline F^{A}\times F^{B}\times G^{C} & f\times g\times\_\rightarrow\text{zip}_{F}(f\times g)\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ F^{A}\times G^{B}\times F^{C} & f\times\_\times h\rightarrow\text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h) & \bbnum 0\\ @@ -3765,9 +3821,11 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr and to apply the tuple-rearranging isomorphisms. For instance, in the row for $F^{A}\times G^{B}\times F^{C}$ we get: \begin{align*} - & \text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F}))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow F}=\text{zip}_{F}(f\times h)\triangleright(a\times(b\times c)\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow a\times(b\times c))^{\downarrow F}\\ + & \text{zip}_{F}(f\times(h\triangleright\pi_{2}^{\downarrow F}))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ + & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times(b\times c)\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow a\times(b\times c))^{\downarrow F}\\ & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times b\times c\rightarrow a\times c)^{\downarrow F}\quad.\\ - & \text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow F}=\text{zip}_{F}(f\times h)\triangleright((a\times b)\times c\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow(a\times b)\times c)^{\downarrow F}\\ + & \text{zip}_{F}((f\triangleright\pi_{1}^{\downarrow F})\times h)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad=\text{zip}_{F}(f\times h)\triangleright((a\times b)\times c\rightarrow a\times c)^{\downarrow F}\bef(a\times b\times c\rightarrow(a\times b)\times c)^{\downarrow F}\\ & \quad=\text{zip}_{F}(f\times h)\triangleright(a\times b\times c\rightarrow a\times c)^{\downarrow F}\quad. \end{align*} In a similar way, we can show that the two sides are equal for all @@ -3783,7 +3841,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr G^{A}\times F^{B} & \_^{:G^{A}}\times q^{:F^{B}}\rightarrow q\triangleright\pi_{1}^{\downarrow F} & \bbnum 0\\ G^{A}\times G^{B} & \bbnum 0 & \text{swap}\bef\text{zip}_{G} \end{array}\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{C}\bef\text{swap}^{\downarrow C}=\,\begin{array}{|c||cc|} +{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{C}\bef\text{swap}^{\downarrow C}\\ + & =\,\begin{array}{|c||cc|} & F^{B\times A} & G^{B\times A}\\ \hline F^{A}\times F^{B} & \text{zip}_{F}\bef\text{swap}^{\downarrow F} & \bbnum 0\\ F^{A}\times G^{B} & p^{:F^{A}}\times\_^{:G^{B}}\rightarrow p\triangleright\pi_{1}^{\downarrow F}\bef\text{swap}^{\downarrow F} & \bbnum 0\\ @@ -3792,7 +3851,7 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-co-pr \end{array}\quad. \end{align*} The two sides are equal due to the commutativity laws of $\text{zip}_{F}$ -and $\text{zip}_{G}$, and due to the properties +and $\text{zip}_{G}$, and due to the properties: \[ \text{swap}\bef\pi_{1}=(a\times b\rightarrow b\times a)\bef(c\times d\rightarrow c)=a\times b\rightarrow b=\pi_{2}\quad,\quad\quad\text{swap}\bef\pi_{2}=\pi_{1}\quad. \] @@ -3840,22 +3899,26 @@ \subsubsection{Statement \label{subsec:Statement-applicative-contrafunctor-expon We use the properties such as $\text{ilu}\bef\pi_{2}=\text{id}$ and compute: \begin{align*} - & h\triangleright\text{ilu}^{\uparrow H}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p)\triangleright\text{ilu}^{\downarrow G}=\text{zip}_{G}\big(\text{wu}_{P}(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times p(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H})\big)\triangleright\text{ilu}^{\downarrow G}\\ + & h\triangleright\text{ilu}^{\uparrow H}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p)\triangleright\text{ilu}^{\downarrow G}\\ + & =\text{zip}_{G}\big(\text{wu}_{P}(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times p(h\triangleright\text{ilu}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H})\big)\triangleright\text{ilu}^{\downarrow G}\\ & =\text{zip}_{G}(\text{wu}_{G}\times p(h))\triangleright\text{ilu}^{\downarrow G}=p(h)\quad. \end{align*} The right identity law is verified by a similar calculation: \begin{align*} - & h\triangleright\text{iru}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{wu}_{P})\triangleright\text{iru}^{\downarrow G}=\text{zip}_{G}(p(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H}))\triangleright\text{iru}^{\downarrow G}\\ + & h\triangleright\text{iru}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{wu}_{P})\triangleright\text{iru}^{\downarrow G}\\ + & =\text{zip}_{G}(p(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\text{iru}^{\uparrow H}\triangleright\pi_{2}^{\uparrow H}))\triangleright\text{iru}^{\downarrow G}\\ & =\text{zip}_{G}(p(h)\times\text{wu}_{G})\triangleright\text{iru}^{\downarrow G}=p(h)\quad. \end{align*} To verify the associativity law, we use properties such as $\varepsilon_{12,3}\bef\pi_{2}=\pi_{3}$ and so on: \begin{align*} - & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ + & \quad=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{zip}_{G}\big(q(h\triangleright\pi_{2}^{\uparrow H})\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\big)\triangleright\tilde{\varepsilon}_{1,23}^{\downarrow G}\quad,\\ - & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times r(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & \quad=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times r(h\triangleright\gunderline{\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H}})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times q(h\triangleright\pi_{2}^{\uparrow H})\big)\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\triangleright\tilde{\varepsilon}_{12,3}^{\downarrow G}\quad. \end{align*} The two sides are now equal due to the assumed associativity law of @@ -3900,7 +3963,7 @@ \subsection{Applicative profunctors: Laws and constructions} is a \textsf{``}GADT\index{GADT}\textsf{''}: \begin{lstlisting} -sealed trait U[A] // Unfunctor. +sealed trait U[A] // The type constructor U is a GADT. final case class U1(s: Double) extends U[Unit] final case class U2(b: String) extends U[Int] final case class U3(b: String) extends U[Long] @@ -3988,7 +4051,7 @@ \subsubsection{Example \label{subsec:Example-profunctor-pure-not-equivalent}\ref \[ A\rightarrow P^{A}=A\rightarrow\left(A\rightarrow A\right)\rightarrow A\cong\left(A\rightarrow A\right)\rightarrow A\rightarrow A\quad. \] -Examples of functions of this type are +Examples of functions of this type are: \[ f_{1}\triangleq k^{:A\rightarrow A}\rightarrow k\quad,\quad\quad f_{2}\triangleq k^{:A\rightarrow A}\rightarrow(k\bef k)\quad, \] @@ -4041,18 +4104,22 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-product} To verify the left identity law of $\text{zip}_{P}$: \begin{align*} -{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}:}\quad & \text{zip}_{P}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)=\gunderline{\text{zip}_{P}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ +{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}:}\quad & \text{zip}_{P}\big(\gunderline{\text{wu}_{L}}\times(p^{:F^{A}}\times q^{:G^{A}})\big)\\ + & =\gunderline{\text{zip}_{P}}((\text{wu}_{F}\times\text{wu}_{G})\times(p\times q))\\ {\color{greenunder}\text{definition of }\text{zip}_{P}:}\quad & =\text{zip}_{F}(\text{wu}_{F}\times p)\times\text{zip}_{G}(\text{wu}_{G}\times q)\\ {\color{greenunder}\text{left identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad & =(p\triangleright\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\times(q\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\\ -{\color{greenunder}\text{definition of }\boxtimes:}\quad & =(p\times q)\triangleright\big((\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\boxtimes(\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\big)=(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +{\color{greenunder}\text{definition of }\boxtimes:}\quad & =(p\times q)\triangleright\big((\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F})\boxtimes(\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G})\big)\\ + & =(p\times q)\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} To verify the right identity law of $\text{zip}_{P}$: \begin{align*} -{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}:}\quad & \text{zip}_{P}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)=\gunderline{\text{zip}_{P}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ +{\color{greenunder}\text{expect to equal }(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}:}\quad & \text{zip}_{P}\big((p^{:F^{A}}\times q^{:G^{A}})\times\gunderline{\text{wu}_{L}}\big)\\ + & =\gunderline{\text{zip}_{P}}((p\times q)\times(\text{wu}_{F}\times\text{wu}_{G}))\\ {\color{greenunder}\text{definition of }\text{zip}_{P}:}\quad & =\text{zip}_{F}(p\times\text{wu}_{F})\times\text{zip}_{G}(q\times\text{wu}_{G})\\ {\color{greenunder}\text{right identity laws of }\text{zip}_{F}\text{ and }\text{zip}_{G}:}\quad & =(p\triangleright\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\times(q\triangleright\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\\ -{\color{greenunder}\text{definition of }\boxtimes:}\quad & =(p\times q)\triangleright\big((\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\boxtimes(\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\big)=(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. +{\color{greenunder}\text{definition of }\boxtimes:}\quad & =(p\times q)\triangleright\big((\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F})\boxtimes(\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G})\big)\\ + & =(p\times q)\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. \end{align*} To verify the associativity law, begin with its left-hand side and @@ -4074,10 +4141,14 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-product} To verify the commutativity law of $P$ assuming it holds for $F$ and $G$: \begin{align*} -{\color{greenunder}\text{expect }\text{zip}_{P}\big((p\times q)\times(m\times n)\big):}\quad & \text{zip}_{P}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ -{\color{greenunder}\text{definitions of }\text{zip}_{P}\text{ and }^{\uparrow P}:}\quad & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright\big((\text{swap}^{\uparrow F}\text{swap}^{\downarrow F})\boxtimes(\text{swap}^{\uparrow G}\text{swap}^{\downarrow G})\big)\\ -{\color{greenunder}\text{definition of }\boxtimes:}\quad & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\text{swap}^{\downarrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}\big)\\ -{\color{greenunder}\text{commutativity of }F\text{ and }G:}\quad & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{P}\big((p\times q)\times(m\times n)\big)\quad. + & \quad{\color{greenunder}\text{expect to equal }\text{zip}_{P}\big((p\times q)\times(m\times n)\big):}\quad\\ + & \text{zip}_{P}\big((m\times n)\times(p\times q)\big)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ + & \quad{\color{greenunder}\text{definitions of }\text{zip}_{P}\text{ and }^{\uparrow P}:}\quad\\ + & =\big(\text{zip}_{F}(m\times p)\times\text{zip}_{G}(n\times q)\big)\triangleright\big((\text{swap}^{\uparrow F}\text{swap}^{\downarrow F})\boxtimes(\text{swap}^{\uparrow G}\text{swap}^{\downarrow G})\big)\\ + & \quad{\color{greenunder}\text{definition of }\boxtimes:}\quad\\ + & =\big(\text{zip}_{F}(m\times p)\triangleright\text{swap}^{\uparrow F}\text{swap}^{\downarrow F}\big)\times\big(\text{zip}_{G}(n\times q)\triangleright\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}\big)\\ + & \quad{\color{greenunder}\text{commutativity of }F\text{ and }G:}\quad\\ + & =\text{zip}_{F}(p\times m)\times\text{zip}_{G}(q\times n)=\text{zip}_{P}\big((p\times q)\times(m\times n)\big)\quad. \end{align*} $\square$ @@ -4087,7 +4158,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ monoid type then the profunctor $P^{A}\triangleq Z+F^{A}$ is also applicative: \begin{align*} - & \text{zip}_{P}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\quad\quad\text{zip}_{P}\triangleq\,\begin{array}{|c||cc|} + & \text{zip}_{P}:(Z+F^{A})\times(Z+F^{B})\rightarrow Z+F^{A\times B}\quad,\\ + & \text{zip}_{P}\triangleq\,\begin{array}{|c||cc|} & Z & F^{A\times B}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{A}\times Z & \_^{:F^{A}}\times z\rightarrow z & \bbnum 0\\ @@ -4115,7 +4187,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ To verify the left identity law, we use the left identity law of $\text{zip}_{F}$: \begin{align*} - & \text{zip}_{P}(\text{wu}_{P}\times p^{:Z+F^{B}})=\text{zip}_{P}((\bbnum 0+\text{wu}_{F})\times p)=(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(\text{wu}_{P}\times p^{:Z+F^{B}})=\text{zip}_{P}((\bbnum 0+\text{wu}_{F})\times p)\\ + & =(\text{wu}_{F}\times p)\triangleright\,\begin{array}{|c||cc|} & Z & F^{\bbnum 1\times B}\\ \hline F^{\bbnum 1}\times Z & \_^{:F^{\bbnum 1}}\times z\rightarrow z & \bbnum 0\\ F^{\bbnum 1}\times F^{B} & \bbnum 0 & \text{zip}_{F} @@ -4128,16 +4201,20 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ & Z & F^{\bbnum 1\times B}\\ \hline Z & \text{id} & \bbnum 0\\ F^{B} & \bbnum 0 & k\rightarrow k\triangleright\text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F} -\end{array}\,=p\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +\end{array}\\ + & =p\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} To verify the right identity law, we write a similar calculation: \begin{align*} - & \text{zip}_{P}(p^{:Z+F^{A}}\times\text{wu}_{P})=\text{zip}_{P}(p\times(\bbnum 0+\text{wu}_{F}))=(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(p^{:Z+F^{A}}\times\text{wu}_{P})=\text{zip}_{P}(p\times(\bbnum 0+\text{wu}_{F}))\\ + & =(p\times\text{wu}_{F})\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z\times F^{\bbnum 1} & z\times\_^{:F^{\bbnum 1}}\rightarrow z & \bbnum 0\\ F^{A}\times F^{\bbnum 1} & \bbnum 0 & \text{zip}_{F} -\end{array}\\ +\end{array} +\end{align*} +\begin{align*} & =p\triangleright\,\begin{array}{|c||cc|} & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ @@ -4146,7 +4223,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ & Z & F^{A\times\bbnum 1}\\ \hline Z & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & k\rightarrow k\triangleright\text{iru}^{\uparrow F}\pi_{1}^{\downarrow F} -\end{array}\,=p\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. +\end{array}\\ + & =p\triangleright\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P}\quad. \end{align*} To verify the associativity law, we use a trick to avoid long derivations. @@ -4192,14 +4270,16 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ F^{A}\times Z & \bbnum 0 & \bbnum 0 & \text{swap} & \bbnum 0\\ Z\times F^{B} & \bbnum 0 & \text{swap} & \bbnum 0 & \bbnum 0\\ F^{A}\times F^{B} & \bbnum 0 & \bbnum 0 & \bbnum 0 & \text{swap} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array} +\end{align*} +\begin{align*} + & \bef\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{1}\oplus z_{2} & \bbnum 0\\ F^{B}\times Z & \_\times z\rightarrow z & \bbnum 0\\ Z\times F^{A} & z\times\_\rightarrow z & \bbnum 0\\ F^{B}\times F^{A} & \bbnum 0 & \text{zip}_{F} -\end{array}\\ - & =\,\begin{array}{|c||cc|} +\end{array}\,=\,\begin{array}{|c||cc|} & Z & F^{B\times A}\\ \hline Z\times Z & z_{1}\times z_{2}\rightarrow z_{2}\oplus z_{1} & \bbnum 0\\ F^{A}\times Z & \_\times z\rightarrow z & \bbnum 0\\ @@ -4265,7 +4345,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ To verify the left identity law, we begin with its left-hand side: \begin{align*} - & \text{zip}_{P}(\text{wu}_{P}\times p)=\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} + & \text{zip}_{P}(\text{wu}_{P}\times p)\\ + & =\big((\text{wu}_{H}^{:H^{\bbnum 1}}+\bbnum 0^{:F^{\bbnum 1}})\times p^{:H^{B}+F^{B}}\big)\triangleright\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{\bbnum 1}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ H^{\bbnum 1}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ @@ -4290,12 +4371,12 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & h\rightarrow\text{zip}_{H}(\text{wu}_{H}\times h) & \bbnum 0\\ F^{B} & \bbnum 0 & f\rightarrow\text{zip}_{F}((\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})\times f) -\end{array}\,=\,\begin{array}{|c||cc|} +\end{array}\\ + & =\,\begin{array}{|c||cc|} & H^{\bbnum 1\times B} & F^{\bbnum 1\times B}\\ \hline H^{B} & \text{ilu}^{\uparrow H}\pi_{2}^{\downarrow H} & \bbnum 0\\ F^{B} & \bbnum 0 & \text{ilu}^{\uparrow F}\pi_{2}^{\downarrow F} -\end{array}\\ - & =\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. +\end{array}\,=\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}\quad. \end{align*} After this simplification, the left-hand side equals $p\triangleright\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P}$ (the right-hand side of the law). @@ -4307,9 +4388,7 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & h\rightarrow\text{zip}_{H}(h\times\text{wu}_{H}) & \bbnum 0\\ F^{A} & \bbnum 0 & f\rightarrow\text{zip}_{F}(f\times(\text{wu}_{H}\triangleright\text{ex}_{H}\triangleright\text{pu}_{F})) -\end{array} -\end{align*} -\begin{align*} +\end{array}\\ & =p\triangleright\,\,\begin{array}{|c||cc|} & H^{A\times\bbnum 1} & F^{A\times\bbnum 1}\\ \hline H^{A} & \text{iru}^{\uparrow H}\pi_{1}^{\downarrow H} & \bbnum 0\\ @@ -4318,9 +4397,10 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ \end{align*} The associativity law is an equation between values of type $H^{A\times B\times C}+F^{A\times B\times C}$: -\[ -\text{zip}_{P}(p^{:H^{A}+F^{A}}\times\text{zip}_{P}(q^{:H^{B}+F^{B}}\times r^{:H^{C}+F^{C}}))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\quad. -\] +\begin{align*} + & \text{zip}_{P}(p^{:H^{A}+F^{A}}\times\text{zip}_{P}(q^{:H^{B}+F^{B}}\times r^{:H^{C}+F^{C}}))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\quad. +\end{align*} The operation $\text{zip}_{P}(p\times q)$ is defined in such a way that it returns a value of type $H^{A\times B}+\bbnum 0$ only when both $p$ and $q$ are in the left part of the disjunction: @@ -4334,8 +4414,10 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ $r=c^{:H^{C}}+\bbnum 0$. In this case, $\text{zip}_{P}$ reduces to $\text{zip}_{H}$: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\text{zip}_{H}\big(a\times\text{zip}_{H}(b\times c)\big)\triangleright\varepsilon_{1,23}^{\uparrow H}\tilde{\varepsilon}_{1,23}^{\downarrow H}+\bbnum 0\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}=\text{zip}_{H}\big(\text{zip}_{H}(a\times b)\times c\big)\triangleright\varepsilon_{12,3}^{\uparrow H}\tilde{\varepsilon}_{12,3}^{\downarrow H}+\bbnum 0\quad. +{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\text{zip}_{H}\big(a\times\text{zip}_{H}(b\times c)\big)\triangleright\varepsilon_{1,23}^{\uparrow H}\tilde{\varepsilon}_{1,23}^{\downarrow H}+\bbnum 0\quad,\\ +{\color{greenunder}\text{right-hand side}:}\quad & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\\ + & \quad=\text{zip}_{H}\big(\text{zip}_{H}(a\times b)\times c\big)\triangleright\varepsilon_{12,3}^{\uparrow H}\tilde{\varepsilon}_{12,3}^{\downarrow H}+\bbnum 0\quad. \end{align*} The two sides are equal due to the associativity law of $\text{zip}_{H}$. @@ -4347,8 +4429,10 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ The associativity law of $\text{zip}_{P}$ is then reduced to the same law of $\text{zip}_{F}$: \begin{align*} - & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\quad,\\ - & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\quad. + & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & \quad=\bbnum 0+\text{zip}_{F}\big(\text{toF}\left(p\right)\times\text{zip}_{F}(\text{toF}\left(q\right)\times\text{toF}\left(r\right))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\quad,\\ + & \text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow P}\tilde{\varepsilon}_{12,3}^{\downarrow P}\\ + & \quad=\bbnum 0+\text{zip}_{F}(\text{zip}_{F}(\text{toF}\left(p\right)\times\text{toF}\left(q\right))\times\text{toF}\left(r\right))\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\quad. \end{align*} The two sides are equal due to the associativity law of $\text{zip}_{F}$. @@ -4374,7 +4458,8 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ So, we can rewrite the left-hand side of the associativity law like this: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}=\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ +{\color{greenunder}\text{left-hand side}:}\quad & \text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}\big(a\times\gunderline{\text{pu}_{F}}(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ {\color{greenunder}\text{identity law of }\text{zip}_{F}:}\quad & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times(\text{ex}_{H}(b)\times\text{ex}_{H}(c))\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{1,23}^{\uparrow F}\tilde{\varepsilon}_{1,23}^{\downarrow F}\\ & =\bbnum 0+a\triangleright\big(k^{:A}\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. \end{align*} @@ -4391,10 +4476,13 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ \end{equation} Using this formula, we continue to transform the right-hand side: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & \bbnum 0+\gunderline{\text{zip}_{F}}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\gunderline{\text{toF}\left(c+\bbnum 0\right)})\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -{\color{greenunder}\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:}\quad & =\bbnum 0+\gunderline{\text{zip}_{F}}(a\times\gunderline{\text{toF}\left(b+\bbnum 0\right)})\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -{\color{greenunder}\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:}\quad & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ -{\color{greenunder}\text{compute composition}:}\quad & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. + & \bbnum 0+\gunderline{\text{zip}_{F}}(\text{zip}_{F}(a\times\text{toF}\left(b+\bbnum 0\right))\times\gunderline{\text{toF}\left(c+\bbnum 0\right)})\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad{\color{greenunder}\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:}\quad\\ + & =\bbnum 0+\gunderline{\text{zip}_{F}}(a\times\gunderline{\text{toF}\left(b+\bbnum 0\right)})\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad{\color{greenunder}\text{use Eq.~(\ref{eq:zip-copointed-construction-derivation1-1})}:}\quad\\ + & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\big(k\rightarrow k\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\triangleright\varepsilon_{12,3}^{\uparrow F}\tilde{\varepsilon}_{12,3}^{\downarrow F}\\ + & \quad{\color{greenunder}\text{compute composition}:}\quad\\ + & =\bbnum 0+a\triangleright\big(k\rightarrow k\times\text{ex}_{H}(b)\times\text{ex}_{H}(c)\big)^{\uparrow F}\pi_{1}^{\downarrow F}\quad. \end{align*} The two sides are now equal. @@ -4432,19 +4520,19 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-co-produ The right-hand side is rewritten to the same code after using the laws of $\text{zip}_{F}$ and $\text{zip}_{H}$: \begin{align*} - & \text{zip}_{P}\bef\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ - & =\,\begin{array}{|c||cc|} +\text{zip}_{P}\bef\text{swap}^{\uparrow P}\text{swap}^{\downarrow P} & =\,\begin{array}{|c||cc|} & H^{A\times B} & F^{A\times B}\\ \hline H^{A}\times H^{B} & \text{zip}_{H} & \bbnum 0\\ F^{A}\times H^{B} & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{zip}_{F}\\ H^{A}\times F^{B} & \bbnum 0 & ((\text{ex}_{H}\bef\text{pu}_{F})\boxtimes\text{id})\bef\text{zip}_{F}\\ F^{A}\times F^{B} & \bbnum 0 & \text{zip}_{F} -\end{array}\,\bef\,\begin{array}{|c||cc|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline H^{A\times B} & \text{swap}^{\uparrow H}\text{swap}^{\downarrow H} & \bbnum 0\\ F^{A\times B} & \bbnum 0 & \text{swap}^{\uparrow F}\text{swap}^{\downarrow F} \end{array}\\ - & =\,\,\begin{array}{|c||cc|} + & =\,\begin{array}{|c||cc|} & H^{B\times A} & F^{B\times A}\\ \hline A\times B & \text{swap}\bef\text{zip}_{H} & \bbnum 0\\ F^{A}\times B & \bbnum 0 & (\text{id}\boxtimes(\text{ex}_{H}\bef\text{pu}_{F}))\bef\text{swap}\bef\text{zip}_{F}\\ @@ -4483,34 +4571,40 @@ \subsubsection{Statement \label{subsec:Statement-applicative-profunctor-exponent To verify the left identity law of $P$, we use the left identity law of $G$: \begin{align*} - & h^{:H^{\bbnum 1\times A}}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p^{:H^{A}\rightarrow G^{A}})=\text{zip}_{G}\big(\gunderline{\text{wu}_{P}(h\triangleright\pi_{1}^{\uparrow H})}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ -{\color{greenunder}\text{definition of }\text{wu}_{P}:}\quad & =\text{zip}_{G}\big(\text{wu}_{G}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ -{\color{greenunder}\text{left identity law of }G:}\quad & =p(h\triangleright\pi_{2}^{\uparrow H})\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}=h\triangleright\gunderline{\pi_{2}^{\uparrow H}\bef p\bef\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}}=h\triangleright(p\bef\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P})\quad. + & h^{:H^{\bbnum 1\times A}}\triangleright\text{zip}_{P}(\text{wu}_{P}\times p^{:H^{A}\rightarrow G^{A}})\\ + & =\text{zip}_{G}\big(\gunderline{\text{wu}_{P}(h\triangleright\pi_{1}^{\uparrow H})}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ +{\color{greenunder}\text{definition of }\text{wu}_{P}:}\quad & =\gunderline{\text{zip}_{G}\big(\text{wu}_{G}}\times p(h\triangleright\pi_{2}^{\uparrow H})\big)\\ +{\color{greenunder}\text{left identity law of }G:}\quad & =\gunderline{p(h\triangleright\pi_{2}^{\uparrow H})}\triangleright\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}\\ + & =h\triangleright\gunderline{\pi_{2}^{\uparrow H}\bef p\bef\text{ilu}^{\uparrow G}\pi_{2}^{\downarrow G}}=h\triangleright(p\bef\text{ilu}^{\uparrow P}\pi_{2}^{\downarrow P})\quad. \end{align*} -To verify the right identity law of $P$: +To verify the right identity law of $P$, we use a similar calculation: \begin{align*} - & h^{:H^{A\times\bbnum 1}}\triangleright\text{zip}_{P}(p^{:H^{A}\rightarrow G^{A}}\times\text{wu}_{P})=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\pi_{2}^{\uparrow H})\big)=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{G}\big)\\ + & h^{:H^{A\times\bbnum 1}}\triangleright\text{zip}_{P}(p^{:H^{A}\rightarrow G^{A}}\times\text{wu}_{P})=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{P}(h\triangleright\pi_{2}^{\uparrow H})\big)\\ + & =\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{wu}_{G}\big)\\ & =p(h\triangleright\pi_{1}^{\uparrow H})\triangleright\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G}=h\triangleright\gunderline{\pi_{1}^{\uparrow H}\bef p\bef\text{iru}^{\uparrow G}\pi_{1}^{\downarrow G}}=h\triangleright(p\bef\text{iru}^{\uparrow P}\pi_{1}^{\downarrow P})\quad. \end{align*} To verify the associativity law, we use the definition of $^{\uparrow P}$: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & h^{:H^{A\times B\times C}}\triangleright\big(\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\,\gunderline{\triangleright\,\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}}\big)\\ + & \quad{\color{greenunder}\text{left-hand side}:}\quad\\ + & h^{:H^{A\times B\times C}}\triangleright\big(\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\,\gunderline{\triangleright\,\varepsilon_{1,23}^{\uparrow P}\tilde{\varepsilon}_{1,23}^{\downarrow P}}\big)\\ & \quad=h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\triangleright\text{zip}_{P}(p\times\text{zip}_{P}(q\times r))\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\gunderline{\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{1}^{\uparrow H}})\times\text{zip}_{P}(q\times r)(h\triangleright\tilde{\varepsilon}_{1,23}^{\uparrow H}\bef\pi_{2}^{\uparrow H})\big)\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times\text{zip}_{G}\big(q(h\triangleright\pi_{2}^{\uparrow H})\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\big)\triangleright\varepsilon_{1,23}^{\uparrow G}\tilde{\varepsilon}_{1,23}^{\downarrow G}\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ + & \quad{\color{greenunder}\text{right-hand side}:}\quad\\ + & h^{:H^{A\times B\times C}}\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\triangleright\text{zip}_{P}(\text{zip}_{P}(p\times q)\times r)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{P}(p\times q)(h\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{1}^{\uparrow H})\times r(h\triangleright\tilde{\varepsilon}_{12,3}^{\uparrow H}\bef\pi_{2}^{\uparrow H})\big)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\\ & \quad=\text{zip}_{G}\big(\text{zip}_{G}\big(p(h\triangleright\pi_{1}^{\uparrow H})\times q(h\triangleright\pi_{2}^{\uparrow H})\big)\times r(h\triangleright\pi_{3}^{\uparrow H})\big)\triangleright\varepsilon_{12,3}^{\uparrow G}\tilde{\varepsilon}_{12,3}^{\downarrow G}\quad. \end{align*} The two sides are now equal due to the associativity law of $\text{zip}_{G}$. It remains to verify the commutativity law, assuming that $\text{zip}_{G}$ -satisfies that law: +obeys that law: \begin{align*} & \text{zip}_{P}(q\times p)=\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(q\boxtimes p)\bef\text{zip}_{G}\quad,\\ - & \text{zip}_{P}(p\times q)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}=\text{swap}^{\uparrow H}\bef\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(p\boxtimes q)\bef\gunderline{\text{zip}_{G}\bef\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}}\\ + & \text{zip}_{P}(p\times q)\triangleright\text{swap}^{\uparrow P}\text{swap}^{\downarrow P}\\ + & \quad=\text{swap}^{\uparrow H}\bef\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(p\boxtimes q)\bef\gunderline{\text{zip}_{G}\bef\text{swap}^{\uparrow G}\text{swap}^{\downarrow G}}\\ & \quad=\Delta\bef\gunderline{(\text{swap}^{\uparrow H}\boxtimes\text{swap}^{\uparrow H})\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})}\bef\gunderline{(p\boxtimes q)\bef\text{swap}}\bef\text{zip}_{G}\\ & \quad=\gunderline{\Delta\bef(\pi_{2}^{\uparrow H}\boxtimes\pi_{1}^{\uparrow H})\bef\text{swap}}\bef(q\boxtimes p)\bef\text{zip}_{G}=\Delta\bef(\pi_{1}^{\uparrow H}\boxtimes\pi_{2}^{\uparrow H})\bef(q\boxtimes p)\bef\text{zip}_{G}\quad. \end{align*} @@ -4545,8 +4639,9 @@ \subsection{Equivalence of typeclass methods with laws} law is equivalent to a value $\text{wu}_{F}:F^{\bbnum 1}$. After seeing those detailed proofs, we can now clarify the meaning -of \textsf{``}equivalence under laws\textsf{''}. The goal of this subsection is to -find a rigorous formulation of that equivalence. +of equivalence of typeclass methods when we require some laws to hold. +The goal of this subsection is to find a rigorous formulation of that +equivalence. In each case seen so far, we have two functions with two different type signatures (usually with type parameters), and we assume that @@ -4714,9 +4809,9 @@ \subsection{Relationship between monads and applicative functors} that the \lstinline!Applicative! typeclass is larger than the \lstinline!Monad! typeclass. -\subsection{Applicative morphisms} +\subsection{Applicative morphisms\label{subsec:Applicative-morphisms}} -One of the applicative constructions (Statement~\ref{subsec:Statement-co-product-with-co-pointed-applicative}) +The construction in Statement~\ref{subsec:Statement-co-product-with-co-pointed-applicative} needs a compatibility law~(\ref{eq:compatibility-law-of-extract-and-zip}) between the methods $\text{zip}_{H}$ and $\text{ex}_{H}$. This law is understood better if we rewrite the type signature $\text{ex}_{H}^{A}:H^{A}\rightarrow A$ @@ -4732,9 +4827,10 @@ \subsection{Applicative morphisms} where $H$ and $K$ are two applicative functors, and formulating a \textbf{composition law}\index{composition law!of applicative morphisms} of $\phi$ by analogy with Eq.~(\ref{eq:compatibility-law-of-extract-and-zip}): -\[ -\phi\big(\text{zip}_{H}(p\times q)\big)=\text{zip}_{K}(\phi(p)\times\phi(q))\quad,\quad\text{or equivalently}:\quad\text{zip}_{H}\bef\phi=(\phi\boxtimes\phi)\bef\text{zip}_{K}\quad. -\] +\begin{align*} + & \phi\big(\text{zip}_{H}(p\times q)\big)=\text{zip}_{K}(\phi(p)\times\phi(q))\quad,\\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{zip}_{H}\bef\phi=(\phi\boxtimes\phi)\bef\text{zip}_{K}\quad. +\end{align*} This law reproduces Eq.~(\ref{eq:compatibility-law-of-extract-and-zip}) when $\phi=\text{ex}_{H}$ and $K=\text{Id}$ because we will then have $\text{zip}_{K}=\text{id}$. @@ -4831,14 +4927,16 @@ \subsubsection{Statement \label{subsec:Statement-ap-category-laws}\ref{subsec:St \textbf{(a)} To verify the left identity law, substitute the definition (a) of $\odot$: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p=(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p\\ + & =(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{left identity law of }\text{zip}:}\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow\text{id}\times s)^{\uparrow L}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{function composition under }^{\uparrow L}:}\quad & =p\triangleright(\gunderline{s\rightarrow\text{id}\bef s})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} To verify the right identity law: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})=(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})\\ + & =(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{right identity law of }\text{zip}:}\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow s\times\text{id})^{\uparrow L}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{function composition under }^{\uparrow L}:}\quad & =p\triangleright(\gunderline{s\rightarrow s\bef\text{id}})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} @@ -4847,17 +4945,23 @@ \subsubsection{Statement \label{subsec:Statement-ap-category-laws}\ref{subsec:St trying to bring the \lstinline!zip! functions to the left of the expression: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & (p\odot q)\odot r=\big((p\times q)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ + & \quad{\color{greenunder}\text{left-hand side}:}\quad\\ + & (p\odot q)\odot r=\big((p\times q)\triangleright\text{zip}\bef(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ & =\big(\big(\text{zip}\left(p\times q\right)\triangleright\gunderline{(f\times g\rightarrow f\bef g)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}\\ -{\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =(\text{zip}\left(p\times q\right)\times r)\triangleright\text{zip}\bef\gunderline{((f\times g)\times h\rightarrow(f\bef g)\times h)^{\uparrow L}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}}\\ -{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\left(\text{zip}\left(p\times q\right)\times r\right)\triangleright((f\times g)\times h\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}:}\quad\\ + & =(\text{zip}\left(p\times q\right)\times r)\triangleright\text{zip}\bef\gunderline{((f\times g)\times h\rightarrow(f\bef g)\times h)^{\uparrow L}\bef(k\times h\rightarrow k\bef h)^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad\\ + & =\text{zip}\left(\text{zip}\left(p\times q\right)\times r\right)\triangleright((f\times g)\times h\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} The right-hand side is rewritten similarly: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\\ + & \quad{\color{greenunder}\text{right-hand side}:}\quad\\ + & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(f\times g\rightarrow f\bef g)^{\uparrow L}\big)\\ & =\big(p\times\big(\text{zip}\left(q\times r\right)\triangleright\gunderline{(g\times h\rightarrow g\bef h)^{\uparrow L}}\big)\big)\triangleright\gunderline{\text{zip}}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}\\ -{\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =(p\times\text{zip}\left(q\times r\right))\triangleright\text{zip}\bef\gunderline{(f\times(g\times h)\rightarrow f\times(g\bef h))^{\uparrow L}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}}\\ -{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)\triangleright(f\times(g\times h)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}:}\quad\\ + & =(p\times\text{zip}\left(q\times r\right))\triangleright\text{zip}\bef\gunderline{(f\times(g\times h)\rightarrow f\times(g\bef h))^{\uparrow L}\bef(f\times k\rightarrow f\bef k)^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad\\ + & =\text{zip}\left(p\times\text{zip}\left(q\times r\right)\right)\triangleright(f\times(g\times h)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} It is clear that we need to use the associativity law of \lstinline!zip!. To be able to use that law, we express the functions $(f\times g)\times h\rightarrow f\bef g\bef h$ @@ -4880,31 +4984,37 @@ \subsubsection{Statement \label{subsec:Statement-ap-category-laws}\ref{subsec:St \textbf{(b)} To verify the left identity law, substitute the definition (b) of $\odot$: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p=(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & \text{wid}_{L}\odot p=\text{pu}_{L}(\text{id})\odot p\\ + & =(p\times\text{pu}_{L}(\text{id}))\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{right identity law of }\text{zip}:}\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow s\times\text{id})^{\uparrow L}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{function composition under }^{\uparrow L}:}\quad & =p\triangleright(\gunderline{s\rightarrow\text{id}\bef s})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} To verify the right identity law: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})=(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & p\odot\text{wid}_{L}=p\odot\text{pu}_{L}(\text{id})\\ + & =(\text{pu}_{L}(\text{id})\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{left identity law of }\text{zip}:}\quad & =p\triangleright(s^{:A\rightarrow B}\rightarrow\text{id}\times s)^{\uparrow L}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\\ {\color{greenunder}\text{function composition under }^{\uparrow L}:}\quad & =p\triangleright(\gunderline{s\rightarrow s\bef\text{id}})^{\uparrow L}=p\triangleright\text{id}^{\uparrow L}=p\quad. \end{align*} To verify the composition law, begin rewriting its left-hand side: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & (p\odot q)\odot r=\big((q\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ + & (p\odot q)\odot r=\big((q\times p)\triangleright\text{zip}\bef(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\odot r\\ & =\big(r\times\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(g\times f\rightarrow f\bef g)^{\uparrow L}}\big)\big)\triangleright\gunderline{\text{zip}}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}\\ -{\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =(r\times\text{zip}\left(q\times p\right))\triangleright\text{zip}\bef\gunderline{(h\times(g\times f)\rightarrow h\times(f\bef g))^{\uparrow L}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}}\\ -{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\left(r\times\text{zip}\left(q\times p\right)\right)\triangleright(h\times(g\times f)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}:}\quad\\ + & =(r\times\text{zip}\left(q\times p\right))\triangleright\text{zip}\bef\gunderline{(h\times(g\times f)\rightarrow h\times(f\bef g))^{\uparrow L}\bef(h\times k\rightarrow k\bef h)^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad\\ + & =\text{zip}\left(r\times\text{zip}\left(q\times p\right)\right)\triangleright(h\times(g\times f)\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} The right-hand side is rewritten similarly: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\\ + & p\odot(q\odot r)=p\odot\big(\text{zip}\left(q\times r\right)\triangleright(g\times f\rightarrow f\bef g)^{\uparrow L}\big)\\ & =\big(\big(\text{zip}\left(q\times r\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times p\big)\triangleright\gunderline{\text{zip}}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}\\ -{\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =(\text{zip}\left(q\times r\right)\times p)\triangleright\text{zip}\bef\gunderline{((h\times g)\times f\rightarrow(g\bef h)\times f)^{\uparrow L}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}}\\ -{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\left(\text{zip}\left(q\times r\right)\times p\right)\triangleright((h\times g)\times f\rightarrow f\bef g\bef h)^{\uparrow L}\quad. + & \quad{\color{greenunder}\text{naturality law of }\text{zip}:}\quad\\ + & =(\text{zip}\left(q\times r\right)\times p)\triangleright\text{zip}\bef\gunderline{((h\times g)\times f\rightarrow(g\bef h)\times f)^{\uparrow L}\bef(k\times f\rightarrow f\bef k)^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad\\ + & =\text{zip}\left(\text{zip}\left(q\times r\right)\times p\right)\triangleright((h\times g)\times f\rightarrow f\bef g\bef h)^{\uparrow L}\quad. \end{align*} To apply the associativity law of \lstinline!zip!, we use the conversion functions $\varepsilon_{1,23}$ and $\varepsilon_{12,3}$ and write: @@ -4922,36 +5032,39 @@ \subsubsection{Statement \label{subsec:Statement-ap-category-laws}\ref{subsec:St of \lstinline!zip!. $\square$ The laws of the composition operation ($\odot$) show that values -of type $L^{A\rightarrow B}$ are indeed morphisms. Let us call \textsf{``}$L$-applicative\textsf{''} -the category with those morphisms. We may now write the laws of a -(categorical) functor between the $L$-applicative and the $L$-lifted -categories. Such a functor consists of two mappings: a mapping between -objects: each type $A$ is mapped to the type $L^{A}$; and a mapping -between morphisms: each $L$-applicative morphism $f:L^{A\rightarrow B}$ -is mapped to the morphism $\text{ap}\left(f\right):L^{A}\rightarrow L^{B}$ +of type $L^{A\rightarrow B}$ are indeed morphisms. Let us call \textsf{``}$L$-ap\textsf{''} +the category with those morphisms, which we will call $L$-ap morphisms.\footnote{They are quite different from \emph{applicative morphisms} defined +in Section~\ref{subsec:Applicative-morphisms}. Applicative morphisms +have type $L^{A}\rightarrow M^{A}$, while $L$-ap morphisms have +type $L^{A\rightarrow B}$.} We may now write the laws of a (categorical) functor between the +$L$-ap and the $L$-lifted categories. Such a functor consists of +two mappings: a mapping between objects: each type $A$ is mapped +to the type $L^{A}$; and a mapping between morphisms: each $L$-ap +morphism $f:L^{A\rightarrow B}$ is mapped to the morphism $\text{ap}\left(f\right):L^{A}\rightarrow L^{B}$ in the $L$-lifted category. In other words, we expect the function \lstinline!ap! to play the role of the morphism mapping of that functor. -This mapping must obey the laws of identity and composition. +So, we expect that this mapping must obey the laws of identity and +composition. The identity law says that the function \lstinline!ap! must map the -identity morphism of the $L$-applicative category into the identity -morphism of the $L$-lifted category:\index{identity laws!of ap@of \texttt{ap}} +identity morphism of the $L$-ap category into the identity morphism +of the $L$-lifted category:\index{identity laws!of ap@of \texttt{ap}} \begin{align} {\color{greenunder}\text{left identity law of }\text{ap}:}\quad & \text{ap}\,(\text{pu}_{L}(\text{id}^{:A\rightarrow A}))=\text{id}^{:L^{A}\rightarrow L^{A}}\quad.\label{eq:identity-law-of-ap} \end{align} -The composition law says that the composition $p\odot q$ of any two -$L$-applicative morphisms $p^{:L^{A\rightarrow B}}$ and $q^{:L^{B\rightarrow C}}$ -must be mapped by \lstinline!ap! into the composition $\text{ap}\left(p\right)\bef\text{ap}\left(q\right)$: +The composition law says that for any two $L$-ap morphisms $p^{:L^{A\rightarrow B}}$ +and $q^{:L^{B\rightarrow C}}$, the operation $p\odot q$ must be +mapped by \lstinline!ap! into the composition $\text{ap}\left(p\right)\bef\text{ap}\left(q\right)$: \begin{align} -{\color{greenunder}\text{composition law of }\text{ap}:}\quad & \text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad.\label{eq:composition-law-of-ap} +{\color{greenunder}\text{composition law of }\text{ap}:}\quad & \text{ap}\,\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad.\label{eq:composition-law-of-ap} \end{align} In this law, the operation $\odot$ needs to be defined as in Statement~\ref{subsec:Statement-ap-category-laws}(b). Expressing that operation via \lstinline!ap!, we obtain the following formulation of the composition law of\index{composition law!of ap@of \texttt{ap}} \lstinline!ap!: \[ -\text{ap}\big(\text{ap}\big(q^{:L^{B\rightarrow C}}\triangleright(g^{:B\rightarrow C}\rightarrow f^{:A\rightarrow B}\rightarrow f\bef g)^{\uparrow L}\big)(p^{:L^{A\rightarrow B}})\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad. +\text{ap}\,\big(\text{ap}\,\big(q^{:L^{B\rightarrow C}}\triangleright(g^{:B\rightarrow C}\rightarrow f^{:A\rightarrow B}\rightarrow f\bef g)^{\uparrow L}\big)(p^{:L^{A\rightarrow B}})\big)=\text{ap}\left(p\right)\bef\text{ap}\left(q\right)\quad. \] Instead of proving this complicated law, we will prove the functor laws of \lstinline!ap!: @@ -4971,7 +5084,8 @@ \subsubsection{Statement \label{subsec:Statement-ap-functor-laws}\ref{subsec:Sta To verify the identity law~(\ref{eq:identity-law-of-ap}), apply both sides to some $p^{:L^{A}}$: \begin{align*} -{\color{greenunder}\text{expect to equal }p:}\quad & \text{ap}\,(\text{pu}_{L}(\text{id}))(p^{:L^{A}})=(\gunderline{\text{pu}_{L}(\text{id})}\times p)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}\\ +{\color{greenunder}\text{expect to equal }p:}\quad & \text{ap}\,(\text{pu}_{L}(\text{id}))(p^{:L^{A}})\\ + & =(\gunderline{\text{pu}_{L}(\text{id})}\times p)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}\\ {\color{greenunder}\text{left identity law of }\text{zip}:}\quad & =p\triangleright\gunderline{(a^{:A}\rightarrow\text{id}\times a)^{\uparrow L}\bef(f^{:A\rightarrow A}\times a^{:A}\rightarrow f(a))^{\uparrow L}}\\ {\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =p\triangleright(a^{:A}\rightarrow\text{id}\,(a))^{\uparrow L}=p\triangleright(a\rightarrow a)^{\uparrow L}=p\triangleright\text{id}=p\quad. \end{align*} @@ -4979,15 +5093,22 @@ \subsubsection{Statement \label{subsec:Statement-ap-functor-laws}\ref{subsec:Sta To verify the composition law~(\ref{eq:composition-law-of-ap}), apply both sides to an arbitrary value $r^{:L^{A}}$: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & r\triangleright\text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\,(p\odot q)(r)=((p\odot q)\times r)\triangleright\text{zip}\bef\text{eval}^{\uparrow L}\\ -{\color{greenunder}\text{definition (b) of }\odot:}\quad & =\big(\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}\\ -{\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright\text{zip}\triangleright\gunderline{((h\times g)\times a\rightarrow(g\bef h)\times a)^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ -{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright((h\times g)\times a\rightarrow a\triangleright g\bef h)^{\uparrow L}\quad. +{\color{greenunder}\quad\text{left-hand side}:}\quad & r\triangleright\text{ap}\big(p^{:L^{A\rightarrow B}}\odot q^{:L^{B\rightarrow C}}\big)=\text{ap}\,(p\odot q)(r)\\ + & =((p\odot q)\times r)\triangleright\text{zip}\bef\text{eval}^{\uparrow L} +\end{align*} +\begin{align*} + & \quad{\color{greenunder}\text{definition (b) of }\odot:}\quad\\ + & =\big(\big(\text{zip}\left(q\times p\right)\triangleright\gunderline{(h\times g\rightarrow g\bef h)^{\uparrow L}}\big)\times r\big)\triangleright\gunderline{\text{zip}}\bef\text{eval}^{\uparrow L}\\ + & \quad{\color{greenunder}\text{naturality law of }\text{zip}:}\quad\\ + & =\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright\text{zip}\triangleright\gunderline{((h\times g)\times a\rightarrow(g\bef h)\times a)^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ + & \quad{\color{greenunder}\text{composition under }^{\uparrow L}:}\quad\\ + & =\text{zip}\big(\text{zip}\left(q\times p\right)\times r\big)\triangleright((h\times g)\times a\rightarrow a\triangleright g\bef h)^{\uparrow L}\quad. \end{align*} Now rewrite the right-hand side of Eq.~(\ref{eq:composition-law-of-ap}) applied to $r$: \begin{align*} -{\color{greenunder}\text{right-hand side}:}\quad & r\triangleright\text{ap}\,(p)\bef\text{ap}\,(q)=\text{ap}\,(q)\big(\text{ap}\,(p)(r)\big)=\text{zip}\big(q\times\text{ap}\,(p)(r)\big)\triangleright\text{eval}^{\uparrow L}\\ +{\color{greenunder}\text{right-hand side}:}\quad & r\triangleright\text{ap}\,(p)\bef\text{ap}\,(q)=\text{ap}\,(q)\big(\text{ap}\,(p)(r)\big)\\ + & =\text{zip}\big(q\times\text{ap}\,(p)(r)\big)\triangleright\text{eval}^{\uparrow L}\\ & =\gunderline{\text{zip}}\big(q\times\big(\text{zip}\,(p\times r)\triangleright\gunderline{\text{eval}^{\uparrow L}}\big)\big)\triangleright\text{eval}^{\uparrow L}\\ {\color{greenunder}\text{naturality law of }\text{zip}:}\quad & =\text{zip}\big(q\times\text{zip}\left(p\times r\right)\big)\triangleright\gunderline{(h\times(g\times a)\rightarrow h\times g(a))^{\uparrow L}\bef\text{eval}^{\uparrow L}}\\ {\color{greenunder}\text{composition under }^{\uparrow L}:}\quad & =\text{zip}\big(q\times\text{zip}\left(p\times r\right)\big)\triangleright\big(h\times(g\times a)\rightarrow h(g(a))\big)^{\uparrow L}\quad. @@ -5005,10 +5126,10 @@ \subsubsection{Statement \label{subsec:Statement-ap-functor-laws}\ref{subsec:Sta does create a valid category but describes a reversed order of effects and cannot be used to write the law of \lstinline!ap! in the form of a (categorical) functor composition law. So, we will use the definition~(b) -for the category we call \textsf{``}$L$-applicative\textsf{''}. Statements~\ref{subsec:Statement-ap-category-laws}\textendash \ref{subsec:Statement-ap-functor-laws} -show that the laws of \lstinline!ap!, viewed as the laws of the $L$-applicative -category together with the laws of a functor from the $L$-applicative -to the $L$-lifted category, are a consequence of the laws of \lstinline!zip!. +for the category we call \textsf{``}$L$-ap\textsf{''}. Statements~\ref{subsec:Statement-ap-category-laws}\textendash \ref{subsec:Statement-ap-functor-laws} +show that the laws of \lstinline!ap!, viewed as the laws of the $L$-ap +category together with the laws of a functor from the $L$-ap to the +$L$-lifted category, are a consequence of the laws of \lstinline!zip!. In this way, we have used the guidance of category theory to formulate the laws of \lstinline!ap!. @@ -5098,17 +5219,16 @@ \subsection{The pattern of \textquotedblleft functorial\textquotedblright{} type Let us go through this pattern for the applicative functor typeclass studied in this chapter. Following the functorial pattern, we say that a covariant type constructor $F$ is applicative if there exists -a (categorical) functor between the $F$-applicative and $F$-lifted -categories. The morphisms of the $F$-applicative category are values -of type $F^{A\rightarrow B}$; the morphisms of the $F$-lifted category -are values of type $F^{A}\rightarrow F^{B}$. This is all we need -to start with. All other properties of applicative functors are then -derived in a systematic way. With this approach, we do not need to -memorize the complicated type signatures and laws of the methods \lstinline!map2! -and \lstinline!ap!. - -The first step is to define the $F$-applicative category\textsf{'}s morphisms. -We define identity morphisms (\lstinline!wid[A]! of type $F^{A\rightarrow A}$) +a (categorical) functor between the $F$-ap and $F$-lifted categories. +The morphisms of the $F$-ap category are values of type $F^{A\rightarrow B}$; +the morphisms of the $F$-lifted category are values of type $F^{A}\rightarrow F^{B}$. +This is all we need to start with. All other properties of applicative +functors are then derived in a systematic way. With this approach, +we do not need to memorize the complicated type signatures and laws +of the methods \lstinline!map2! and \lstinline!ap!. + +The first step is to define the $F$-ap category\textsf{'}s morphisms. We +define identity morphisms (\lstinline!wid[A]! of type $F^{A\rightarrow A}$) and the composition operation ($\odot$) that composes $F^{A\rightarrow B}$ with $F^{B\rightarrow C}$ to obtain $F^{A\rightarrow C}$. The second step is to verify that the category laws hold with those definitions; @@ -5134,18 +5254,18 @@ \subsection{The pattern of \textquotedblleft functorial\textquotedblright{} type Many typeclasses can be derived from this pattern, but some cannot. For example, applicative contrafunctors (Section~\ref{sec:Applicative-contrafunctors-and-profunctors}) and traversable functors (Chapter~\ref{chap:9-Traversable-functors-and}) -are not functorial typeclasses. Their laws must be motivated by other -considerations. +are not functorial typeclasses. Their laws must be motivated by considerations +other than referring to the functor laws. \subsection{Exercises\index{exercises}} \subsubsection{Exercise \label{subsec:Exercise-applicative-II-3}\ref{subsec:Exercise-applicative-II-3}} -Implement an applicative instance for $F^{A}=\bbnum 1+\text{Int}\times A+A\times A\times A$. +Implement an \lstinline!Applicative! instance for $F^{A}=\bbnum 1+\text{Int}\times A+A\times A\times A\times A$. \subsubsection{Exercise \label{subsec:Exercise-function-type-construction-not-applicative}\ref{subsec:Exercise-function-type-construction-not-applicative}} -Show that the following functors $F^{\bullet}$ \emph{cannot} be applicative: +Show that the following functors $F$ \emph{cannot} be applicative: \textbf{(a)} $F^{A}\triangleq(A\rightarrow P)\rightarrow Q\quad.$ @@ -5224,18 +5344,18 @@ \subsubsection{Exercise \label{subsec:Exercise-applicative-of-monoid-is-monoid}\ \subsubsection{Exercise \label{subsec:Exercise-applicative-II-1}\ref{subsec:Exercise-applicative-II-1}} -Prove the following statements (which complement Statement~\ref{subsec:Statement-applicative-composition}): +To complement Statement~\ref{subsec:Statement-applicative-composition}, +prove that: -\textbf{(a)} If $F^{\bullet}$ is an applicative functor and $G^{\bullet}$ -is an applicative contrafunctor then the contrafunctor $L^{A}\triangleq G^{F^{A}}$ +\textbf{(a)} If $F$ is an applicative functor and $G$ is an applicative +contrafunctor then the contrafunctor $L^{A}\triangleq G^{F^{A}}$ is applicative. -\textbf{(b)} If $F^{\bullet}$ and $G^{\bullet}$ are both applicative -contrafunctors then $L^{A}\triangleq F^{G^{A}}$ is an applicative -\emph{functor}. +\textbf{(b)} If $F$ and $G$ are both applicative contrafunctors +then $L^{A}\triangleq F^{G^{A}}$ is an applicative \emph{functor}. -\textbf{(c)} In both parts \textbf{(a)} and \textbf{(b)}, if $F^{\bullet}$ -and $G^{\bullet}$ are commutative then $L^{\bullet}$ is also commutative. +\textbf{(c)} In both parts \textbf{(a)} and \textbf{(b)}, if $F$ +and $G$ are commutative then $L$ is also commutative. \subsubsection{Exercise \label{subsec:Exercise-applicative-II-4-1}\ref{subsec:Exercise-applicative-II-4-1}} @@ -5247,7 +5367,7 @@ \subsubsection{Exercise \label{subsec:Exercise-applicative-II-4-1}\ref{subsec:Ex \subsubsection{Exercise \label{subsec:Exercise-applicative-II-5}\ref{subsec:Exercise-applicative-II-5}} -Explicitly prove the laws in the construction of Statement~\ref{subsec:Statement-applicative-contrafunctor-product}. +Prove the laws in the construction of Statement~\ref{subsec:Statement-applicative-contrafunctor-product}. \subsubsection{Exercise \label{subsec:Exercise-applicative-II-7}\ref{subsec:Exercise-applicative-II-7}} @@ -5262,7 +5382,7 @@ \subsubsection{Exercise \label{subsec:Exercise-applicative-profunctor-compositio \subsubsection{Exercise \label{subsec:Exercise-profunctor-example}\ref{subsec:Exercise-profunctor-example}} -The type constructor $Q^{\bullet}$ is defined by: +The type constructor $Q$ is defined by: \[ Q^{A}\triangleq\left(A\rightarrow\text{Int}\right)\times A\times\left(A\rightarrow A\right)\quad. \] diff --git a/sofp-src/sofp-curry-howard.lyx b/sofp-src/sofp-curry-howard.lyx index ee10666b8..6490ba46b 100644 --- a/sofp-src/sofp-curry-howard.lyx +++ b/sofp-src/sofp-curry-howard.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -1455,10 +1455,13 @@ following the types \begin_inset Quotes erd \end_inset -? It is remarkable that this question can be asked at all. - When working with non-functional programming languages, the notion of fully - parametric functions is usually not relevant, and implementations cannot - be derived from types. +? +\end_layout + +\begin_layout Standard +It is remarkable that this question can be asked at all. + When working with non-FP languages, the notion of fully parametric functions + is usually not relevant, and implementations cannot be derived from types. But in functional programming, fully parametric functions are used often. It is then important for the programmer to know whether a given fully parametri c type signature can be implemented, and if so, to be able to derive the @@ -1746,6 +1749,7 @@ turnstile status open \begin_layout Plain Layout +0@ \begin_inset Formula $\vdash$ \end_inset @@ -1942,28 +1946,8 @@ name "subsec:Type-notation-and-standard-type-constructions" \end_layout \begin_layout Standard -A proposition -\begin_inset Formula ${\cal CH}(A)$ -\end_inset - - may be true with one set of premises such as -\begin_inset Formula ${\cal CH}(X)$ -\end_inset - -, -\begin_inset Formula ${\cal CH}(Y)$ -\end_inset - -, ..., -\begin_inset Formula ${\cal CH}(Z)$ -\end_inset - - but false with another. - Here and in the following sections, we will be reasoning about -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions within sequents of the form: +Here and in the following sections, we will be reasoning about sequents + of the form: \begin_inset Formula \[ {\cal CH}(X),{\cal CH}(Y),...,{\cal CH}(Z)\vdash{\cal CH}(A) @@ -1972,8 +1956,8 @@ A proposition \end_inset that represent type signatures of fully parametric functions. - It will be convenient to shorten the notation and to denote all premises - by the symbol + It will be convenient to shorten the notation and to denote the set of + all premises by the symbol \begin_inset Formula $\Gamma$ \end_inset @@ -2072,6 +2056,20 @@ plural "false" caps "false" noprefix "false" +\end_inset + + on page +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand pageref +reference "chap:Appendix-Notations" +plural "false" +caps "false" +noprefix "false" + \end_inset for a summary of our type notation.) @@ -2096,7 +2094,7 @@ six type constructions \end_inset - supported by all functional languages: primitive types (including + supported by all functional languages: primitive types, including the \begin_inset listings inline true status open @@ -2108,7 +2106,7 @@ Unit \end_inset - type and the void type, called + type and the void type ( \begin_inset listings inline true status open @@ -2120,7 +2118,7 @@ Nothing \end_inset - in Scala), tuples (also called +), tuples (also called \begin_inset Index idx status open @@ -2153,7 +2151,7 @@ co-product types \begin_inset Formula ${\cal CH}$ \end_inset --propositions for each of these type constructions (except recursive types). +-propositions for each of these type constructions except recursive types. \end_layout \begin_layout Paragraph @@ -2268,7 +2266,7 @@ Unit \end_inset . - We may write + We may write the rule as \begin_inset Formula $\mathcal{CH}(\bbnum 1)=True$ \end_inset @@ -2346,7 +2344,7 @@ N1 \end_inset is always true. - Named unit types are also denoted by + In the type notation, named unit types are also denoted by \begin_inset Formula $\bbnum 1$ \end_inset @@ -2464,7 +2462,7 @@ String \emph on always true \emph default - because we could use a constant value, e.g.: + because we may use a constant value, e.g.: \begin_inset listings inline false status open @@ -2624,8 +2622,7 @@ status open \end_inset . - Tuples and case classes with more than two parts are denoted similarly - as + Tuples and case classes with more than two parts are denoted by \begin_inset Formula $A\times B\times...\times C$ \end_inset @@ -2663,9 +2660,9 @@ is written in the type notation as \end_layout \begin_layout Standard -A disjunctive type may consist of several case classes. +A disjunctive type may consist of several cases. Having a value of a disjunctive type means to have a value of (at least) - one of those case classes. + one of those cases. An example of translating this relationship into a formula was shown by Eq. \begin_inset space ~ @@ -2767,8 +2764,8 @@ is translated to the type notation as: \end_inset -Here the type notation is significantly shorter because it omits all case - class names and part names from the type definitions. +The type notation is significantly shorter because it omits all case class + names and part names from the type definitions. Using the type notation, the rule for disjunctive types is written as: \begin_inset Formula \[ @@ -3023,6 +3020,22 @@ for all types . \end_layout +\begin_layout Standard +So, the rule for parameterized types with the type notation +\begin_inset Formula $\forall A.\,F^{A}$ +\end_inset + + is: +\begin_inset Formula +\[ +{\cal CH}(\forall A.\,F^{A})=\forall A.\,{\cal CH}(F^{A})\quad. +\] + +\end_inset + + +\end_layout + \begin_layout Standard The type notation for the type signature of \begin_inset listings @@ -3076,7 +3089,8 @@ for all \end_layout \begin_layout Standard -In Scala, longer type expressions can be named and their names (called +In Scala, longer type expressions can be named, and those names (called + \series bold type aliases \series default @@ -3196,22 +3210,6 @@ This syntax closely corresponds to the code notation . \end_layout -\begin_layout Standard -So, the rule for parameterized types with the type notation -\begin_inset Formula $\forall A.\,F^{A}$ -\end_inset - - is: -\begin_inset Formula -\[ -{\cal CH}(\forall A.\,F^{A})=\forall A.\,{\cal CH}(F^{A})\quad. -\] - -\end_inset - - -\end_layout - \begin_layout Standard Case classes and disjunctive types use \emph on @@ -3242,8 +3240,8 @@ The rules just shown will allow us to express \end_layout \begin_layout Standard -In this way, we see a correspondence between fully parametric type signatures - and logical sequents that express the proposition +In this way, we see a correspondence between a fully parametric type signature + and a logical sequent that expresses the statement \begin_inset Quotes eld \end_inset @@ -3252,7 +3250,7 @@ the type signature can be implemented \end_inset . - This is the first half of the Curry-Howard correspondence. + This is the first part of the Curry-Howard correspondence. \end_layout \begin_layout Standard @@ -3334,8 +3332,7 @@ The type product operator ( \end_inset . - This convention makes type expressions easier to reason about (for people - familiar with arithmetic). + This convention makes type expressions easier to read. \end_layout \begin_layout Itemize @@ -3398,9 +3395,9 @@ The type quantifiers group weaker than all other operators, so we can write \end_inset without parentheses. - This is helpful because type quantifiers are most often placed outside - a type expression. - When this is not the case, parentheses are necessary, e.g., in the type expressio + This is helpful because type quantifiers are most often placed at the top + level of a type expression. + When that is not the case, parentheses are necessary, e.g., in the type expressio n \begin_inset Formula $\left(\forall A.\,A\rightarrow A\rightarrow A\right)\rightarrow\bbnum 1+\bbnum 1$ \end_inset @@ -4234,8 +4231,20 @@ A => (A, A) \end_inset . - We also note that there is only one way of implementing a fully parametric - function with type signature + We also note that +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +delta +\end_layout + +\end_inset + + seems to be the only way of implementing a fully parametric function with + type signature \begin_inset listings inline true status open @@ -4247,7 +4256,7 @@ A => (A, A) \end_inset -: the function must duplicate its given argument. +. \end_layout \begin_layout Standard @@ -4952,7 +4961,7 @@ A \end_inset . - So we begin writing the code as: + So, we begin writing the code as: \begin_inset listings inline false status open @@ -5105,7 +5114,7 @@ f \end_inset - are chosen purely for convenience. + are chosen arbitrarily. \end_layout \begin_layout Subsubsection @@ -5213,7 +5222,7 @@ We do not put parentheses around \end_inset ) groups weaker than the other type operations. - Parentheses around + But parentheses around \begin_inset Formula $\left(A\rightarrow B\right)$ \end_inset @@ -6150,7 +6159,11 @@ xN \end_inset . - So, each of the eight code constructs will give a proof rule in the logic. + +\end_layout + +\begin_layout Standard +So, each of the eight code constructs will give a proof rule in the logic. \end_layout \begin_layout Standard @@ -6233,9 +6246,9 @@ eight code constructions \end_layout \begin_layout Standard -In this way, we will get a correspondence between proofs of sequents and - fully parametric programs. - This is the second half of the Curry-Howard correspondence. +In this way, we will get a correspondence between fully parametric programs + and proofs of sequents. + This is the second part of the Curry-Howard correspondence. \end_layout \begin_layout Standard @@ -6759,7 +6772,35 @@ function \emph default that takes a proof of the previous sequent as an argument and returns a proof of the new sequent. - By the CH correspondence, a proof of a sequent corresponds to a code expression + We call that function a +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Curry-Howard correspondence!proof transformer +\end_layout + +\end_inset + + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +proof transformer +\end_layout + +\end_inset + + +\series bold +proof transformer +\series default +. +\end_layout + +\begin_layout Standard +By the CH correspondence, a proof of a sequent corresponds to a code expression of the type given by the goal of the sequent. That expression may use arguments of types corresponding to the premises of the sequent. @@ -6835,7 +6876,7 @@ exprB \end_inset . - The proof code is: + That rule's proof transformer is: \begin_inset Formula \[ \text{Proof}\,\big(\Gamma\vdash{\cal CH}(A)\Rightarrow{\cal CH}(B)\big)=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,{\cal CH}(A)\vdash{\cal CH}(B)\big)_{\text{given }x^{:A}}\quad. @@ -6843,7 +6884,7 @@ exprB \end_inset -Here the subscript +Here, the subscript \begin_inset Quotes eld \end_inset @@ -6859,7 +6900,7 @@ given \begin_inset Formula $x^{:A}$ \end_inset - is a known proof of the proposition + is a previously known proof of the proposition \begin_inset Formula ${\cal CH}(A)$ \end_inset @@ -7174,7 +7215,7 @@ t._2 respectively, and the corresponding sequent proof rules are: \begin_inset Formula \[ -\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\quad\quad. +\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad,\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\quad\quad. \] \end_inset @@ -7341,7 +7382,8 @@ y:B \end_inset -The corresponding proof code can be written using the case class names +The corresponding proof transformers can be written using the case class + names \begin_inset listings inline true status open @@ -7834,7 +7876,21 @@ no \begin_inset Formula $\Gamma$ \end_inset - of premises is empty ( + of premises is empty (denoted by the +\begin_inset Index idx +status open + +\begin_layout Plain Layout +0@ +\begin_inset Formula $\emptyset$ +\end_inset + + (empty set) +\end_layout + +\end_inset + +empty set, \begin_inset Formula $\Gamma=\emptyset$ \end_inset @@ -7989,7 +8045,7 @@ We now need to prove the sequent \end_inset where we define -\begin_inset Formula $\Gamma_{1}\triangleq[(\alpha\Rightarrow\alpha)\Rightarrow\beta]$ +\begin_inset Formula $\Gamma_{1}\triangleq\{(\alpha\Rightarrow\alpha)\Rightarrow\beta\}$ \end_inset to denote the set containing the single premise @@ -8456,7 +8512,7 @@ The right-most leaf \end_inset . - So we can write: + So, we can write: \begin_inset Formula \[ \text{Proof}\left(\Gamma_{1}\vdash(\alpha\Rightarrow\alpha)\Rightarrow\beta\right)_{\text{given }f}=f^{:(A\rightarrow A)\rightarrow B}\quad. @@ -9081,7 +9137,7 @@ name "app:The-LJT-algorithm" \end_layout \begin_layout Standard -The LJT algorithm resolves an important issue: namely, that the logic rules +The LJT algorithm solves an important problem: namely, that the logic rules in Table \begin_inset space ~ \end_inset @@ -9399,7 +9455,7 @@ use function \end_layout \begin_layout Standard -To see that the rules in Table +The rules in Table \begin_inset space ~ \end_inset @@ -9413,7 +9469,7 @@ noprefix "false" \end_inset - are not helpful for proof search, note that the rules + are not helpful for proof search because the rules \begin_inset Quotes eld \end_inset @@ -9441,8 +9497,8 @@ Either \begin_inset Quotes erd \end_inset - require us to choose new unknown propositions and to prove more complicated - sequents than the ones we had before. + require us to choose new unknown propositions and to prove sequents more + complicated than the ones we had before. For instance, the rule \begin_inset Quotes eld \end_inset @@ -10047,7 +10103,7 @@ This sequent follows from the \begin_inset Quotes erd \end_inset -axiom. + axiom. There are no more sequents to prove, so the proof of \begin_inset Formula $S_{0}$ \end_inset @@ -10186,6 +10242,10 @@ B & y^{:B}\rightarrow\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p,y} \end_inset +\begin_inset VSpace defskip +\end_inset + + \end_layout \end_inset @@ -10253,7 +10313,7 @@ Since the leaves are axioms, let us write the code corresponding to each axiom of LJ: \begin_inset Formula \begin{align*} - & \frac{}{\Gamma,X\vdash X}~(\text{Id})\quad:\quad\quad\text{Proof}\,(\Gamma,X\vdash X)_{\text{given }p^{:\Gamma},x^{:X}}=x\quad;\\ + & \frac{}{\Gamma,X\vdash X}~(\text{Id})\quad:\quad\quad\text{Proof}\,(\Gamma,X\vdash X)_{\text{given }p^{:\Gamma},\,x^{:X}}=x\quad;\\ & \frac{}{\Gamma\vdash\top}~(\text{True})\quad:\quad\quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\quad. \end{align*} @@ -10356,7 +10416,7 @@ evidence of proof \begin_inset Formula \begin{align*} & S_{3}\triangleq\beta\vdash\beta\quad,\quad\quad\text{Proof}\,(S_{3})_{\text{given }y^{:B}}=y\quad,\\ - & S_{6}\triangleq\gamma,\alpha\vdash\alpha\quad,\quad\quad\text{Proof}\,(S_{6})_{\text{given }q^{:C},x^{:A}}=x\quad. + & S_{6}\triangleq\gamma,\alpha\vdash\alpha\quad,\quad\quad\text{Proof}\,(S_{6})_{\text{given }q^{:C},\,x^{:A}}=x\quad. \end{align*} \end_inset @@ -10396,7 +10456,7 @@ evidence of proof : \begin_inset Formula \[ -\xymatrix{\xyScaleY{1.5pc}\xyScaleX{4pc} & & & \square\\ +\xymatrix{\xyScaleY{1.5pc}\xyScaleX{4.2pc} & & & \square\\ \ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.5){S_{1}} & (\text{Left}\Rightarrow)\ar[r]\sp(0.5){S_{2}}\ar[ru]\sp(0.6){(y)_{\text{given }y^{:B}}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){(x)_{\text{given }q^{:C},x^{:A}}} & \square } \] @@ -10443,31 +10503,7 @@ s a proof of \end_inset . - We call this function the -\series bold -proof transformer -\series default - -\begin_inset Index idx -status open - -\begin_layout Plain Layout -Curry-Howard correspondence!proof transformer -\end_layout - -\end_inset - - -\begin_inset Index idx -status open - -\begin_layout Plain Layout -proof transformer -\end_layout - -\end_inset - - corresponding to the rule + That function is the proof transformer corresponding to the rule \begin_inset Quotes eld \end_inset @@ -10484,7 +10520,7 @@ proof transformer \begin_inset Formula \begin{align*} \frac{\Gamma,A\vdash B}{\Gamma\vdash A\Rightarrow B}~(\text{Right}\Rightarrow)\quad: & \quad\quad\text{Proof}\,(\Gamma\vdash A\Rightarrow B)_{\text{given }p^{:\Gamma}}\\ - & \quad\quad=x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash B)_{\text{given }p^{:\Gamma},x^{:A}}\quad. + & \quad\quad=x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash B)_{\text{given }p^{:\Gamma},\,x^{:A}}\quad. \end{align*} \end_inset @@ -10500,7 +10536,7 @@ Applying the proof transformer to the known proof of : \begin_inset Formula \[ -\text{Proof}\,(S_{2})_{\text{given }q^{:C}}=x^{:A}\rightarrow\text{Proof}\,(S_{6})_{\text{given }q^{:C},x^{:A}}=(x^{:A}\rightarrow x)_{\text{given }q^{:C}}\quad. +\text{Proof}\,(S_{2})_{\text{given }q^{:C}}=x^{:A}\rightarrow\text{Proof}\,(S_{6})_{\text{given }q^{:C},\,x^{:A}}=(x^{:A}\rightarrow x)_{\text{given }q^{:C}}\quad. \] \end_inset @@ -10551,7 +10587,7 @@ In the proof tree shown above, we obtain a proof of \begin_inset Formula $S_{1}$ \end_inset - by applying this proof transformer to the proofs of + by applying that proof transformer to the proofs of \begin_inset Formula $S_{2}$ \end_inset @@ -10571,7 +10607,7 @@ In the proof tree shown above, we obtain a proof of Substituting this proof into the proof tree, we shorten the tree to: \begin_inset Formula \[ -\xymatrix{\xyScaleY{1.5pc}\xyScaleX{3.5pc}\ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}} & \square} +\xymatrix{\xyScaleY{1.5pc}\xyScaleX{5.5pc}\ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}} & \square} \] \end_inset @@ -10605,11 +10641,11 @@ It remains to obtain the proof of \end_inset -The proof tree is now shortened to the code expression +The proof tree is now shortened to just the code \begin_inset Formula $q^{:(A\rightarrow A)\rightarrow B}\rightarrow q(x^{:A}\rightarrow x)$ \end_inset - has type +, which has type \begin_inset Formula $\left(\left(A\rightarrow A\right)\rightarrow B\right)\rightarrow B$ \end_inset @@ -10700,7 +10736,7 @@ As we have seen, the LJ algorithm enters a loop if the rule That rule requires us to prove two new sequents: \begin_inset Formula \[ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\quad\Gamma,B\vdash C}{\Gamma,A\Rightarrow B\vdash C}~(\text{Left}\Rightarrow)\quad. +\frac{\Gamma,A\Rightarrow B\vdash A\quad\quad\Gamma,B\vdash C}{\Gamma,A\Rightarrow B\vdash C}~(\text{Left}\Rightarrow)\quad\quad. \] \end_inset @@ -11168,6 +11204,10 @@ status open \end_inset +\begin_inset VSpace defskip +\end_inset + + \end_layout \end_inset @@ -13721,7 +13761,7 @@ noprefix "false" \begin_inset Formula \begin{align} & \forall(\alpha,\beta,\gamma).\,\left(\alpha\Rightarrow\left(\beta\vee\gamma\right)\right)\Rightarrow\left(\left(\alpha\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\gamma\right)\right)\quad,\label{eq:abc-example-classical-logic-bad}\\ -\text{where we denoted}\quad & \alpha\triangleq{\cal CH}(A),\quad\beta\triangleq{\cal CH}(B),\quad\gamma\triangleq{\cal CH}(C)\quad.\nonumber +\text{where we denoted}:\quad & \alpha\triangleq{\cal CH}(A),\quad\beta\triangleq{\cal CH}(B),\quad\gamma\triangleq{\cal CH}(C)\quad.\nonumber \end{align} \end_inset @@ -13814,7 +13854,7 @@ equal \end_layout \begin_layout Standard -Let us also give a proof via truth-value reasoning. +Let us also give a proof by truth-value reasoning. The only possibility for an implication \begin_inset Formula $X\Rightarrow Y$ \end_inset @@ -14113,15 +14153,7 @@ noprefix "false" \end_inset -This formula is the well-known -\begin_inset Quotes eld -\end_inset - -distributive law -\begin_inset Quotes erd -\end_inset - - +This formula is a well-known distributive law \begin_inset Foot status open @@ -14249,21 +14281,7 @@ f2 \end_inset . - It is not straightforward to guess how to combine the proof rules of Table -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:Proof-rules-of-constructive-and-boolean" -plural "false" -caps "false" -noprefix "false" - -\end_inset - - to obtain proofs of Eqs. + We could use the proof rules of the LJT algorithm to obtain proofs of Eqs. \begin_inset space ~ \end_inset @@ -14287,8 +14305,7 @@ noprefix "false" \end_inset -). - So, instead of deriving the implementations of +) and to derive implementations of \begin_inset listings inline true status open @@ -14312,7 +14329,8 @@ f2 \end_inset - from the CH correspondence, we will write the Scala code directly. +. + Instead, let us exercise our intuition and write the Scala code directly. \end_layout \begin_layout Standard @@ -14555,7 +14573,7 @@ y \end_layout \begin_layout Standard -Let us write these conditions as equations: +Let us write those conditions as equations: \begin_inset Formula \[ \forall x^{:(A+B)\times C}.\,f_{2}(f_{1}(x))=x\quad,\quad\quad\forall y^{:A\times C+B\times C}.\,f_{1}\left(f_{2}(y)\right)=y\quad. @@ -14710,7 +14728,7 @@ when there exist functions \end_inset that are inverses of each other. - We can write these conditions using the notation + We can write that using the notation \begin_inset Formula $(f_{1}\bef f_{2})(x)\triangleq f_{2}(f_{1}(x))$ \end_inset @@ -15450,7 +15468,8 @@ status open \begin_inset Formula $A\times\left(B\times C\right)$ \end_inset - are equivalent, and we can write + are equivalent. + We will often write \begin_inset Formula $A\times B\times C$ \end_inset @@ -15696,8 +15715,8 @@ None \end_layout \begin_layout Standard -Another example of a logical identity without a type equivalence is the - distributive law: +Another example of a logical identity that does not correspond to a type + equivalence is the distributive law: \begin_inset Formula \begin{equation} \forall(A,B,C).\,\left(A\wedge B\right)\vee C=\left(A\vee C\right)\wedge\left(B\vee C\right)\quad,\label{eq:ch-example-distributive-2} @@ -16096,7 +16115,7 @@ not \begin_inset space ~ \end_inset - +( \begin_inset CommandInset ref LatexCommand ref reference "eq:ch-example-incorrect-identity-2" @@ -16106,7 +16125,7 @@ noprefix "false" \end_inset -, e.g., +), e.g., \begin_inset Formula $\left(1\times10\right)+20\neq\left(1+20\right)\times\left(10+20\right)$ \end_inset @@ -16149,7 +16168,19 @@ noprefix "false" ), which does not yield a type equivalence, leads to an incorrect arithmetic statement ( -\begin_inset Formula $\forall a.\,1+a=1$ +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $1+a=1$ +\end_inset + + for all +\begin_inset Formula $a$ +\end_inset + + +\begin_inset Quotes erd \end_inset ). @@ -18236,8 +18267,8 @@ f1 \begin_inset Formula \[ f_{1}\triangleq x^{:A+B}\rightarrow\begin{cases} -\text{if }x=a^{:A}+\bbnum 0^{:B}\quad: & \bbnum 0^{:B}+a^{:A}\\ -\text{if }x=\bbnum 0^{:A}+b^{:B}\quad: & b^{:B}+\bbnum 0^{:A} +\quad\text{if }x=a^{:A}+\bbnum 0^{:B}\quad: & \bbnum 0^{:B}+a^{:A}\\ +\quad\text{if }x=\bbnum 0^{:A}+b^{:B}\quad: & b^{:B}+\bbnum 0^{:A} \end{cases} \] @@ -18366,7 +18397,7 @@ status open \begin_layout Plain Layout -case Left(a) => Right(a) +case Left(a) => Right(a) \end_layout \end_inset @@ -18385,14 +18416,26 @@ case Left(a) => Right(a) \end_inset because no value of that type is returned. - In this way, we translate each line of the + In this way, we translate all lines of the \begin_inset listings inline true status open \begin_layout Plain Layout -match / case +match +\end_layout + +\end_inset + +/ +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +case \end_layout \end_inset @@ -19433,15 +19476,8 @@ Left(true) \emph on are \emph default - equivalent, but there is no -\begin_inset Quotes eld -\end_inset - -natural -\begin_inset Quotes erd -\end_inset - - choice of the conversion functions + equivalent, but there is no natural choice of the conversion functions + \begin_inset listings inline true status open @@ -19465,8 +19501,7 @@ f2 \end_inset - that will work correctly in all applications, because the meaning of these - data types will be application-dependent. + because the meaning of those data types will be application-dependent. We call this type equivalence \series bold accidental @@ -20144,7 +20179,7 @@ Nevertheless, the formula \begin_inset Formula $B$ \end_inset - have only a small number of distinct values (for example, + have only a small number of distinct values (for example, with \begin_inset Formula $A=$ \end_inset @@ -20235,7 +20270,7 @@ It is notable that no logic identity is available for the formula \begin_inset Formula $A\rightarrow B+C$ \end_inset - is more complicated because those types usually cannot be transformed into + is more complicated because those types usually cannot be rewritten as simpler types. \end_layout @@ -20815,7 +20850,7 @@ Unit \end_inset . - We can always produce that value as + We produce that value as \begin_inset listings inline true status open @@ -22568,6 +22603,7 @@ pipe notation status open \begin_layout Plain Layout +0@ \begin_inset Formula $\triangleright$ \end_inset @@ -22635,13 +22671,13 @@ With these notations, we compute further. : \begin_inset Formula \begin{align*} - & \begin{array}{|cc|} + & h(a+\bbnum 0)=\,\begin{array}{|cc|} a & \bbnum 0\end{array}\,\triangleright\,h=\,\begin{array}{|cc|} a & \bbnum 0\end{array}\,\triangleright\,\begin{array}{||c|} p\\ q \end{array}\,=a\triangleright p=p(a)\quad,\\ - & \begin{array}{|cc|} + & h(\bbnum 0+b)=\,\begin{array}{|cc|} \bbnum 0 & b\end{array}\,\triangleright\,h=\,\,\begin{array}{|cc|} \bbnum 0 & b\end{array}\,\triangleright\,\begin{array}{||c|} p\\ @@ -22658,7 +22694,7 @@ Now we can complete the proof of : \begin_inset Formula \begin{align*} -f_{1}\bef f_{2} & =h\rightarrow\,\begin{array}{||c|} + & f_{1}\bef f_{2}=h\rightarrow\,\begin{array}{||c|} a\rightarrow h(a+\bbnum 0)\\ b\rightarrow h(\bbnum 0+b) \end{array}\\ @@ -22710,11 +22746,11 @@ f\\ g \end{array}\,\bigg)\bef\big(h\rightarrow(a\rightarrow(a+\bbnum 0)\triangleright h)\times(b\rightarrow(\bbnum 0+b)\triangleright h)\big)\\ \text{composition}:\quad & =f\times g\rightarrow\big(a\rightarrow\gunderline{\,\begin{array}{|cc|} -a & \bbnum 0\end{array}\,\triangleright}\,\begin{array}{||c|} +a & \bbnum 0\end{array}\,\,\triangleright}\,\begin{array}{||c|} f\\ g \end{array}\,\big)\times\big(b\rightarrow\gunderline{\,\begin{array}{|cc|} -\bbnum 0 & b\end{array}\,\triangleright}\,\begin{array}{||c|} +\bbnum 0 & b\end{array}\,\,\triangleright}\,\begin{array}{||c|} f\\ g \end{array}\,\big)\\ @@ -23546,7 +23582,7 @@ P \end_inset - in the type notation and simplify it to an equivalent type. + in the type notation. \end_layout \begin_layout Subparagraph @@ -23916,7 +23952,7 @@ Solution \begin_layout Standard Begin by writing the given type in the type notation. - The tuple becomes the product type, and + The tuple becomes a product type, and \begin_inset listings inline true status open @@ -23928,15 +23964,7 @@ Either \end_inset - becomes the disjunctive (or -\begin_inset Quotes eld -\end_inset - -sum -\begin_inset Quotes erd -\end_inset - -) type: + becomes a disjunctive type: \begin_inset Formula \[ P\triangleq(A+B)\times(C+D)\quad. @@ -23953,7 +23981,7 @@ P\cong A\times C+A\times D+B\times C+B\times D\quad. \end_inset -This is a disjunctive type having +This is a disjunctive type with \begin_inset Formula $4$ \end_inset @@ -24002,7 +24030,7 @@ Solution \end_layout \begin_layout Standard -Note that the arithmetic equalities do not hold, +The arithmetic equalities do not hold, \begin_inset Formula $A+A\neq A$ \end_inset @@ -24676,7 +24704,7 @@ B \end_inset , which we do not have. - So we cannot produce a + So, we cannot produce a \begin_inset listings inline true status open @@ -24773,17 +24801,17 @@ status open \begin_layout Plain Layout -def f2[A,B,C]: Either[A=>C, B=>C] => ((A,B)) => C = { +def f2[A,B,C]: Either[A => C, B => C] => ((A, B)) => C = { \end_layout \begin_layout Plain Layout - case Left(g) => { case (a, b) => g(a) } + case Left(g) => { case (a, b) => g(a) } \end_layout \begin_layout Plain Layout - case Right(h) => { case (a, b) => h(b) } + case Right(h) => { case (a, b) => h(b) } \end_layout \begin_layout Plain Layout @@ -25296,7 +25324,7 @@ Solution \begin_layout Standard Begin by defining a type alias for the type constructor -\begin_inset Formula $\text{Read}^{E,A}$ +\begin_inset Formula $\text{Reader}^{E,A}$ \end_inset : @@ -25306,7 +25334,7 @@ status open \begin_layout Plain Layout -type Read[E, A] = E => A +type Reader[E, A] = E => A \end_layout \end_inset @@ -25318,7 +25346,7 @@ status open \begin_layout Plain Layout -def p[E, A]: A => Read[E, A] = { x => _ => x } +def p[E, A]: A => Reader[E, A] = { x => _ => x } \end_layout \end_inset @@ -25379,7 +25407,7 @@ status open \begin_layout Plain Layout -def map[E, A, B]: Read[E, A] => (A => B) => Read[E, B] = ??? +def map[E, A, B]: Reader[E, A] => (A => B) => Reader[E, B] = ??? \end_layout \end_inset @@ -25521,7 +25549,7 @@ To fill the typed hole \end_inset . - So we write: + So, we write: \begin_inset Formula \[ \text{map}\triangleq r^{:E\rightarrow A}\rightarrow f^{:A\rightarrow B}\rightarrow e^{:E}\rightarrow f(???^{:A})\quad. @@ -25623,12 +25651,12 @@ status open \begin_layout Plain Layout -Read[A, T] => (A => B) => Read[B, T] +Reader[A, T] => (A => B) => Reader[B, T] \end_layout \end_inset - cannot be implemented as a fully parametric function. + cannot be implemented by a fully parametric function. \end_layout \begin_layout Subparagraph @@ -26704,7 +26732,7 @@ Either[L, R] \end_inset . - So we obtain the type signatures: + So, we obtain the type signatures: \begin_inset Formula \begin{align*} \text{map} & :L+R\rightarrow(L\rightarrow M)\rightarrow M+R\quad,\\ @@ -28769,7 +28797,7 @@ noprefix "false" ). These constructions are foundational in the sense that they are used to express all design patterns of functional programming. - A language that does not directly support some of these constructions cannot + A language that does not directly support all of those constructions cannot be considered a functional programming language. \end_layout @@ -28850,8 +28878,8 @@ appears \end_inset ) although that value is not actually available. - In practice, such code will crash because of a value that has a wrong type, - is + In practice, such code will crash because of a value that has a wrong type + or is \begin_inset Quotes eld \end_inset @@ -28859,7 +28887,7 @@ null \begin_inset Quotes erd \end_inset -, or is a pointer to an invalid memory location. + (a pointer to an invalid memory location). Those errors cannot happen in a programming language whose logic of types is consistent and whose compiler checks all types at compile time. @@ -28975,12 +29003,12 @@ It is possible to apply the FP paradigm while writing code in any programming language. However, some languages lack certain features that make FP techniques easier to use in practice. - For example, in a language such as JavaScript, Python, or Ruby, one can - productively use the map/reduce operations but not disjunctive types. + For example, in a language such as C++ or Java, one can easily use the + map/reduce operations but not disjunctive types. More advanced FP constructions (such as typeclasses) are impractical in - these languages because the required code becomes too hard to read and - to write without errors, which negates the advantages of rigorous reasoning - about functional programs. + those languages: the required code becomes too hard to read and to write + without errors, which negates the advantages of rigorous reasoning about + functional programs. \end_layout \begin_layout Standard @@ -29028,7 +29056,7 @@ void \begin_inset Quotes erd \end_inset - type as defined in this book is a type with no values. + type is a type with no values. It is \emph on not @@ -29054,7 +29082,8 @@ no value \end_inset . - Those functions are equivalent to Scala functions returning the + Those functions are equivalent to Scala functions returning the (unique) + value of \begin_inset listings inline true status open @@ -29379,7 +29408,7 @@ x \begin_layout Standard This book does not discuss exceptions in much detail. The functional programming paradigm does not use exceptions because their - presence significantly complicates reasoning about code. + presence prevents mathematical reasoning about code. \end_layout \begin_layout Standard @@ -29536,13 +29565,12 @@ negation (in logic) \end_inset -Its practical use is as limited as that of +Its practical use in functional programming is as limited as that of \begin_inset Formula $False$ \end_inset and the void type. - However, logical negation plays an important role in Boolean logic, which - we will discuss next. + However, logical negation plays an important role in Boolean logic. \end_layout \begin_layout Subsection @@ -29584,7 +29612,7 @@ noprefix "false" \end_inset -) are also true in Boolean logic. +) also hold in Boolean logic. \end_layout \begin_layout Standard @@ -29886,7 +29914,7 @@ Boolean logic \begin_layout Plain Layout \size small -\begin_inset Formula $\frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create Left})$ +\begin_inset Formula $\frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Left}})$ \end_inset @@ -29916,7 +29944,7 @@ Boolean logic \begin_layout Plain Layout \size small -\begin_inset Formula $\frac{\Gamma\vdash\alpha\vee\beta\quad\Gamma,\alpha\vdash\gamma\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use Either})$ +\begin_inset Formula $\frac{\Gamma\vdash\alpha\vee\beta\quad\Gamma,\alpha\vdash\gamma\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use \texttt{Either}})$ \end_inset @@ -30042,8 +30070,20 @@ To simplify the calculations, note that all terms in the formulas contain \begin_inset Quotes eld \end_inset +use +\begin_inset space ~ +\end_inset + + +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either +\end_layout -\begin_inset Formula $\text{use Either}$ \end_inset @@ -30072,7 +30112,7 @@ To simplify the calculations, note that all terms in the formulas contain \begin_inset Formula \begin{align*} -\text{formula ``use Either''}:\quad & \left(\left(\alpha\vee\beta\right)\wedge\left(\alpha\Rightarrow\gamma\right)\wedge\left(\beta\Rightarrow\gamma\right)\right)\Rightarrow\gamma\\ +\text{formula ``use \texttt{Either}''}:\quad & \left(\left(\alpha\vee\beta\right)\wedge\left(\alpha\Rightarrow\gamma\right)\wedge\left(\beta\Rightarrow\gamma\right)\right)\Rightarrow\gamma\\ \text{use Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:\quad & =\neg\left(\left(\alpha\vee\beta\right)\wedge\left(\neg\alpha\vee\gamma\right)\wedge\left(\neg\beta\vee\gamma\right)\right)\vee\gamma\\ \text{de Morgan's laws}:\quad & =\left(\neg\alpha\wedge\neg\beta\right)\vee\gunderline{\left(\alpha\wedge\neg\gamma\right)}\vee\gunderline{\left(\beta\wedge\neg\gamma\right)}\vee\gamma\\ \text{identity }p\vee(\neg p\wedge q)=p\vee q:\quad & =\gunderline{\left(\neg\alpha\wedge\neg\beta\right)\vee\alpha}\vee\beta\vee\gamma\\ @@ -30316,8 +30356,8 @@ not \end_layout \begin_layout Standard -The reason Boolean logic can use truth tables is that every Boolean proposition - is either +The Boolean logic can use truth tables because every Boolean proposition + may be assumed in advance to be either \begin_inset Formula $True$ \end_inset @@ -30511,14 +30551,19 @@ Int \end_inset . + For similar reasons, we cannot compute a value of type +\begin_inset Formula $A$ +\end_inset + + either. \end_layout \begin_layout Standard -Why is it impossible to implement a value of the type +Is it really impossible to implement a value of the type \begin_inset Formula $\left(A\rightarrow\bbnum 0\right)+A$ \end_inset -? Surely, the type +? We could reason like this: the type \begin_inset Formula $A$ \end_inset diff --git a/sofp-src/sofp-curry-howard.tex b/sofp-src/sofp-curry-howard.tex index afd6afce7..773561418 100644 --- a/sofp-src/sofp-curry-howard.tex +++ b/sofp-src/sofp-curry-howard.tex @@ -130,14 +130,15 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} So, when working with fully parametric code and looking at some type signature of a function, we may ask the question \textemdash{} is that type signature implementable, and if so, can we derive the code -by just \textsf{``}following the types\textsf{''}? It is remarkable that this question -can be asked at all. When working with non-functional programming -languages, the notion of fully parametric functions is usually not -relevant, and implementations cannot be derived from types. But in -functional programming, fully parametric functions are used often. -It is then important for the programmer to know whether a given fully -parametric type signature can be implemented, and if so, to be able -to derive the code. +by just \textsf{``}following the types\textsf{''}? + +It is remarkable that this question can be asked at all. When working +with non-FP languages, the notion of fully parametric functions is +usually not relevant, and implementations cannot be derived from types. +But in functional programming, fully parametric functions are used +often. It is then important for the programmer to know whether a given +fully parametric type signature can be implemented, and if so, to +be able to derive the code. Can we prove rigorously that the functions \lstinline!bad!, \lstinline!bad2!, \lstinline!bad3! cannot be implemented by any fully parametric code? @@ -171,7 +172,7 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} is equivalent to \textsf{``}${\cal CH}(A)$ is true assuming ${\cal CH}(X)$, ${\cal CH}(Y)$, ..., ${\cal CH}(Z)$ are true\textsf{''}. In mathematical logic, a statement of this form is called a \textbf{sequent} and\index{sequent (in logic)} -is denoted using the symbol $\vdash$ (the \textsf{``}turnstile\textsf{''}):\index{vdash (turnstile) symbol@$\vdash$ (turnstile) symbol}\index{turnstile (vdash) symbol@turnstile ($\vdash$) symbol} +is denoted using the symbol $\vdash$ (the \textsf{``}turnstile\textsf{''}):\index{0@$\vdash$ (turnstile) symbol}\index{turnstile (vdash) symbol@turnstile ($\vdash$) symbol} \begin{align} {\color{greenunder}\text{sequent}:}\quad & {\cal CH}(X),{\cal CH}(Y),...,{\cal CH}(Z)\vdash{\cal CH}(A)\quad.\label{eq:ch-example-sequent} \end{align} @@ -218,16 +219,14 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} \subsection{Type notation and ${\cal CH}$-propositions for standard type constructions\label{subsec:Type-notation-and-standard-type-constructions}} -A proposition ${\cal CH}(A)$ may be true with one set of premises -such as ${\cal CH}(X)$, ${\cal CH}(Y)$, ..., ${\cal CH}(Z)$ but -false with another. Here and in the following sections, we will be -reasoning about ${\cal CH}$-propositions within sequents of the form: +Here and in the following sections, we will be reasoning about sequents +of the form: \[ {\cal CH}(X),{\cal CH}(Y),...,{\cal CH}(Z)\vdash{\cal CH}(A) \] that represent type signatures of fully parametric functions. It will -be convenient to shorten the notation and to denote all premises by -the symbol $\Gamma$. We will then write just $\Gamma\vdash{\cal CH}(A)$ +be convenient to shorten the notation and to denote the set of all +premises by the symbol $\Gamma$. We will then write just $\Gamma\vdash{\cal CH}(A)$ instead of ${\cal CH}(X),{\cal CH}(Y),...,{\cal CH}(Z)\vdash{\cal CH}(A)$. In Section~\ref{subsec:Disjunctions-and-conjunctions} we saw examples @@ -239,17 +238,17 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru in terms of ${\cal CH}$-propositions for simple type parameters: ${\cal CH}(A)$, ${\cal CH}(B)$, etc. A special type notation\index{type notation} explained in this section will help us write type expressions more -concisely. (See Appendix~\ref{chap:Appendix-Notations} for a summary -of our type notation.) +concisely. (See Appendix~\ref{chap:Appendix-Notations} on page~\pageref{chap:Appendix-Notations} +for a summary of our type notation.) There exist \textbf{six} \textbf{standard type constructions}\index{six type constructions} -supported by all functional languages: primitive types (including -\lstinline!Unit! type and the void type, called \lstinline!Nothing! -in Scala), tuples (also called \index{product types}\textbf{product -types}), disjunctive types (also called \index{co-product types}\textbf{co-product +supported by all functional languages: primitive types, including +the \lstinline!Unit! type and the void type (\lstinline!Nothing!), +tuples (also called \index{product types}\textbf{product types}), +disjunctive types (also called \index{co-product types}\textbf{co-product types}), function types, parameterized types, and recursive types. We will now derive the rules for writing ${\cal CH}$-propositions -for each of these type constructions (except recursive types). +for each of these type constructions except recursive types. \paragraph{1a) Rule for the \texttt{Unit} type} @@ -264,7 +263,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \end{lstlisting} So, the proposition ${\cal CH}($\lstinline!Unit!$)$ is always true. In the type notation, the \lstinline!Unit! type is denoted by $\bbnum 1$. -We may write $\mathcal{CH}(\bbnum 1)=True$. +We may write the rule as $\mathcal{CH}(\bbnum 1)=True$. Named unit types\index{unit type!named} also have a single value that is always possible to compute. For example: @@ -277,8 +276,8 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru val x: N1 = N1() \end{lstlisting} So, the proposition ${\cal CH}($\lstinline!N1!$)$ is always true. -Named unit types are also denoted by $\bbnum 1$, just as the \lstinline!Unit! -type itself. +In the type notation, named unit types are also denoted by $\bbnum 1$, +just as the \lstinline!Unit! type itself. \paragraph{1b) Rule for the void type} @@ -290,7 +289,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru For a specific primitive (or library-defined) type such as \lstinline!Int! or \lstinline!String!, the corresponding ${\cal CH}$-proposition -is \emph{always true} because we could use a constant value, e.g.: +is \emph{always true} because we may use a constant value, e.g.: \begin{lstlisting} def f[...]: ... { ... @@ -309,8 +308,8 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru A similar formula holds for case classes, as Eq.~(\ref{eq:curry-howard-example-case-class}) shows. In the type notation, the tuple \lstinline!(A, B)! is written as $A\times B$. Tuples and case classes with more than two parts -are denoted similarly as $A\times B\times...\times C$. For example, -the Scala definition: +are denoted by $A\times B\times...\times C$. For example, the Scala +definition: \begin{lstlisting} case class Person(firstName: String, lastName: String, age: Int) \end{lstlisting} @@ -323,9 +322,9 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \paragraph{3) Rule for disjunctive types} -A disjunctive type may consist of several case classes. Having a value -of a disjunctive type means to have a value of (at least) one of those -case classes. An example of translating this relationship into a formula +A disjunctive type may consist of several cases. Having a value of +a disjunctive type means to have a value of (at least) one of those +cases. An example of translating this relationship into a formula was shown by Eq.~(\ref{eq:curry-howard-example-disjunction}). For the standard disjunctive type \lstinline!Either[A, B]!, we have the logical formula ${\cal CH}($\lstinline!Either[A, B]!$)={\cal CH}(A)\vee{\cal CH}(B)$. @@ -341,9 +340,9 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \[ \text{RootsOfQ}\triangleq\bbnum 1+\text{Double}+\text{Double}\times\text{Double}\quad. \] -Here the type notation is significantly shorter because it omits all -case class names and part names from the type definitions. Using the -type notation, the rule for disjunctive types is written as: +The type notation is significantly shorter because it omits all case +class names and part names from the type definitions. Using the type +notation, the rule for disjunctive types is written as: \[ {\cal CH}\left(A+B+...+C\right)={\cal CH}(A)\vee{\cal CH}(B)\vee...\vee{\cal CH}(C)\quad. \] @@ -394,6 +393,12 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru quantifier} in logic. We read $\forall A.\,{\cal CH}(B)$ as the proposition \textsf{``}for all types $A$, we can compute a value of type $B$\textsf{''}. +So, the rule for parameterized types with the type notation $\forall A.\,F^{A}$ +is: +\[ +{\cal CH}(\forall A.\,F^{A})=\forall A.\,{\cal CH}(F^{A})\quad. +\] + The type notation for the type signature of \lstinline!f! is written in one of the following ways: \[ @@ -402,7 +407,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru The type quantifier (\textsf{``}for all $A$ and $B$\textsf{''}) indicates that $f$ can be used with all types $A$ and $B$. -In Scala, longer type expressions can be named and their names (called +In Scala, longer type expressions can be named, and those names (called \textbf{type aliases}\index{type alias}) can be used to make code shorter. Type aliases may also contain type parameters. Defining and using a type alias for the type of the function \lstinline!f! looks @@ -431,12 +436,6 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \end{lstlisting} This syntax closely corresponds to the code notation $\forall(A,B).\,x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)$. -So, the rule for parameterized types with the type notation $\forall A.\,F^{A}$ -is: -\[ -{\cal CH}(\forall A.\,F^{A})=\forall A.\,{\cal CH}(F^{A})\quad. -\] - Case classes and disjunctive types use \emph{names} for the types and their parts. However, those names only add convenience for programmers and do not affect the computational properties of types. The type @@ -447,9 +446,9 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru Then any type signature can be rewritten as a sequent that contains ${\cal CH}$-propositions only for the individual type parameters. -In this way, we see a correspondence between fully parametric type -signatures and logical sequents that express the proposition \textsf{``}the -type signature can be implemented\textsf{''}. This is the first half of the +In this way, we see a correspondence between a fully parametric type +signature and a logical sequent that expresses the statement \textsf{``}the +type signature can be implemented\textsf{''}. This is the first part of the Curry-Howard correspondence. Table~\ref{tab:ch-correspondence-type-notation-CH-propositions} @@ -467,7 +466,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru operator ($+$), so that type expressions such as $A+B\times C$ have the same operator precedence as in standard arithmetic. That is, $A+B\times C$ means $A+\left(B\times C\right)$. This convention makes type expressions -easier to reason about (for people familiar with arithmetic). +easier to read. \item The function type arrow ($\rightarrow$) groups weaker than the operators $+$ and $\times$, so that often-used types such as $A\rightarrow\bbnum 1+B$ (representing \lstinline!A => Option[B]!) or $A\times B\rightarrow C$ @@ -477,8 +476,9 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \item The type quantifiers group weaker than all other operators, so we can write types such as $\forall A.\,A\rightarrow A\rightarrow A$ without parentheses. This is helpful because type quantifiers are -most often placed outside a type expression. When this is not the -case, parentheses are necessary, e.g., in the type expression $\left(\forall A.\,A\rightarrow A\rightarrow A\right)\rightarrow\bbnum 1+\bbnum 1$. +most often placed at the top level of a type expression. When that +is not the case, parentheses are necessary, e.g., in the type expression +$\left(\forall A.\,A\rightarrow A\rightarrow A\right)\rightarrow\bbnum 1+\bbnum 1$. \end{itemize} \begin{table} \begin{centering} @@ -549,9 +549,8 @@ \subsubsection{Example \label{subsec:Example-ch-dupl-function}\ref{subsec:Exampl def delta[A](x: A): (A, A) = (x, x) \end{lstlisting} We find that the most general type of \lstinline!delta! is \lstinline!A => (A, A)!. -We also note that there is only one way of implementing a fully parametric -function with type signature \lstinline!A => (A, A)!: the function -must duplicate its given argument. +We also note that \lstinline!delta! seems to be the only way of implementing +a fully parametric function with type signature \lstinline!A => (A, A)!. We will use the letter $\Delta$ for the function \lstinline!delta!. In the type notation, the type signature of $\Delta$ is: @@ -651,7 +650,7 @@ \subsubsection{Example \label{subsec:Example-ch-notation-function-3}\ref{subsec: case classes. For the purposes of this example, let us choose names \lstinline!F1!, \lstinline!F2!, and \lstinline!F3!. Each of these case classes needs to have the same type parameter \lstinline!A!. -So we begin writing the code as: +So, we begin writing the code as: \begin{lstlisting} sealed trait F[A] final case class F1[A](...) extends F[A] @@ -669,7 +668,7 @@ \subsubsection{Example \label{subsec:Example-ch-notation-function-3}\ref{subsec: final case class F3[A](n: Int, f: Int => A) extends F[A] \end{lstlisting} The names \lstinline!n!, \lstinline!x1!, \lstinline!x2!, and \lstinline!f! -are chosen purely for convenience. +are chosen arbitrarily. \subsubsection{Example \label{subsec:Example-ch-notation-function-4}\ref{subsec:Example-ch-notation-function-4}} @@ -694,8 +693,8 @@ \subsubsection{Example \label{subsec:Example-ch-notation-function-4}\ref{subsec: \end{align*} We do not put parentheses around $\bbnum 1+A$ and $\bbnum 1+B$ because the function arrow ($\rightarrow$) groups weaker than the other type -operations. Parentheses around $\left(A\rightarrow B\right)$ are -required. +operations. But parentheses around $\left(A\rightarrow B\right)$ +are required. We will usually prefer to write type parameters in superscripts rather than under type quantifiers. So, for example, we will write $\text{id}^{A}\triangleq x^{:A}\rightarrow x$ @@ -853,8 +852,10 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul The proposition ${\cal CH}(X)$ is true if we can create a sequence of computed values such as \lstinline!x1!, \lstinline!x2!, ..., \lstinline!xN!, each using one of these eight code constructs, with -\lstinline!xN! having type $X$. So, each of the eight code constructs -will give a proof rule in the logic. +\lstinline!xN! having type $X$. + +So, each of the eight code constructs will give a proof rule in the +logic. It is important that there are only a finite number of allowed code constructions. This defines rigorously the concept of \textsf{``}fully parametric @@ -874,8 +875,8 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul can be translated into a combination of logic rules, which will produce a proof of the proposition ${\cal CH}(X)$. -In this way, we will get a correspondence between proofs of sequents -and fully parametric programs. This is the second half of the Curry-Howard +In this way, we will get a correspondence between fully parametric +programs and proofs of sequents. This is the second part of the Curry-Howard correspondence. In the following text, we will need to write ${\cal CH}$-propositions @@ -973,23 +974,27 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul The proof of $\Gamma\vdash\alpha\Rightarrow\beta$ depends on a proof of another sequent. So, the corresponding code must be a \emph{function} that takes a proof of the previous sequent as an argument and returns -a proof of the new sequent. By the CH correspondence, a proof of a -sequent corresponds to a code expression of the type given by the -goal of the sequent. That expression may use arguments of types corresponding -to the premises of the sequent. So, a proof of the sequent $\Gamma,\alpha\vdash\beta$ -is an expression \lstinline!exprB! of type $B$ that may use a given -value of type $A$ as well as any other arguments given previously. -Then we can write the proof code for the sequent $\Gamma\vdash\alpha\Rightarrow\beta$ +a proof of the new sequent. We call that function a \index{Curry-Howard correspondence!proof transformer}\index{proof transformer}\textbf{proof +transformer}. + +By the CH correspondence, a proof of a sequent corresponds to a code +expression of the type given by the goal of the sequent. That expression +may use arguments of types corresponding to the premises of the sequent. +So, a proof of the sequent $\Gamma,\alpha\vdash\beta$ is an expression +\lstinline!exprB! of type $B$ that may use a given value of type +$A$ as well as any other arguments given previously. Then we can +write the proof code for the sequent $\Gamma\vdash\alpha\Rightarrow\beta$ as the nameless function \lstinline!(x:A) => exprB!. This function has type $A\rightarrow B$ and requires us to already have a suitable expression \lstinline!exprB!. This exactly corresponds to the proof -rule \textsf{``}$\text{create function}$\textsf{''}. The proof code is: +rule \textsf{``}$\text{create function}$\textsf{''}. That rule\textsf{'}s proof transformer +is: \[ \text{Proof}\,\big(\Gamma\vdash{\cal CH}(A)\Rightarrow{\cal CH}(B)\big)=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,{\cal CH}(A)\vdash{\cal CH}(B)\big)_{\text{given }x^{:A}}\quad. \] -Here the subscript \textsf{``}given $x^{:A}$\textsf{''} indicates that the value -$x^{:A}$ is a known proof of the proposition ${\cal CH}(A)$. We -will see in Section~\ref{subsec:Example:-Proving-a-ch-proposition} +Here, the subscript \textsf{``}given $x^{:A}$\textsf{''} indicates that the value +$x^{:A}$ is a previously known proof of the proposition ${\cal CH}(A)$. +We will see in Section~\ref{subsec:Example:-Proving-a-ch-proposition} how premises with a known proof are used when extracting code from proofs. @@ -1040,7 +1045,7 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul \lstinline!t._1! and \lstinline!t._2! respectively, and the corresponding sequent proof rules are: \[ -\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\quad\quad. +\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad,\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\quad\quad. \] The proof code can be written as: \[ @@ -1068,8 +1073,8 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul \[ \frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create Left})\quad\quad\quad\quad\quad\frac{\Gamma\vdash\beta}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create Right})\quad\quad. \] -The corresponding proof code can be written using the case class names -\lstinline!Left! and \lstinline!Right! as: +The corresponding proof transformers can be written using the case +class names \lstinline!Left! and \lstinline!Right! as: \begin{align*} \text{Proof}\left(\Gamma\vdash\alpha\vee\beta\right) & =\text{Left}\,(\text{Proof}\left(\Gamma\vdash\alpha\right))\quad,\\ \text{Proof}\left(\Gamma\vdash\alpha\vee\beta\right) & =\text{Right}\,(\text{Proof}\left(\Gamma\vdash\beta\right))\quad. @@ -1151,8 +1156,9 @@ \subsection{Example: Proving a ${\cal CH}$-proposition and deriving code from values of types $A$ or $B$. So, the task is formulated as computing a value of type $F$ with \emph{no} previously defined values. This is written as the sequent $\Gamma\vdash{\cal CH}(F)$, where the set -$\Gamma$ of premises is empty ($\Gamma=\emptyset$). Rewriting this -sequent using the rules of Table~\ref{tab:ch-correspondence-type-notation-CH-propositions}, +$\Gamma$ of premises is empty (denoted by the \index{0@$\emptyset$ (empty set)}empty +set, $\Gamma=\emptyset$). Rewriting this sequent using the rules +of Table~\ref{tab:ch-correspondence-type-notation-CH-propositions}, we get: \begin{equation} \forall(\alpha,\beta).~\emptyset\vdash((\alpha\Rightarrow\alpha)\Rightarrow\beta)\Rightarrow\beta\quad,\label{eq:ch-example-sequent-2} @@ -1176,7 +1182,7 @@ \subsection{Example: Proving a ${\cal CH}$-proposition and deriving code from \frac{(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\beta}{\emptyset\vdash((\alpha\Rightarrow\alpha)\Rightarrow\beta)\Rightarrow\beta}\quad\text{(\textquotedblleft create function\textquotedblright)}\quad. \] We now need to prove the sequent $(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\beta$, -which we can write as $\Gamma_{1}\vdash\beta$ where we define $\Gamma_{1}\triangleq[(\alpha\Rightarrow\alpha)\Rightarrow\beta]$ +which we can write as $\Gamma_{1}\vdash\beta$ where we define $\Gamma_{1}\triangleq\{(\alpha\Rightarrow\alpha)\Rightarrow\beta\}$ to denote the set containing the single premise $(\alpha\Rightarrow\alpha)\Rightarrow\beta$. There are no proof rules that derive a sequent with a premise in the @@ -1236,7 +1242,7 @@ \subsection{Example: Proving a ${\cal CH}$-proposition and deriving code from \] The right-most leaf \textsf{``}$\text{use arg}$\textsf{''} corresponds to the code $f^{:(A\rightarrow A)\rightarrow B}$, where $f$ is the premise contained -in $\Gamma_{1}$. So we can write: +in $\Gamma_{1}$. So, we can write: \[ \text{Proof}\left(\Gamma_{1}\vdash(\alpha\Rightarrow\alpha)\Rightarrow\beta\right)_{\text{given }f}=f^{:(A\rightarrow A)\rightarrow B}\quad. \] @@ -1350,7 +1356,7 @@ \subsection{Example: Proving a ${\cal CH}$-proposition and deriving code from \subsection{The LJT algorithm\label{app:The-LJT-algorithm}} -The LJT algorithm resolves an important issue: namely, that the logic +The LJT algorithm solves an important problem: namely, that the logic rules in Table~\ref{tab:Proof-rules-of-constructive-and-boolean} do not provide an algorithm for finding a proof for a given sequent. In the previous section, we saw an example showing that searching @@ -1391,10 +1397,10 @@ \subsection{The LJT algorithm\label{app:The-LJT-algorithm}} and $A,B\vee C\vdash\alpha\Rightarrow((A\wedge B)\vee C)$. The rules give us no guidance for choosing $\alpha$ appropriately. -To see that the rules in Table~\ref{tab:Proof-rules-for-constructive-logic} -are not helpful for proof search, note that the rules \textsf{``}use function\textsf{''} +The rules in Table~\ref{tab:Proof-rules-for-constructive-logic} +are not helpful for proof search because the rules \textsf{``}use function\textsf{''} and \textsf{``}use \lstinline!Either!\textsf{''} require us to choose new unknown -propositions and to prove more complicated sequents than the ones +propositions and to prove sequents more complicated than the ones we had before. For instance, the rule \textsf{``}use function\textsf{''} gives a proof of $\Gamma\vdash\beta$ only if we first choose some other proposition $\alpha$ and prove the sequents $\Gamma\vdash\alpha$ and $\Gamma\vdash\alpha\Rightarrow\beta$. @@ -1496,9 +1502,9 @@ \subsubsection*{The LJ algorithm} \[ S_{6}\triangleq\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta,\alpha\vdash\alpha\quad. \] -This sequent follows from the \textsf{``}(Id)\textsf{''}axiom. There are no more sequents -to prove, so the proof of $S_{0}$ is finished. It can be drawn as -a \index{proof tree}\textbf{proof tree} like this: +This sequent follows from the \textsf{``}(Id)\textsf{''} axiom. There are no more +sequents to prove, so the proof of $S_{0}$ is finished. It can be +drawn as a \index{proof tree}\textbf{proof tree} like this: \[ \xymatrix{\xyScaleY{1.5pc}\xyScaleX{4pc} & & & (\text{Id})\\ \ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.5){S_{1}} & (\text{Left}\Rightarrow)\ar[r]\sp(0.5){S_{2}}\ar[ru]\sp(0.6){S_{3}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){S_{6}} & (\text{Id}) @@ -1548,6 +1554,7 @@ \subsubsection*{Extracting code from proofs} \frac{\Gamma\vdash A}{\Gamma\vdash{\color{blue}A\vee B}}~(\text{Right}\vee_{1})\quad & \quad\text{Proof}\,(\Gamma\vdash A\vee B)_{\text{given }p^{:\Gamma}}=\text{Proof}\,(\Gamma\vdash A)+\bbnum 0^{:B}\\ \frac{\Gamma\vdash B}{\Gamma\vdash{\color{blue}A\vee B}}~(\text{Right}\vee_{2})\quad & \quad\text{Proof}\,(\Gamma\vdash A\vee B)_{\text{given }p^{:\Gamma}}=\bbnum 0^{:A}+\text{Proof}\,(\Gamma\vdash B) \end{align*} +\medskip{} }% \end{minipage}}{\small\par} \par\end{centering} @@ -1571,7 +1578,7 @@ \subsubsection*{Extracting code from proofs} Since the leaves are axioms, let us write the code corresponding to each axiom of LJ: \begin{align*} - & \frac{}{\Gamma,X\vdash X}~(\text{Id})\quad:\quad\quad\text{Proof}\,(\Gamma,X\vdash X)_{\text{given }p^{:\Gamma},x^{:X}}=x\quad;\\ + & \frac{}{\Gamma,X\vdash X}~(\text{Id})\quad:\quad\quad\text{Proof}\,(\Gamma,X\vdash X)_{\text{given }p^{:\Gamma},\,x^{:X}}=x\quad;\\ & \frac{}{\Gamma\vdash\top}~(\text{True})\quad:\quad\quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\quad. \end{align*} Here we denote explicitly the values (such as $p$ and $x$) given @@ -1588,7 +1595,7 @@ \subsubsection*{Extracting code from proofs} $\gamma={\cal CH}(C)$. Then we can write: \begin{align*} & S_{3}\triangleq\beta\vdash\beta\quad,\quad\quad\text{Proof}\,(S_{3})_{\text{given }y^{:B}}=y\quad,\\ - & S_{6}\triangleq\gamma,\alpha\vdash\alpha\quad,\quad\quad\text{Proof}\,(S_{6})_{\text{given }q^{:C},x^{:A}}=x\quad. + & S_{6}\triangleq\gamma,\alpha\vdash\alpha\quad,\quad\quad\text{Proof}\,(S_{6})_{\text{given }q^{:C},\,x^{:A}}=x\quad. \end{align*} Note that the proof of $S_{6}$ does not use the first given value $q^{:C}$ (corresponding to the premise $\gamma$). @@ -1596,7 +1603,7 @@ \subsubsection*{Extracting code from proofs} We now shorten the proof tree by replacing the sequents $S_{3}$ and $S_{6}$ by their \textsf{``}evidence of proof\textsf{''}: \[ -\xymatrix{\xyScaleY{1.5pc}\xyScaleX{4pc} & & & \square\\ +\xymatrix{\xyScaleY{1.5pc}\xyScaleX{4.2pc} & & & \square\\ \ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.5){S_{1}} & (\text{Left}\Rightarrow)\ar[r]\sp(0.5){S_{2}}\ar[ru]\sp(0.6){(y)_{\text{given }y^{:B}}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){(x)_{\text{given }q^{:C},x^{:A}}} & \square } \] @@ -1605,18 +1612,17 @@ \subsubsection*{Extracting code from proofs} by applying the rule \textsf{``}($\text{Right}\Rightarrow$)\textsf{''}. This rule promises to give a proof of $S_{2}$ if we have a proof of $S_{6}$. In order to extract code from that rule, we can write a function that -transforms a proof of $S_{6}$ into a proof of $S_{2}$. We call this -function the \textbf{proof transformer}\index{Curry-Howard correspondence!proof transformer}\index{proof transformer} -corresponding to the rule \textsf{``}($\text{Right}\Rightarrow$)\textsf{''}. That -rule and its transformer are defined as: +transforms a proof of $S_{6}$ into a proof of $S_{2}$. That function +is the proof transformer corresponding to the rule \textsf{``}($\text{Right}\Rightarrow$)\textsf{''}. +That rule and its transformer are defined as: \begin{align*} \frac{\Gamma,A\vdash B}{\Gamma\vdash A\Rightarrow B}~(\text{Right}\Rightarrow)\quad: & \quad\quad\text{Proof}\,(\Gamma\vdash A\Rightarrow B)_{\text{given }p^{:\Gamma}}\\ - & \quad\quad=x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash B)_{\text{given }p^{:\Gamma},x^{:A}}\quad. + & \quad\quad=x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash B)_{\text{given }p^{:\Gamma},\,x^{:A}}\quad. \end{align*} Applying the proof transformer to the known proof of $S_{6}$, we obtain a proof of $S_{2}$: \[ -\text{Proof}\,(S_{2})_{\text{given }q^{:C}}=x^{:A}\rightarrow\text{Proof}\,(S_{6})_{\text{given }q^{:C},x^{:A}}=(x^{:A}\rightarrow x)_{\text{given }q^{:C}}\quad. +\text{Proof}\,(S_{2})_{\text{given }q^{:C}}=x^{:A}\rightarrow\text{Proof}\,(S_{6})_{\text{given }q^{:C},\,x^{:A}}=(x^{:A}\rightarrow x)_{\text{given }q^{:C}}\quad. \] The proof tree can be now shortened to: \[ @@ -1635,14 +1641,14 @@ \subsubsection*{Extracting code from proofs} & \quad\quad\text{where}\quad b^{:B}\triangleq q\big(\text{Proof}\,(\Gamma,A\Rightarrow B\vdash A)_{\text{given }p^{:\Gamma},q^{:A\rightarrow B}}\big)\quad. \end{align*} In the proof tree shown above, we obtain a proof of $S_{1}$ by applying -this proof transformer to the proofs of $S_{2}$ and $S_{3}$: +that proof transformer to the proofs of $S_{2}$ and $S_{3}$: \begin{align*} & \text{Proof}\,(S_{1})_{\text{given }q^{:C}}=\text{Proof}\,(S_{3})_{\text{given }b^{:B}}\text{ where }b^{:B}\triangleq q(\text{Proof}\,(S_{2}))_{\text{given }q^{:C}}\\ & \quad=b\text{ where }b^{:B}\triangleq q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}=q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}\quad. \end{align*} Substituting this proof into the proof tree, we shorten the tree to: \[ -\xymatrix{\xyScaleY{1.5pc}\xyScaleX{3.5pc}\ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}} & \square} +\xymatrix{\xyScaleY{1.5pc}\xyScaleX{5.5pc}\ar[r]\sp(0.35){S_{0}} & (\text{Right}\Rightarrow)\ar[r]\sp(0.65){q(x^{:A}\rightarrow x)_{\text{given }q^{:C}}} & \square} \] It remains to obtain the proof of $S_{0}$ by applying the proof transformer @@ -1651,8 +1657,8 @@ \subsubsection*{Extracting code from proofs} & \text{Proof}\,(S_{0})=\text{Proof}\,(\emptyset\vdash(\alpha\Rightarrow\alpha)\Rightarrow\beta)\Rightarrow\beta)\\ & =q^{:(A\rightarrow A)\rightarrow B}\rightarrow\text{Proof}\,(S_{1})_{\text{given }q^{:C}}=q^{:(A\rightarrow A)\rightarrow B}\rightarrow q(x^{:A}\rightarrow x)\quad. \end{align*} -The proof tree is now shortened to the code expression $q^{:(A\rightarrow A)\rightarrow B}\rightarrow q(x^{:A}\rightarrow x)$ -has type $\left(\left(A\rightarrow A\right)\rightarrow B\right)\rightarrow B$. +The proof tree is now shortened to just the code $q^{:(A\rightarrow A)\rightarrow B}\rightarrow q(x^{:A}\rightarrow x)$, +which has type $\left(\left(A\rightarrow A\right)\rightarrow B\right)\rightarrow B$. So, that code is an evidence of proof for $S_{0}$. In this way, we have derived the code of a fully parametric function from its type signature. @@ -1670,7 +1676,7 @@ \subsubsection*{The LJT algorithm} gives a sequent we already had at a previous step. That rule requires us to prove two new sequents: \[ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\quad\Gamma,B\vdash C}{\Gamma,A\Rightarrow B\vdash C}~(\text{Left}\Rightarrow)\quad. +\frac{\Gamma,A\Rightarrow B\vdash A\quad\quad\Gamma,B\vdash C}{\Gamma,A\Rightarrow B\vdash C}~(\text{Left}\Rightarrow)\quad\quad. \] A sign of trouble is that the first of these sequents ($\Gamma,A\Rightarrow B\vdash A$) does not have a simpler form than the initial sequent ($\Gamma,A\Rightarrow B\vdash C$). @@ -1785,6 +1791,7 @@ \subsubsection*{The LJT algorithm} & \quad\quad\quad\quad\quad\quad\quad\quad B\Rightarrow C\vdash A\Rightarrow B)_{\text{given }p,r}\big)\\ & \quad\quad\text{ and }r^{:B\rightarrow C}\triangleq b^{:B}\rightarrow q(\_^{:A}\rightarrow b) \end{align*} +\medskip{} }% \end{minipage}}{\small\par} \par\end{centering} @@ -2009,7 +2016,7 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi into a ${\cal CH}$-proposition: \begin{align} & \forall(\alpha,\beta,\gamma).\,\left(\alpha\Rightarrow\left(\beta\vee\gamma\right)\right)\Rightarrow\left(\left(\alpha\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\gamma\right)\right)\quad,\label{eq:abc-example-classical-logic-bad}\\ -\text{where we denoted}\quad & \alpha\triangleq{\cal CH}(A),\quad\beta\triangleq{\cal CH}(B),\quad\gamma\triangleq{\cal CH}(C)\quad.\nonumber +{\color{greenunder}\text{where we denoted}:}\quad & \alpha\triangleq{\cal CH}(A),\quad\beta\triangleq{\cal CH}(B),\quad\gamma\triangleq{\cal CH}(C)\quad.\nonumber \end{align} It turns out that this formula is true in Boolean logic. To prove this, we need to show that Eq.~(\ref{eq:abc-example-classical-logic-bad}) @@ -2027,7 +2034,7 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi to $\left(\alpha\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\gamma\right)$ in Boolean logic. -Let us also give a proof via truth-value reasoning. The only possibility +Let us also give a proof by truth-value reasoning. The only possibility for an implication $X\Rightarrow Y$ to be $False$ is when $X=True$ and $Y=False$. So, Eq.~(\ref{eq:abc-example-classical-logic-bad}) can be $False$ only if $\left(\alpha\Rightarrow(\beta\vee\gamma)\right)=True$ @@ -2089,7 +2096,7 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse \begin{equation} \forall(A,B,C).\,\left(A\vee B\right)\wedge C=\left(A\wedge C\right)\vee\left(B\wedge C\right)\quad.\label{eq:ch-example-distributive-1} \end{equation} -This formula is the well-known \textsf{``}distributive law\textsf{''}\footnote{See \texttt{\href{https://en.wikipedia.org/wiki/Distributive_property\#Rule_of_replacement}{https://en.wikipedia.org/wiki/Distributive\_property\#Rule\_of\_replacement}}} +This formula is a well-known distributive law\footnote{See \texttt{\href{https://en.wikipedia.org/wiki/Distributive_property\#Rule_of_replacement}{https://en.wikipedia.org/wiki/Distributive\_property\#Rule\_of\_replacement}}} valid in Boolean logic as well as in the constructive logic. Since a logical equation $P=Q$ means $P\Rightarrow Q$ and $Q\Rightarrow P$, the distributive law~(\ref{eq:ch-example-distributive-1}) means @@ -2111,12 +2118,10 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse \end{align*} Since the two logical formulas (\ref{eq:ch-example-distributive-1a})\textendash (\ref{eq:ch-example-distributive-1b}) are true theorems in constructive logic, we expect to be able to implement -the functions \lstinline!f1! and \lstinline!f2!. It is not straightforward -to guess how to combine the proof rules of Table~\ref{tab:Proof-rules-of-constructive-and-boolean} -to obtain proofs of Eqs.~(\ref{eq:ch-example-distributive-1a})\textendash (\ref{eq:ch-example-distributive-1b}). -So, instead of deriving the implementations of \lstinline!f1! and -\lstinline!f2! from the CH correspondence, we will write the Scala -code directly. +the functions \lstinline!f1! and \lstinline!f2!. We could use the +proof rules of the LJT algorithm to obtain proofs of Eqs.~(\ref{eq:ch-example-distributive-1a})\textendash (\ref{eq:ch-example-distributive-1b}) +and to derive implementations of \lstinline!f1! and \lstinline!f2!. +Instead, let us exercise our intuition and write the Scala code directly. To implement \lstinline!f1!, we need to perform pattern matching on the argument: @@ -2146,7 +2151,7 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse should be transformed by \lstinline!f2! and then by \lstinline!f1! back to the same value \lstinline!y!. -Let us write these conditions as equations: +Let us write those conditions as equations: \[ \forall x^{:(A+B)\times C}.\,f_{2}(f_{1}(x))=x\quad,\quad\quad\forall y^{:A\times C+B\times C}.\,f_{1}\left(f_{2}(y)\right)=y\quad. \] @@ -2165,8 +2170,8 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse Generally, we say that types $P$ and $Q$ are \textbf{equivalent} or \textbf{isomorphic} (denoted $P\cong Q$) \index{type equivalence}when there exist functions $f_{1}:P\rightarrow Q$ and $f_{2}:Q\rightarrow P$ -that are inverses of each other. We can write these conditions using -the notation $(f_{1}\bef f_{2})(x)\triangleq f_{2}(f_{1}(x))$ as: +that are inverses of each other. We can write that using the notation +$(f_{1}\bef f_{2})(x)\triangleq f_{2}(f_{1}(x))$ as: \[ f_{1}\bef f_{2}=\text{id}\quad,\quad\quad f_{2}\bef f_{1}=\text{id}\quad. \] @@ -2243,7 +2248,7 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse is also directly visible in the code: the nested tuple pattern \lstinline!((a, b), c)! is mapped to the pattern \lstinline!(a, (b, c))! and back. So, the types $\left(A\times B\right)\times C$ and $A\times\left(B\times C\right)$ -are equivalent, and we can write $A\times B\times C$ without parentheses. +are equivalent. We will often write $A\times B\times C$ without parentheses. Does a logical identity always correspond to an equivalence of types? This turns out to be \emph{not} so. A simple example of a logical @@ -2276,8 +2281,8 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse identity function, because the identity function does \emph{not} always return \lstinline!None!. -Another example of a logical identity without a type equivalence is -the distributive law: +Another example of a logical identity that does not correspond to +a type equivalence is the distributive law: \begin{equation} \forall(A,B,C).\,\left(A\wedge B\right)\vee C=\left(A\vee C\right)\wedge\left(B\vee C\right)\quad,\label{eq:ch-example-distributive-2} \end{equation} @@ -2336,8 +2341,8 @@ \subsection{Arithmetic identity corresponds to type equivalence} \] The logical identity in Eq.~(\ref{eq:ch-example-distributive-2}), which does \emph{not} yield a type equivalence, leads to an incorrect -arithmetic equation~\ref{eq:ch-example-incorrect-identity-2}, e.g., -$\left(1\times10\right)+20\neq\left(1+20\right)\times\left(10+20\right)$. +arithmetic equation~(\ref{eq:ch-example-incorrect-identity-2}), +e.g., $\left(1\times10\right)+20\neq\left(1+20\right)\times\left(10+20\right)$. Similarly, the associativity law~(\ref{eq:ch-example-associativity-conjunction}) leads to a type equivalence and to the arithmetic identity: \[ @@ -2345,7 +2350,7 @@ \subsection{Arithmetic identity corresponds to type equivalence} \] The logical identity in Eq.~(\ref{eq:ch-example-logic-identity-2}), which does not yield a type equivalence, leads to an incorrect arithmetic -statement ($\forall a.\,1+a=1$). +statement (\textsf{``}$1+a=1$ for all $a$\textsf{''}). Table~\ref{tab:Logical-identities-with-disjunction-and-conjunction} summarizes these and other examples of logical identities and the @@ -2599,8 +2604,8 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} or $\bbnum 0+B$. So, we may write the code of \lstinline!f1! as: \[ f_{1}\triangleq x^{:A+B}\rightarrow\begin{cases} -\text{if }x=a^{:A}+\bbnum 0^{:B}\quad: & \bbnum 0^{:B}+a^{:A}\\ -\text{if }x=\bbnum 0^{:A}+b^{:B}\quad: & b^{:B}+\bbnum 0^{:A} +\quad\text{if }x=a^{:A}+\bbnum 0^{:B}\quad: & \bbnum 0^{:B}+a^{:A}\\ +\quad\text{if }x=\bbnum 0^{:A}+b^{:B}\quad: & b^{:B}+\bbnum 0^{:A} \end{cases} \] Since both the argument and the result of $f_{1}$ are disjunctive @@ -2625,10 +2630,10 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} type of the argument. The columns of the matrix correspond to the parts of the disjunctive type of the result.\index{pattern matching!in matrix notation} The matrix element in row $A$ and column $A$ is a function of type -$A\rightarrow A$ that corresponds to the line \lstinline!case Left(a) => Right(a)! +$A\rightarrow A$ that corresponds to the line \lstinline!case Left(a) => Right(a)! in the Scala code. The matrix element in row $A$ and column $B$ is written as $\bbnum 0$ because no value of that type is returned. -In this way, we translate each line of the \lstinline!match / case! +In this way, we translate all lines of the \lstinline!match!/\lstinline!case! expression into a code matrix. The code of $f_{2}$ is written similarly. Let us rename arguments @@ -2831,10 +2836,10 @@ \subsection{Type cardinalities and type equivalence} In \lstinline!f1!, we could map \lstinline!None! to \lstinline!Left(false)! or to \lstinline!Left(true)! and adjust the rest of the code accordingly. The type equivalence holds with either choice. So, these types \emph{are} -equivalent, but there is no \textsf{``}natural\textsf{''} choice of the conversion -functions \lstinline!f1! and \lstinline!f2! that will work correctly -in all applications, because the meaning of these data types will -be application-dependent. We call this type equivalence \textbf{accidental}\index{type equivalence!accidental}. +equivalent, but there is no natural choice of the conversion functions +\lstinline!f1! and \lstinline!f2! because the meaning of those data +types will be application-dependent. We call this type equivalence +\textbf{accidental}\index{type equivalence!accidental}. \subsubsection{Example \label{subsec:ch-Example-cardinality-option-either}\ref{subsec:ch-Example-cardinality-option-either}\index{examples (with code)}} @@ -2925,7 +2930,7 @@ \subsection{Type equivalence involving function types} Nevertheless, the formula $\left|B\right|^{\left|A\right|}$ is useful since it shows the number of distinct functions that are possible in principle. When types $A$ and $B$ have only a small number of -distinct values (for example, $A=$ \lstinline!Option[Boolean]]! +distinct values (for example, with $A=$ \lstinline!Option[Boolean]]! and $B=$ \lstinline!Either[Boolean, Boolean]!), the formula $\left|B\right|^{\left|A\right|}$ gives an exact and practically relevant answer. @@ -2940,7 +2945,7 @@ \subsection{Type equivalence involving function types} no type equivalence is available for the type expression $A\rightarrow B+C$ (although there is an identity for $A\rightarrow B\times C$). Reasoning about types of the form $A\rightarrow B+C$ is more complicated because -those types usually cannot be transformed into simpler types. +those types usually cannot be rewritten as simpler types. \begin{table} \begin{centering} @@ -2993,7 +2998,7 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-f}\ref{subsec:ch-E The first function needs to produce a value of type \lstinline!A!, given an argument of the function type \lstinline!Unit => A!. The only possibility is to apply that function to the value of type \lstinline!Unit!. -We can always produce that value as \lstinline!()!: +We produce that value as \lstinline!()!: \begin{lstlisting} def f1[A]: (Unit => A) => A = (h: Unit => A) => h(()) \end{lstlisting} @@ -3310,7 +3315,7 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E \] Here we used the symbol $\triangleright$ to separate an argument from a function when the argument is written to the \emph{left} of -the function. The symbol $\triangleright$ (pronounced \textsf{``}pipe\textsf{''}\index{pipe notation}\index{triangleright-notation@$\triangleright$-notation!see \textsf{``}pipe notation\textsf{''}}) +the function. The symbol $\triangleright$ (pronounced \textsf{``}pipe\textsf{''}\index{pipe notation}\index{0@$\triangleright$-notation!see \textsf{``}pipe notation\textsf{''}}) is defined by $x\triangleright f\triangleq f(x)$. In Scala, this operation is available as \lstinline!x.pipe(f)! as of Scala 2.13. @@ -3324,13 +3329,13 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E With these notations, we compute further. Omit all terms applying $\bbnum 0$ or applying something to $\bbnum 0$: \begin{align*} - & \begin{array}{|cc|} + & h(a+\bbnum 0)=\,\begin{array}{|cc|} a & \bbnum 0\end{array}\,\triangleright\,h=\,\begin{array}{|cc|} a & \bbnum 0\end{array}\,\triangleright\,\begin{array}{||c|} p\\ q \end{array}\,=a\triangleright p=p(a)\quad,\\ - & \begin{array}{|cc|} + & h(\bbnum 0+b)=\,\begin{array}{|cc|} \bbnum 0 & b\end{array}\,\triangleright\,h=\,\,\begin{array}{|cc|} \bbnum 0 & b\end{array}\,\triangleright\,\begin{array}{||c|} p\\ @@ -3339,7 +3344,7 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E \end{align*} Now we can complete the proof of $f_{1}\bef f_{2}=\text{id}$: \begin{align*} -f_{1}\bef f_{2} & =h\rightarrow\,\begin{array}{||c|} + & f_{1}\bef f_{2}=h\rightarrow\,\begin{array}{||c|} a\rightarrow h(a+\bbnum 0)\\ b\rightarrow h(\bbnum 0+b) \end{array}\\ @@ -3366,11 +3371,11 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E g \end{array}\,\bigg)\bef\big(h\rightarrow(a\rightarrow(a+\bbnum 0)\triangleright h)\times(b\rightarrow(\bbnum 0+b)\triangleright h)\big)\\ {\color{greenunder}\text{composition}:}\quad & =f\times g\rightarrow\big(a\rightarrow\gunderline{\,\begin{array}{|cc|} -a & \bbnum 0\end{array}\,\triangleright}\,\begin{array}{||c|} +a & \bbnum 0\end{array}\,\,\triangleright}\,\begin{array}{||c|} f\\ g \end{array}\,\big)\times\big(b\rightarrow\gunderline{\,\begin{array}{|cc|} -\bbnum 0 & b\end{array}\,\triangleright}\,\begin{array}{||c|} +\bbnum 0 & b\end{array}\,\,\triangleright}\,\begin{array}{||c|} f\\ g \end{array}\,\big)\\ @@ -3574,8 +3579,7 @@ \subsection{Examples\index{examples (with code)}} \subsubsection{Example \label{subsec:ch-solvedExample-1}\ref{subsec:ch-solvedExample-1}} Find the cardinality of the type \lstinline!P = Option[Option[Boolean] => Boolean]!. -Write \lstinline!P! in the type notation and simplify it to an equivalent -type. +Write \lstinline!P! in the type notation. \subparagraph{Solution} @@ -3647,8 +3651,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-2a}\ref{subsec:ch-solvedEx \subparagraph{Solution} Begin by writing the given type in the type notation. The tuple becomes -the product type, and \lstinline!Either! becomes the disjunctive -(or \textsf{``}sum\textsf{''}) type: +a product type, and \lstinline!Either! becomes a disjunctive type: \[ P\triangleq(A+B)\times(C+D)\quad. \] @@ -3657,7 +3660,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-2a}\ref{subsec:ch-solvedEx \[ P\cong A\times C+A\times D+B\times C+B\times D\quad. \] -This is a disjunctive type having $4$ parts. +This is a disjunctive type with $4$ parts. \subsubsection{Example \label{subsec:ch-solvedExample-3}\ref{subsec:ch-solvedExample-3}} @@ -3667,10 +3670,10 @@ \subsubsection{Example \label{subsec:ch-solvedExample-3}\ref{subsec:ch-solvedExa \subparagraph{Solution} -Note that the arithmetic equalities do not hold, $A+A\neq A$ and -$A\times A\ne A$. This already indicates that the types are not equivalent. -To build further intuition, consider that a value of type $A+A$ (in -Scala, \lstinline!Either[A, A]!) is a \lstinline!Left(a)! or a \lstinline!Right(a)! +The arithmetic equalities do not hold, $A+A\neq A$ and $A\times A\ne A$. +This already indicates that the types are not equivalent. To build +further intuition, consider that a value of type $A+A$ (in Scala, +\lstinline!Either[A, A]!) is a \lstinline!Left(a)! or a \lstinline!Right(a)! for some \lstinline!a:A!. In the code notation, it is either $a^{:A}+\bbnum 0$ or $\bbnum 0+a^{:A}$. So, a value of type $A+A$ contains a value of type $A$ with the additional information about whether it is the @@ -3804,8 +3807,8 @@ \subsubsection{Example \label{subsec:ch-solvedExample-4}\ref{subsec:ch-solvedExa Given a value of type \lstinline!A!, we would need to return a value of type \lstinline!C!. The only way to obtain a value of type \lstinline!C! is by applying \lstinline!k! to some arguments. But to apply \lstinline!k!, -we need a value of type \lstinline!B!, which we do not have. So we -cannot produce a \lstinline!g: A => C!. Similarly, we cannot produce +we need a value of type \lstinline!B!, which we do not have. So, +we cannot produce a \lstinline!g: A => C!. Similarly, we cannot produce a function \lstinline!h! of type \lstinline!B => C!. We repeat the same argument in the type notation. Obtaining a value @@ -3819,9 +3822,9 @@ \subsubsection{Example \label{subsec:ch-solvedExample-4}\ref{subsec:ch-solvedExa The inverse type signature \emph{can} be implemented: \begin{lstlisting} -def f2[A,B,C]: Either[A=>C, B=>C] => ((A,B)) => C = { - case Left(g) => { case (a, b) => g(a) } - case Right(h) => { case (a, b) => h(b) } +def f2[A,B,C]: Either[A => C, B => C] => ((A, B)) => C = { + case Left(g) => { case (a, b) => g(a) } + case Right(h) => { case (a, b) => h(b) } } \end{lstlisting} \[ @@ -3929,13 +3932,13 @@ \subsubsection{Example \label{subsec:ch-solvedExample-5}\ref{subsec:ch-solvedExa \subparagraph{Solution} -Begin by defining a type alias for the type constructor $\text{Read}^{E,A}$: +Begin by defining a type alias for the type constructor $\text{Reader}^{E,A}$: \begin{lstlisting} -type Read[E, A] = E => A +type Reader[E, A] = E => A \end{lstlisting} The first type signature has only one implementation: \begin{lstlisting} -def p[E, A]: A => Read[E, A] = { x => _ => x } +def p[E, A]: A => Reader[E, A] = { x => _ => x } \end{lstlisting} We \emph{must} discard the argument of type $E$; we cannot use it for computing a value of type \lstinline!A! given \lstinline!x:A!. @@ -3943,7 +3946,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-5}\ref{subsec:ch-solvedExa The second type signature has three type parameters. It is the curried version of the function \lstinline!map!: \begin{lstlisting} -def map[E, A, B]: Read[E, A] => (A => B) => Read[E, B] = ??? +def map[E, A, B]: Reader[E, A] => (A => B) => Reader[E, B] = ??? \end{lstlisting} Expanding the type alias, we see that the two curried arguments are functions of types $E\rightarrow A$ and $A\rightarrow B$. The forward @@ -3970,7 +3973,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-5}\ref{subsec:ch-solvedExa To fill the typed hole $\text{???}^{:B}$, we need a value of type $B$. Since no arguments have type $B$, the only way of getting a value of type $B$ is to apply $f^{:A\rightarrow B}$ to some value -of type $A$. So we write: +of type $A$. So, we write: \[ \text{map}\triangleq r^{:E\rightarrow A}\rightarrow f^{:A\rightarrow B}\rightarrow e^{:E}\rightarrow f(???^{:A})\quad. \] @@ -3994,7 +3997,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-5}\ref{subsec:ch-solvedExa \subsubsection{Example \label{subsec:ch-solvedExample-6}\ref{subsec:ch-solvedExample-6}} -Show that the type signature \lstinline!Read[A, T] => (A => B) => Read[B, T]! +Show that the type signature \lstinline!Reader[A, T] => (A => B) => Reader[B, T]! cannot be implemented as a fully parametric function. \subparagraph{Solution} @@ -4168,7 +4171,7 @@ \subsubsection{Example \label{subsec:ch-solvedExample-8}\ref{subsec:ch-solvedExa For the type \lstinline!Either[L, R]! (in the type notation, $L+R$), we keep the type parameter $R$ fixed while $L$ is replaced by $M$. -So we obtain the type signatures: +So, we obtain the type signatures: \begin{align*} \text{map} & :L+R\rightarrow(L\rightarrow M)\rightarrow M+R\quad,\\ \text{flatMap} & :L+R\rightarrow(L\rightarrow M+R)\rightarrow M+R\quad. @@ -4571,8 +4574,8 @@ \subsection{Implications for designing new programming languages} and the eight standard code constructions (Section~\ref{subsec:The-rules-of-proof}). These constructions are foundational in the sense that they are used to express all design patterns of functional programming. A language -that does not directly support some of these constructions cannot -be considered a functional programming language. +that does not directly support all of those constructions cannot be +considered a functional programming language. A remarkable result of the CH correspondence is that the type system of any given programming language (functional or not) is mapped into @@ -4601,10 +4604,9 @@ \subsection{Implications for designing new programming languages} to compute a certain value (since the $\mathcal{CH}$-proposition was proved to be $True$) although that value is not actually available. In practice, such code will crash because of a value that has a wrong -type, is \textsf{``}null\textsf{''}, or is a pointer to an invalid memory location. -Those errors cannot happen in a programming language whose logic of -types is consistent and whose compiler checks all types at compile -time. +type or is \textsf{``}null\textsf{''} (a pointer to an invalid memory location). Those +errors cannot happen in a programming language whose logic of types +is consistent and whose compiler checks all types at compile time. So, the CH correspondence gives a mathematically justified procedure for designing new programming languages. The procedure has the following @@ -4646,12 +4648,11 @@ \subsection{Implications for designing new programming languages} It is possible to apply the FP paradigm while writing code in any programming language. However, some languages lack certain features that make FP techniques easier to use in practice. For example, in -a language such as JavaScript, Python, or Ruby, one can productively -use the map/reduce operations but not disjunctive types. More advanced -FP constructions (such as typeclasses) are impractical in these languages -because the required code becomes too hard to read and to write without -errors, which negates the advantages of rigorous reasoning about functional -programs. +a language such as C++ or Java, one can easily use the map/reduce +operations but not disjunctive types. More advanced FP constructions +(such as typeclasses) are impractical in those languages: the required +code becomes too hard to read and to write without errors, which negates +the advantages of rigorous reasoning about functional programs. Some programming languages, such as Haskell and OCaml, were designed specifically for advanced use in the FP paradigm. Other languages, @@ -4665,11 +4666,10 @@ \subsection{Implications for designing new programming languages} \subsection{Practical uses of the void type (Scala\textsf{'}s \texttt{Nothing})} -The \index{void type}void type\footnote{The \textsf{``}void\textsf{''} type as defined in this book is a type with no values. -It is \emph{not} the same as the \lstinline!void! keyword in Java -or C that denotes functions returning \textsf{``}no value\textsf{''}. Those functions -are equivalent to Scala functions returning the \lstinline!Unit! -type.} (Scala\textsf{'}s \lstinline!Nothing!) corresponds to the logical constant +The \index{void type}void type\footnote{The \textsf{``}void\textsf{''} type is a type with no values. It is \emph{not} the +same as the \lstinline!void! keyword in Java or C that denotes functions +returning \textsf{``}no value\textsf{''}. Those functions are equivalent to Scala +functions returning the (unique) value of \lstinline!Unit! type.} (Scala\textsf{'}s \lstinline!Nothing!) corresponds to the logical constant $False$. (The proposition \textsf{``}\emph{the code can compute a value of the void type}\textsf{''} is always false.) The void type is used in some theoretical proofs but has few practical uses. One use case is for @@ -4699,7 +4699,7 @@ \subsection{Practical uses of the void type (Scala\textsf{'}s \texttt{Nothing})} This book does not discuss exceptions in much detail. The functional programming paradigm does not use exceptions because their presence -significantly complicates reasoning about code. +prevents mathematical reasoning about code. As another example of using the void type, suppose an external library implements a function: @@ -4727,9 +4727,9 @@ \subsection{Practical uses of the void type (Scala\textsf{'}s \texttt{Nothing})} \[ \neg\alpha\triangleq(\alpha\Rightarrow False)\quad. \] -Its practical use is as limited as that of $False$ and the void type. -However, logical negation plays an important role in Boolean logic, -which we will discuss next. +Its practical use in functional programming is as limited as that +of $False$ and the void type. However, logical negation plays an +important role in Boolean logic. \subsection{Relationship between Boolean logic and constructive logic\label{subsec:Relationship-between-Boolean} } @@ -4739,7 +4739,7 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs not hold in the constructive logic. However, as we will now show, any theorem of constructive logic is also a theorem of Boolean logic. The reason is that all eight rules of constructive logic (Section~\ref{subsec:The-rules-of-proof}) -are also true in Boolean logic. +also hold in Boolean logic. To verify that a formula is true in Boolean logic, it is sufficient to check that the value of the formula is $True$ for all possible @@ -4775,9 +4775,9 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs \hline {\small{}$\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)$} & {\small{}$\left(\neg\Gamma\vee\left(\alpha\wedge\beta\right)\right)\Rightarrow\left(\neg\Gamma\vee\alpha\right)$}\tabularnewline \hline -{\small{}$\frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create Left})$} & {\small{}$\left(\neg\Gamma\vee\alpha\right)\Rightarrow\left(\neg\Gamma\vee\left(\alpha\vee\beta\right)\right)$}\tabularnewline +{\small{}$\frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Left}})$} & {\small{}$\left(\neg\Gamma\vee\alpha\right)\Rightarrow\left(\neg\Gamma\vee\left(\alpha\vee\beta\right)\right)$}\tabularnewline \hline -{\small{}$\frac{\Gamma\vdash\alpha\vee\beta\quad\Gamma,\alpha\vdash\gamma\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use Either})$} & {\small{}$\left(\neg\Gamma\vee\alpha\vee\beta\right)\wedge\left(\neg\Gamma\vee\neg\alpha\vee\gamma\right)\quad\quad$}\tabularnewline +{\small{}$\frac{\Gamma\vdash\alpha\vee\beta\quad\Gamma,\alpha\vdash\gamma\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use \texttt{Either}})$} & {\small{}$\left(\neg\Gamma\vee\alpha\vee\beta\right)\wedge\left(\neg\Gamma\vee\neg\alpha\vee\gamma\right)\quad\quad$}\tabularnewline & $\quad\quad\wedge\left(\neg\Gamma\vee\neg\beta\vee\gamma\right)\Rightarrow\left(\neg\Gamma\vee\gamma\right)$\tabularnewline \hline \end{tabular} @@ -4792,8 +4792,8 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs check. So, it remains to verify the formula in case $\Gamma=True$, and then we can simply omit all instances of $\neg\Gamma$ in the formulas. Let us show the Boolean derivations for the rules \textsf{``}$\text{use function}$\textsf{''} -and \textsf{``}$\text{use Either}$\textsf{''}; other formulas are checked in a similar -way: +and \textsf{``}use~\lstinline!Either!\textsf{''}; other formulas are checked in +a similar way: \begin{align*} {\color{greenunder}\text{formula \textsf{``}use function\textsf{''}}:}\quad & \left(\alpha\wedge\left(\alpha\Rightarrow\beta\right)\right)\Rightarrow\beta\\ {\color{greenunder}\text{use Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:}\quad & =\gunderline{\neg}(\alpha\,\gunderline{\wedge}\,(\neg\alpha\,\gunderline{\vee}\,\beta))\vee\beta\\ @@ -4804,7 +4804,7 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs {\color{greenunder}\text{axiom \textsf{``}use arg\textsf{''}}:}\quad & =True\quad. \end{align*} \begin{align*} -{\color{greenunder}\text{formula \textsf{``}use Either\textsf{''}}:}\quad & \left(\left(\alpha\vee\beta\right)\wedge\left(\alpha\Rightarrow\gamma\right)\wedge\left(\beta\Rightarrow\gamma\right)\right)\Rightarrow\gamma\\ +{\color{greenunder}\text{formula \textsf{``}use \texttt{Either}\textsf{''}}:}\quad & \left(\left(\alpha\vee\beta\right)\wedge\left(\alpha\Rightarrow\gamma\right)\wedge\left(\beta\Rightarrow\gamma\right)\right)\Rightarrow\gamma\\ {\color{greenunder}\text{use Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:}\quad & =\neg\left(\left(\alpha\vee\beta\right)\wedge\left(\neg\alpha\vee\gamma\right)\wedge\left(\neg\beta\vee\gamma\right)\right)\vee\gamma\\ {\color{greenunder}\text{de Morgan\textsf{'}s laws}:}\quad & =\left(\neg\alpha\wedge\neg\beta\right)\vee\gunderline{\left(\alpha\wedge\neg\gamma\right)}\vee\gunderline{\left(\beta\wedge\neg\gamma\right)}\vee\gamma\\ {\color{greenunder}\text{identity }p\vee(\neg p\wedge q)=p\vee q:}\quad & =\gunderline{\left(\neg\alpha\wedge\neg\beta\right)\vee\alpha}\vee\beta\vee\gamma\\ @@ -4865,10 +4865,11 @@ \subsection{The constructive logic and the law of excluded middle} requires getting used to. Reasoning in the constructive logic must use the axioms and derivation rules directly, instead of truth tables. -The reason Boolean logic can use truth tables is that every Boolean -proposition is either $True$ or $False$. This can be written as -the formula $\forall\alpha.\,(\neg\alpha\vee\alpha=True)$. Table~\ref{tab:Proof-rules-of-constructive-and-boolean} -uses the Boolean identity $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$, +The Boolean logic can use truth tables because every Boolean proposition +may be assumed in advance to be either $True$ or $False$. This can +be written as the formula $\forall\alpha.\,(\neg\alpha\vee\alpha=True)$. +Table~\ref{tab:Proof-rules-of-constructive-and-boolean} uses the +Boolean identity $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$, which does not hold in the constructive logic, to translate the constructive axiom \textsf{``}$\text{use arg}$\textsf{''} into the Boolean axiom $\neg\alpha\vee\alpha=True$. The formula $\forall\alpha.\,\neg\alpha\vee\alpha=True$ is known @@ -4890,13 +4891,14 @@ \subsection{The constructive logic and the law of excluded middle} itself $\bbnum 0$. But we do not know in advance whether $A=\bbnum 0$. Since there are no values of type $\bbnum 0$, and the type parameter $A$ could be, say, \lstinline!Int!, we cannot compute a value of -type $A\rightarrow\bbnum 0$. - -Why is it impossible to implement a value of the type $\left(A\rightarrow\bbnum 0\right)+A$? -Surely, the type $A$ is either void or not void. If $A$ is void -then $\left(A\rightarrow\bbnum 0\right)\cong\bbnum 1$ is not void -(as Example~\ref{subsec:ch-Example-type-identity-A-0} shows). So, -one of the types in the disjunction $\left(A\rightarrow\bbnum 0\right)+A$ +type $A\rightarrow\bbnum 0$. For similar reasons, we cannot compute +a value of type $A$ either. + +Is it really impossible to implement a value of the type $\left(A\rightarrow\bbnum 0\right)+A$? +We could reason like this: the type $A$ is either void or not void. +If $A$ is void then $\left(A\rightarrow\bbnum 0\right)\cong\bbnum 1$ +is not void (as Example~\ref{subsec:ch-Example-type-identity-A-0} +shows). So, one of the types in the disjunction $\left(A\rightarrow\bbnum 0\right)+A$ should be non-void and have values that we can compute. While this argument is true, it does not help implementing a value diff --git a/sofp-src/sofp-disjunctions.lyx b/sofp-src/sofp-disjunctions.lyx index 5b538990c..b89302626 100644 --- a/sofp-src/sofp-disjunctions.lyx +++ b/sofp-src/sofp-disjunctions.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -320,7 +320,15 @@ case classes \end_layout \begin_layout Section -Scala's case classes +Scala's +\begin_inset Quotes eld +\end_inset + +case classes +\begin_inset Quotes erd +\end_inset + + \end_layout \begin_layout Subsection @@ -391,7 +399,7 @@ restaurant \begin_inset Quotes erd \end_inset -) // Payment amount and payee. +) // The amount paid and the payee. \end_layout \begin_layout Plain Layout @@ -578,11 +586,10 @@ tuples with names \end_inset . - A case class is equivalent to a tuple type that has a name chosen when - we define the case class. - Also, each part of the case class will have a separate name that we must - choose. - This is how to define case classes for the example with socks and payments: + A case class is equivalent to a tuple type that has a name designating + the type and a separate name for each part of the case class. + This is how we might define case classes for the example with socks and + payments: \begin_inset listings inline false status open @@ -1354,7 +1361,11 @@ s: MySockX[String] = MySockX(10.5,white,last pair) \end_inset -However, we can write + +\end_layout + +\begin_layout Standard +We can write \series bold parametric code \series default @@ -1619,14 +1630,15 @@ scala> fits[Int](MySockX(10.5, "blue", List(1,2,3))) Case classes may have several type parameters, and the types of the parts may use these type parameters. Here is an artificial example of a case class using type parameters in - different ways, + different ways: \begin_inset listings inline false status open \begin_layout Plain Layout -case class Complicated[A,B,C,D](x: (A, A), y: (B, Int) => A, z: C => C) +case class Complicated[A, B, C, D](x: (A, A), y: (B, Int) => A, z: C => + C) \end_layout \end_inset @@ -2631,21 +2643,8 @@ case $pattern$ => ... \end_layout \begin_layout Standard -Case classes can be used in both situations. - A destructuring definition can be used in a function whose argument is - of case class type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -BagOfSocks -\end_layout - -\end_inset - -: +In both situations, case classes can be used as patterns. + The following code is an example of a destructuring definition: \begin_inset listings inline false status open @@ -2776,7 +2775,7 @@ bag \end_inset - is matched with the pattern expression + is matched against the pattern expression \begin_inset listings inline true status open @@ -2813,7 +2812,7 @@ Double \end_inset - and assign its value to the corresponding part of the case class. + and assign the corresponding part of the case class to that variable. For example, the value \begin_inset listings inline true @@ -2853,7 +2852,7 @@ status open \begin_layout Plain Layout -size +10.5 \end_layout \end_inset @@ -2865,13 +2864,13 @@ status open \begin_layout Plain Layout -10.5 +size \end_layout \end_inset . - The symbol + The symbols \begin_inset Quotes eld \end_inset @@ -2891,19 +2890,18 @@ _ \begin_inset Quotes erd \end_inset - means that we just ignore other parts of the case classes and do not create - any pattern variables for them (because we do not need them in this specific - code). + mean that we just ignore other parts of the case classes and do not create + any pattern variables for them (because we do not need them in this code). \end_layout \begin_layout Standard The syntax for pattern matching for case classes is similar to the syntax - for pattern matching for tuples, except for the presence of the + for pattern matching for tuples, except for the presence of \emph on names \emph default of the case classes. - For example, by removing the case class names from the pattern + For example, by removing the case class names from the pattern: \begin_inset listings inline false status open @@ -2915,7 +2913,7 @@ case BagOfSocks(MySock(size, _), _) => ... \end_inset -we obtain the nested tuple pattern +we obtain a nested tuple pattern: \begin_inset listings inline false status open @@ -3177,7 +3175,7 @@ status open \end_inset -, or +, or a \begin_inset listings inline true status open @@ -3189,7 +3187,7 @@ Double \end_inset -, or the tuple + value, or a tuple of type \begin_inset listings inline true status open @@ -3216,7 +3214,7 @@ SearchResult \end_inset - must be either + must be either an \begin_inset listings inline true status open @@ -3228,7 +3226,7 @@ Int \end_inset - or the empty tuple + value or the empty tuple \begin_inset listings inline true status open @@ -3279,11 +3277,11 @@ String \end_inset - message + error message \end_layout \begin_layout Standard -We see that the empty tuple, also known as the +We see that the empty tuple, i.e., the \begin_inset listings inline true status open @@ -3394,7 +3392,7 @@ index \begin_inset Quotes erd \end_inset - with value + with an \begin_inset listings inline true status open @@ -3406,7 +3404,7 @@ Int \end_inset -, or + value, or \begin_inset Quotes eld \end_inset @@ -3620,8 +3618,8 @@ Error(message: String) \end_layout \begin_layout Standard -Our three examples are now described as types that select one case class - out of a given set. +Our three examples are now described as types that allow us to select one + case class out of a given set. It remains to see how Scala defines such types. For instance, the definition of \begin_inset listings @@ -4149,7 +4147,7 @@ status open \begin_layout Plain Layout -def f(r: RootsOfQ): String = r match { +def print(r: RootsOfQ): String = r match { \end_layout \begin_layout Plain Layout @@ -4202,7 +4200,7 @@ real roots: ($x, $y) \begin_layout Plain Layout -scala> f(x) +scala> print(x) \end_layout \begin_layout Plain Layout @@ -5676,7 +5674,19 @@ def mul(rx: Result[Int], ry: Result[Int]): Result[Int] = (rx, ry) match \end_inset -To avoid repetition, we may define a general function that +To avoid repetition, we may define a general function ( +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +map2 +\end_layout + +\end_inset + +) that \begin_inset Quotes eld \end_inset @@ -5684,7 +5694,7 @@ maps \begin_inset Quotes erd \end_inset - operations on integers to operations on + binary operations on integers to operations on \begin_inset listings inline true status open @@ -5903,6 +5913,12 @@ res13: Result[Int] = Error(error: sqrt(-1)) \end_layout \begin_layout Subsection +\begin_inset CommandInset label +LatexCommand label +name "subsec:Standard-disjunctive-types:" + +\end_inset + Standard disjunctive types: \family typewriter Option @@ -6144,7 +6160,7 @@ Nothing \emph on no \emph default - values (also called the + values, also called the \series bold void \series default @@ -6162,7 +6178,7 @@ void type|textit \end_inset -, unlike Java or C's + (not to be confused with Java or C's \begin_inset listings inline true status open @@ -6174,7 +6190,7 @@ void \end_inset - keyword). + keyword!). The special type annotation \begin_inset listings inline true @@ -6922,7 +6938,19 @@ lifting \end_inset - a given function of type + a given function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f +\end_layout + +\end_inset + + of type \begin_inset listings inline true status open @@ -6934,7 +6962,7 @@ A => B \end_inset - to the type + to a new function of type \begin_inset listings inline true status open @@ -7842,8 +7870,7 @@ noprefix "false" \end_inset -: if the country code is not present, we should return the default country - code +: if the country code is not present, return the default country code \begin_inset Formula $1$ \end_inset @@ -7907,7 +7934,7 @@ res3: Int = 1 \end_inset -So we can implement the new requirement as: +So, we can implement the new requirement as: \begin_inset listings inline false status open @@ -7936,7 +7963,7 @@ Option \end_layout \begin_layout Standard -Many Scala library methods return an +Several Scala library methods return an \begin_inset listings inline true status open @@ -7949,7 +7976,7 @@ Option \end_inset as a result. - The main examples are + Examples are \begin_inset listings inline true status open @@ -8034,7 +8061,7 @@ res0: Option[Int] = Some(6) \begin_layout Plain Layout -scala> (1 to 10).find(_ > 10) // No element is > 10. +scala> (1 to 10).find(_ > 100) // No element is > 100. \end_layout \begin_layout Plain Layout @@ -8316,22 +8343,6 @@ scala> Map(10 -> "a", 20 -> "b")(30) java.util.NoSuchElementException: key not found: 30 \end_layout -\begin_layout Plain Layout - - at scala.collection.MapLike$class.default(MapLike.scala:228) -\end_layout - -\begin_layout Plain Layout - - at scala.collection.AbstractMap.default(Map.scala:59) -\end_layout - -\begin_layout Plain Layout - - ... - 32 elided -\end_layout - \end_inset Similarly, @@ -8347,7 +8358,7 @@ lift \end_inset is a safe by-index access to collections, unlike the direct access that - may fail: + may fail with an exception: \begin_inset listings inline false status open @@ -8376,22 +8387,6 @@ scala> Seq(10,20,30)(5) java.lang.IndexOutOfBoundsException: 5 \end_layout -\begin_layout Plain Layout - - at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65) -\end_layout - -\begin_layout Plain Layout - - at scala.collection.immutable.List.apply(List.scala:84) -\end_layout - -\begin_layout Plain Layout - - ... - 32 elided -\end_layout - \end_inset @@ -8632,57 +8627,34 @@ Option \end_inset - for computations that may fail? A failing computation such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -\begin_inset Quotes eld -\end_inset - -xyz -\begin_inset Quotes erd -\end_inset - -.toInt -\end_layout - -\end_inset - - cannot return a result, and sometimes we might use + for computations that may fail? When a missing result is an error, we will + usually need to know the reason why the result is unavailable. + The \begin_inset listings inline true status open \begin_layout Plain Layout -None +Either \end_layout \end_inset - to indicate that a result is not available. - However, when the result is a requirement for further calculations, we - will usually need to know exactly -\emph on -which -\emph default - error prevented the result from being available. - The + type may provide detailed information about such errors, which \begin_inset listings inline true status open \begin_layout Plain Layout -Either +Option \end_layout \end_inset - type may provide detailed information about such errors, which + cannot do. + An \begin_inset listings inline true status open @@ -8694,8 +8666,11 @@ Option \end_inset - cannot do. - + type is mostly used in cases where the absence of a result is +\emph on +not +\emph default + an error. \end_layout \begin_layout Standard @@ -8983,7 +8958,7 @@ noprefix "false" \end_inset -), or if a stack overflow occurs during the computation (as we saw in Section +), or if a stack overflow occurs during the computation (see Section \begin_inset space ~ \end_inset @@ -8998,7 +8973,7 @@ noprefix "false" \end_inset ). - Exceptions may also occur due to programmer's error: when a pattern matching + Exceptions may also occur due to programmer's errors: when a pattern matching operation fails, when a requested key does not exist in a dictionary, or when the \begin_inset listings @@ -9318,11 +9293,7 @@ Throwable \end_inset - is the general type of all exceptions (i.e. -\begin_inset space ~ -\end_inset - -values to which a + is the general type of all exceptions (i.e., values to which a \begin_inset listings inline true status open @@ -9552,7 +9523,7 @@ t: Throwable \end_inset - is the value containing the details about the exception. + is a value containing details about the exception. Here is an example of using \begin_inset listings inline true @@ -9654,7 +9625,7 @@ throw \end_inset - an exception can be enclosed in a + a planned exception can be enclosed in a \begin_inset listings inline true status open @@ -10497,7 +10468,7 @@ A \end_inset . - So we could define + So, we could define \begin_inset listings inline true status open @@ -11520,7 +11491,7 @@ status open \begin_layout Plain Layout -head:A +head: A \end_layout \end_inset @@ -11532,7 +11503,7 @@ status open \begin_layout Plain Layout -tail:List[A] +tail: List[A] \end_layout \end_inset @@ -11576,11 +11547,8 @@ f \end_inset to the head value, which will give the first element of the resulting list. - The remaining elements are computed by the induction assumption, i.e. -\begin_inset space ~ -\end_inset - -by a recursive call to + The remaining elements are computed by the induction assumption, i.e., by + a recursive call to \begin_inset listings inline true status open @@ -11781,7 +11749,7 @@ init \end_inset . - So we apply + So, we apply \begin_inset listings inline true status open @@ -12587,21 +12555,7 @@ foldLeft \end_inset - method (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Tail-recursion-with-list" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -): + method: \begin_inset listings inline false status open @@ -12725,7 +12679,7 @@ NEL[A] must be non-empty. It seems that we need to handle the case of a one-element list separately. - So we begin by matching on the argument of + So, we begin by matching on the argument of \begin_inset listings inline true status open @@ -12775,7 +12729,7 @@ def reverse[A]: NEL[A] => NEL[A] = { \begin_layout Plain Layout - foldLeft(tail)(Last(x): NEL[A])((prev,x) => More(x, prev)) + foldLeft(tail)(Last(x): NEL[A])((prev, x) => More(x, prev)) \end_layout \begin_layout Plain Layout @@ -13995,7 +13949,7 @@ A \end_inset . - So we can rewrite the above definition as: + So, we can rewrite the above definition as: \begin_inset listings inline false status open @@ -15963,17 +15917,18 @@ status open \begin_layout Plain Layout -def div(x: Either[String, Int], y: Either[String, Int]): +def div(x: Either[String, Int], y: Either[String, Int]): Either[String, + Int] = \end_layout \begin_layout Plain Layout - Either[String, Int] = x.flatMap { r1 => y.flatMap(r2 => + x.flatMap { r1 => y.flatMap { r2 => \end_layout \begin_layout Plain Layout - if (r2 == 0) Left(s + if (r2 == 0) Left(s \begin_inset Quotes eld \end_inset @@ -15981,12 +15936,17 @@ error: $r1 / $r2 \begin_inset Quotes erd \end_inset -) else Right(r1 / r2) ) +) else Right(r1 / r2) \end_layout \begin_layout Plain Layout -} + } +\end_layout + +\begin_layout Plain Layout + + } \end_layout \end_inset @@ -16366,8 +16326,8 @@ DayOfWeek \end_inset - so that the values additionally represent names of restaurants, the total - amount for Fridays, and the wake-up time on Saturdays. + so that on Fridays the values additionally represent names of restaurants + and amounts paid, and on Saturdays a wake-up time. \end_layout \begin_layout Subparagraph @@ -16574,9 +16534,8 @@ final case class TwoRootsQ(x: Double, y: Double) extends RootsOfQ2 \end_inset -This disjunctive type contains six parts, among which three parts are empty - tuples and two parts are single-element tuples; but this is not a useless - redundancy. +This disjunctive type contains six parts: three parts are empty tuples and + two parts are single-element tuples; but this is not a useless redundancy. We would lose information if we reused \begin_inset listings inline true @@ -16617,7 +16576,7 @@ NoRoots() \end_inset - for representing all three different no-roots cases. + for all three different no-roots cases. \end_layout \begin_layout Subsubsection @@ -17750,7 +17709,7 @@ B \end_inset . - So we have two possibilities: to return + So, we have two possibilities: to return \begin_inset listings inline true status open @@ -17892,7 +17851,7 @@ a: A \end_inset -, i.e., we will lose information. +, which loses information. \begin_inset Index idx status open @@ -17902,7 +17861,7 @@ information loss \end_inset - So we return + So, we return \begin_inset listings inline true status open @@ -18493,7 +18452,7 @@ None \end_inset . - So we can simplify the code: + So, we can simplify the code: \begin_inset listings inline false status open @@ -19629,7 +19588,7 @@ noprefix "false" . The point, the line, and the plane do not intersect (i.e., have no common - points. + points). Together, they form the set of the possible roots of the quadratic equation \begin_inset Formula $x^{2}+bx+c=0$ @@ -19914,7 +19873,7 @@ because \end_inset -For instance, this representation has no distinction between +For instance, this representation has no distinction between the cases \begin_inset listings inline true status open @@ -19982,8 +19941,8 @@ TwoRoots . To represent this mathematically, we can attach a distinct label to each part of the union. - Labels are symbols without any special meaning, and we can just assume - that labels are names of Scala case classes. + Labels are symbols without any special meaning, and we can assume that + labels are names of Scala case classes. Parts of the union are then represented by sets of pairs such as \begin_inset Formula $(\text{\texttt{OneRoot}},x)_{x\in\mathbb{R}^{1}}$ \end_inset @@ -20289,7 +20248,7 @@ NoRoots \end_inset . - For this reason, they can be viewed as + For this reason, this book calls them \begin_inset Quotes eld \end_inset @@ -20396,7 +20355,8 @@ union { int x; double y; long z; } i_d_l; \end_inset -This type does not include any label telling us which of the values is present. +This type does not include any labels telling us which of the values is + present. Without a label, we (and the compiler) will not know whether a given value of type \begin_inset listings @@ -20746,7 +20706,7 @@ noprefix "false" will introduce a mathematical notation designed for efficient reasoning about types. - That notation is even more concise than Haskell or OCaml. + That notation is even more concise than the syntax of Haskell or OCaml. \end_layout \begin_layout Subsection @@ -20965,12 +20925,12 @@ here \begin_inset Quotes erd \end_inset - we mean a particular point in a program. + we mean a particular scope in a program. So, the proposition \begin_inset Quotes eld \end_inset -the function's body +the code \emph on can \emph default @@ -21037,7 +20997,7 @@ TwoRoots(x: Double, y: Double) \end_inset . - We have a value of type + We can have a value of type \begin_inset listings inline true status open @@ -21117,7 +21077,7 @@ disjunctive types status open \begin_layout Plain Layout -Disjunctive types are also called variants, sum types, co-product types, +Disjunctive types are also called sum types, co-product types, variants, and tagged unions. This book uses the terms \begin_inset Quotes eld diff --git a/sofp-src/sofp-disjunctions.tex b/sofp-src/sofp-disjunctions.tex index 6c500549c..dc030598a 100644 --- a/sofp-src/sofp-disjunctions.tex +++ b/sofp-src/sofp-disjunctions.tex @@ -7,7 +7,7 @@ \chapter{The logic of types. I. Disjunctive types\label{chap:Disjunctive-types}} To see how Scala implements disjunctive types, we need to begin by looking at \textsf{``}case classes\textsf{''}. -\section{Scala\textsf{'}s case classes} +\section{Scala\textsf{'}s \textquotedblleft case classes\textquotedblright} \subsection{Tuple types with names} @@ -21,7 +21,7 @@ \subsection{Tuple types with names} \begin{lstlisting} def totalAmountPaid(ps: Seq[(Double, String)]): Double = ps.map(_._1).sum val x = (10.5, "white") // Sock size and color. -val y = (25.0, "restaurant") // Payment amount and payee. +val y = (25.0, "restaurant") // The amount paid and the payee. scala> totalAmountPaid(Seq(x, y)) // Nonsense. res0: Double = 35.5 @@ -59,9 +59,9 @@ \subsection{Tuple types with names} Scala\textsf{'}s \textbf{case classes}\index{case class} can be seen as \textsf{``}tuples with names\textsf{''}. A case class is equivalent to a tuple type that has -a name chosen when we define the case class. Also, each part of the -case class will have a separate name that we must choose. This is -how to define case classes for the example with socks and payments: +a name designating the type and a separate name for each part of the +case class. This is how we might define case classes for the example +with socks and payments: \begin{lstlisting} case class MySock(size: Double, color: String) case class Payment(amount: Double, name: String) @@ -195,8 +195,9 @@ \subsection{Case classes with type parameters} scala> val s = MySockX[String](10.5, "white", "last pair") s: MySockX[String] = MySockX(10.5,white,last pair) \end{lstlisting} -However, we can write \textbf{parametric code}\index{parametric code} -working with \lstinline!MySockX[A]!, that is, keeping the type parameter + +We can write \textbf{parametric code}\index{parametric code} working +with \lstinline!MySockX[A]!, that is, keeping the type parameter \lstinline!A! in the code. For example, a function that checks whether a sock of type \lstinline!MySockX[A]! fits the author\textsf{'}s foot can be written as: @@ -228,9 +229,9 @@ \subsection{Case classes with type parameters} Case classes may have several type parameters, and the types of the parts may use these type parameters. Here is an artificial example -of a case class using type parameters in different ways, +of a case class using type parameters in different ways: \begin{lstlisting} -case class Complicated[A,B,C,D](x: (A, A), y: (B, Int) => A, z: C => C) +case class Complicated[A, B, C, D](x: (A, A), y: (B, Int) => A, z: C => C) \end{lstlisting} This case class contains parts of different types that use the type parameters \lstinline!A!, \lstinline!B!, \lstinline!C! in tuples @@ -336,8 +337,8 @@ \subsection{Pattern matching for case classes} \item destructuring definition: \lstinline[mathescape=true]!val $pattern$ = ...! \item \lstinline!case! expression: \lstinline[mathescape=true]!case $pattern$ => ...! \end{itemize} -Case classes can be used in both situations. A destructuring definition -can be used in a function whose argument is of case class type \lstinline!BagOfSocks!: +In both situations, case classes can be used as patterns. The following +code is an example of a destructuring definition: \begin{lstlisting} case class MySock(size: Double, color: String) case class BagOfSocks(sock: MySock, count: Int) @@ -361,24 +362,24 @@ \subsection{Pattern matching for case classes} } \end{lstlisting} In the code of this function, the value of \lstinline!bag! is matched -with the pattern expression \lstinline!BagOfSocks(MySock(size, _), _)!. +against the pattern expression \lstinline!BagOfSocks(MySock(size, _), _)!. This pattern will define \lstinline!size! as a pattern variable of -type \lstinline!Double! and assign its value to the corresponding -part of the case class. For example, the value \lstinline!BagOfSocks(MySock(10.5, "white"), 6)!) +type \lstinline!Double! and assign the corresponding part of the +case class to that variable. For example, the value \lstinline!BagOfSocks(MySock(10.5, "white"), 6)!) matched against \lstinline!BagOfSocks(MySock(size, _), _)! assigns -\lstinline!size! to \lstinline!10.5!. The symbol \textsf{``}\lstinline!_!\textsf{''} -means that we just ignore other parts of the case classes and do not +\lstinline!10.5! to \lstinline!size!. The symbols \textsf{``}\lstinline!_!\textsf{''} +mean that we just ignore other parts of the case classes and do not create any pattern variables for them (because we do not need them -in this specific code). +in this code). The syntax for pattern matching for case classes is similar to the syntax for pattern matching for tuples, except for the presence of -the \emph{names} of the case classes. For example, by removing the -case class names from the pattern +\emph{names} of the case classes. For example, by removing the case +class names from the pattern: \begin{lstlisting} case BagOfSocks(MySock(size, _), _) => ... \end{lstlisting} -we obtain the nested tuple pattern +we obtain a nested tuple pattern: \begin{lstlisting} case ((size, _), _) => ... \end{lstlisting} @@ -427,21 +428,21 @@ \subsection{Motivation and first examples\label{subsec:Disjunctive-Motivation-an if that type is able to describe a mutually exclusive set of cases: \begin{itemize} \item \lstinline!RootsOfQ! must be either the empty tuple \lstinline!()!, -or \lstinline!Double!, or the tuple \lstinline!(Double, Double)! -\item \lstinline!SearchResult! must be either \lstinline!Int! or the empty -tuple \lstinline!()! +or a \lstinline!Double! value, or a tuple of type \lstinline!(Double, Double)! +\item \lstinline!SearchResult! must be either an \lstinline!Int! value +or the empty tuple \lstinline!()! \item \lstinline!Result! must be either an \lstinline!Int! value or a -\lstinline!String! message +\lstinline!String! error message \end{itemize} -We see that the empty tuple, also known as the \lstinline!Unit! type, -is natural to use in these situations. It is also helpful to assign -names to each of the cases: +We see that the empty tuple, i.e., the \lstinline!Unit! type, is +natural to use in these situations. It is also helpful to assign names +to each of the cases: \begin{itemize} \item \lstinline!RootsOfQ! is \textsf{``}no roots\textsf{''} with value \lstinline!()!, or \textsf{``}one root\textsf{''} with value \lstinline!Double!, or \textsf{``}two roots\textsf{''} with value \lstinline!(Double, Double)! -\item \lstinline!SearchResult! is \textsf{``}index\textsf{''} with value \lstinline!Int!, -or \textsf{``}not found\textsf{''} with value \lstinline!()! +\item \lstinline!SearchResult! is \textsf{``}index\textsf{''} with an \lstinline!Int! +value, or \textsf{``}not found\textsf{''} with value \lstinline!()! \item \lstinline!Result! is \textsf{``}value\textsf{''} of type \lstinline!Int! or \textsf{``}error message\textsf{''} of type \lstinline!String! \end{itemize} @@ -456,10 +457,10 @@ \subsection{Motivation and first examples\label{subsec:Disjunctive-Motivation-an \item \lstinline!Result! is a value of the form \lstinline!Value(x: Int)! or \lstinline!Error(message: String)! \end{itemize} -Our three examples are now described as types that select one case -class out of a given set. It remains to see how Scala defines such -types. For instance, the definition of \lstinline!RootsOfQ! needs -to indicate that the case classes \lstinline!NoRoots!, \lstinline!OneRoot!, +Our three examples are now described as types that allow us to select +one case class out of a given set. It remains to see how Scala defines +such types. For instance, the definition of \lstinline!RootsOfQ! +needs to indicate that the case classes \lstinline!NoRoots!, \lstinline!OneRoot!, and \lstinline!TwoRoots! are the only possibilities allowed by the type \lstinline!RootsOfQ!. The Scala syntax for that definition looks like this: @@ -519,13 +520,13 @@ \subsection{Examples: Pattern matching for disjunctive types\index{examples (wit \lstinline!case! patterns because we need to match several possible cases of the disjunctive type: \begin{lstlisting} -def f(r: RootsOfQ): String = r match { +def print(r: RootsOfQ): String = r match { case NoRoots() => "no real roots" case OneRoot(r) => s"one real root: $r" case TwoRoots(x, y) => s"real roots: ($x, $y)" } -scala> f(x) +scala> print(x) res0: String = "one real root: 2.0" \end{lstlisting} Each \lstinline!case! pattern will introduce its own pattern variables, @@ -759,8 +760,9 @@ \subsubsection{Example \label{subsec:disj-Example-resultA}\ref{subsec:disj-Examp case (_, Error(m)) => Error(m) } \end{lstlisting} -To avoid repetition, we may define a general function that \textsf{``}maps\textsf{''} -operations on integers to operations on \lstinline!Result[Int]! types: +To avoid repetition, we may define a general function (\lstinline!map2!) +that \textsf{``}maps\textsf{''} binary operations on integers to operations on \lstinline!Result[Int]! +types: \begin{lstlisting} def map2(rx: Result[Int], ry: Result[Int])(op: (Int, Int) => Int): Result[Int] = (rx, ry) match { @@ -807,7 +809,8 @@ \subsubsection{Example \label{subsec:disj-Example-resultA}\ref{subsec:disj-Examp \end{lstlisting} -\subsection{Standard disjunctive types: \texttt{Option}, \texttt{Either}, \texttt{Try}} +\subsection{\label{subsec:Standard-disjunctive-types:}Standard disjunctive types: +\texttt{Option}, \texttt{Either}, \texttt{Try}} The Scala library defines the disjunctive types \lstinline!Option!, \lstinline!Either!, and \lstinline!Try! because they are often useful. @@ -831,10 +834,11 @@ \subsection{Standard disjunctive types: \texttt{Option}, \texttt{Either}, \textt Scala\textsf{'}s \lstinline!case object!s cannot have type parameters, the type parameter in the definition of \lstinline!None! must be set to the special type \lstinline!Nothing!, which is a type with \emph{no} -values (also called the \textbf{void} \textbf{type}\index{void type|textit}, -unlike Java or C\textsf{'}s \lstinline!void! keyword). The special type annotation -\lstinline!+T! makes \lstinline!None! usable as a value of type -\lstinline!Option[T]! for any type \lstinline!T!; see Section~\ref{subsec:Covariance,-contravariance,-and-subtyping} +values, also called the \textbf{void} \textbf{type}\index{void type|textit} +(not to be confused with Java or C\textsf{'}s \lstinline!void! keyword!). +The special type annotation \lstinline!+T! makes \lstinline!None! +usable as a value of type \lstinline!Option[T]! for any type \lstinline!T!; +see Section~\ref{subsec:Covariance,-contravariance,-and-subtyping} for more details. An alternative (implemented, e.g., in the \texttt{scalaz} library) @@ -935,7 +939,8 @@ \subsubsection{Example \label{subsec:Disjunctive-Example-option-1}\ref{subsec:Di res1: Option[Seq[Long]] = None \end{lstlisting} We say that the \lstinline!fmap! operation \textbf{lifts}\index{lifting} -a given function of type \lstinline!A => B! to the type \lstinline!Option[A] => Option[B]!. +a given function \lstinline!f! of type \lstinline!A => B! to a new +function of type \lstinline!Option[A] => Option[B]!. It is important to keep in mind that the code \lstinline!case Some(a) => Some(f(a))! changes the type of the option value. On the left side of the arrow, @@ -1035,8 +1040,8 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-flatMap}\ref{sub \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{subsec:Disjunction-Example-Option-getOrElse}} Add a new requirement to Example~\ref{subsec:Disjunction-Example-Option-flatMap}: -if the country code is not present, we should return the default country -code $1$. +if the country code is not present, return the default country code +$1$. \subparagraph{Solution} @@ -1050,7 +1055,7 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s scala> None.getOrElse(1) res3: Int = 1 \end{lstlisting} -So we can implement the new requirement as: +So, we can implement the new requirement as: \begin{lstlisting} scala> countryCode(Some(8004151212L)).getOrElse(1L) res4: Long = 1 @@ -1059,9 +1064,9 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s \paragraph{Using \texttt{Option} with collections} -Many Scala library methods return an \lstinline!Option! as a result. -The main examples are \lstinline!find!, \lstinline!headOption!, -and \lstinline!lift! for sequences, and \lstinline!get! for dictionaries. +Several Scala library methods return an \lstinline!Option! as a result. +Examples are \lstinline!find!, \lstinline!headOption!, and \lstinline!lift! +for sequences, and \lstinline!get! for dictionaries. The \lstinline!find! method returns the first element satisfying a predicate: @@ -1069,7 +1074,7 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s scala> (1 to 10).find(_ > 5) res0: Option[Int] = Some(6) -scala> (1 to 10).find(_ > 10) // No element is > 10. +scala> (1 to 10).find(_ > 100) // No element is > 100. res1: Option[Int] = None \end{lstlisting} @@ -1113,21 +1118,15 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s scala> Map(10 -> "a", 20 -> "b")(30) java.util.NoSuchElementException: key not found: 30 - at scala.collection.MapLike$class.default(MapLike.scala:228) - at scala.collection.AbstractMap.default(Map.scala:59) - ... 32 elided \end{lstlisting} Similarly, \lstinline!lift! is a safe by-index access to collections, -unlike the direct access that may fail: +unlike the direct access that may fail with an exception: \begin{lstlisting} scala> Seq(10,20,30)(0) res9: Int = 10 scala> Seq(10,20,30)(5) java.lang.IndexOutOfBoundsException: 5 - at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65) - at scala.collection.immutable.List.apply(List.scala:84) - ... 32 elided \end{lstlisting} @@ -1167,13 +1166,11 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s \end{lstlisting} Why use \lstinline!Either! instead of \lstinline!Option! for computations -that may fail? A failing computation such as \lstinline!"xyz".toInt! -cannot return a result, and sometimes we might use \lstinline!None! -to indicate that a result is not available. However, when the result -is a requirement for further calculations, we will usually need to -know exactly \emph{which} error prevented the result from being available. -The \lstinline!Either! type may provide detailed information about -such errors, which \lstinline!Option! cannot do. +that may fail? When a missing result is an error, we will usually +need to know the reason why the result is unavailable. The \lstinline!Either! +type may provide detailed information about such errors, which \lstinline!Option! +cannot do. An \lstinline!Option! type is mostly used in cases where +the absence of a result is \emph{not} an error. The \lstinline!Either! type generalizes the type \lstinline!Result! defined in Section~\ref{subsec:Disjunctive-Motivation-and-first-examples} @@ -1205,11 +1202,11 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s As an example, exceptions are generated when the available memory is too small to store the resulting data (as we saw in Section~\ref{subsec:Lazy-values-iterators-and-streams}), -or if a stack overflow occurs during the computation (as we saw in -Section~\ref{subsec:Tail-recursion}). Exceptions may also occur -due to programmer\textsf{'}s error: when a pattern matching operation fails, -when a requested key does not exist in a dictionary, or when the \lstinline!head! -operation is applied to an empty list. +or if a stack overflow occurs during the computation (see Section~\ref{subsec:Tail-recursion}). +Exceptions may also occur due to programmer\textsf{'}s errors: when a pattern +matching operation fails, when a requested key does not exist in a +dictionary, or when the \lstinline!head! operation is applied to +an empty list. Motivated by these examples, we may distinguish \textsf{``}planned\index{planned exception}\textsf{''} and \textsf{``}unplanned\textsf{''} exceptions. @@ -1268,7 +1265,7 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s the Scala library provides a disjunctive type called \lstinline!Try!. The type \lstinline!Try[A]! is equivalent to \lstinline!Either[Throwable, A]!, where \lstinline!Throwable! is the general type of all exceptions -(i.e.~values to which a \lstinline!throw! operation can be applied). +(i.e., values to which a \lstinline!throw! operation can be applied). The two parts of the disjunctive type \lstinline!Try[A]! are called \lstinline!Failure! and \lstinline!Success[A]! (instead of \lstinline!Left[Throwable, A]! and \lstinline!Right[Throwable, A]! in the \lstinline!Either! type). @@ -1280,8 +1277,8 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s If the evaluation of \lstinline!expr! succeeds and returns a value \lstinline!x: A!, the value of \lstinline!Try(expr)! will be \lstinline!Success(x)!. Otherwise it will be \lstinline!Failure(t)!, where \lstinline!t: Throwable! -is the value containing the details about the exception. Here is an -example of using \lstinline!Try!: +is a value containing details about the exception. Here is an example +of using \lstinline!Try!: \begin{lstlisting} import scala.util.{Try, Success, Failure} @@ -1293,9 +1290,9 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s \end{lstlisting} The code \lstinline!Try("xyz".toInt)! does not generate any exceptions and will not crash the program. Any computation that may \lstinline!throw! -an exception can be enclosed in a \lstinline!Try()!, and the exception -will be caught and encapsulated within the disjunctive type as a \lstinline!Failure(...)! -value. +a planned exception can be enclosed in a \lstinline!Try()!, and the +exception will be caught and encapsulated within the disjunctive type +as a \lstinline!Failure(...)! value. The methods \lstinline!map!, \lstinline!filter!, \lstinline!flatMap!, \lstinline!foldLeft! are defined for the \lstinline!Try! class similarly @@ -1383,7 +1380,7 @@ \subsection{\label{subsec:The-recursive-type-List}The recursive type \texttt{Lis $\bullet$ Inductive step: given a list of a previously defined length, say \lstinline!List!$_{n-1}$, define a new case class \lstinline!List!$_{n}$ -describing a list with one more element of type \lstinline!A!. So +describing a list with one more element of type \lstinline!A!. So, we could define \lstinline!List!$_{n}=\,$\lstinline!(A, List!$_{n-1}$\lstinline!)!. Let us try to write this inductive definition as code: @@ -1505,12 +1502,12 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l ... \end{lstlisting} In the inductive step, we have a pair \lstinline!(head, tail)! in -the case class \lstinline!::!, with \lstinline!head:A! and \lstinline!tail:List[A]!. +the case class \lstinline!::!, with \lstinline!head: A! and \lstinline!tail: List[A]!. The pair can be pattern-matched with the syntax \lstinline!head :: tail!. The \lstinline!map! function should apply the argument \lstinline!f! to the head value, which will give the first element of the resulting list. The remaining elements are computed by the induction assumption, -i.e.~by a recursive call to \lstinline!map!: +i.e., by a recursive call to \lstinline!map!: \begin{lstlisting} def map[A, B](xs: List[A])(f: A => B): List[B] = xs match { case Nil => Nil @@ -1537,7 +1534,7 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l The inductive step for \lstinline!foldLeft! says that, given the values \lstinline!head:A! and \lstinline!tail:List[A]!, we need to apply the updater function to the previous accumulator value. That -value is \lstinline!init!. So we apply \lstinline!foldLeft! recursively +value is \lstinline!init!. So, we apply \lstinline!foldLeft! recursively to the tail of the list once we have the updated accumulator value: \begin{lstlisting} @tailrec def foldLeft[A, R](xs: List[A])(init: R)(f: (R, A) => R): R = @@ -1666,8 +1663,7 @@ \subsubsection{Example \label{subsec:Disjunctive-Example-non-empty-list}\ref{sub We will use \lstinline!foldLeft! to build up the reversed list as the accumulator value. It remains to choose the initial value of the accumulator and the updater function. We have already seen the code -for reversing the ordinary list via the \lstinline!foldLeft! method -(Section~\ref{subsec:Tail-recursion-with-list}): +for reversing the ordinary list via the \lstinline!foldLeft! method: \begin{lstlisting} def reverse[A](xs: List[A]): List[A] = xs.foldLeft(Nil: List[A])((prev,x) => x :: prev) \end{lstlisting} @@ -1688,14 +1684,14 @@ \subsubsection{Example \label{subsec:Disjunctive-Example-non-empty-list}\ref{sub the head element \lstinline!10! of the original list. However, we cannot set the initial accumulator value to an empty list, since a value of type \lstinline!NEL[A]! must be non-empty. It seems that -we need to handle the case of a one-element list separately. So we +we need to handle the case of a one-element list separately. So, we begin by matching on the argument of \lstinline!reverse!, and apply \lstinline!foldLeft! only when the list is longer than $1$ element: \begin{lstlisting} def reverse[A]: NEL[A] => NEL[A] = { case Last(x) => Last(x) // `reverse` is a no-op. case More(x, tail) => // Use foldLeft on `tail`. - foldLeft(tail)(Last(x): NEL[A])((prev,x) => More(x, prev)) + foldLeft(tail)(Last(x): NEL[A])((prev, x) => More(x, prev)) } scala> reverse(toNEL(10, List(20, 30))) // The result is [30, 20, 10]. @@ -1873,7 +1869,7 @@ \subsection{Perfect-shaped trees\label{subsec:Perfect-shaped-trees}} and so on. The non-trivial step is to notice that each case class \lstinline!Branch!$_{n}$ uses the previous case class\textsf{'}s data structure with the \emph{type parameter} set to \lstinline!(A, A)! instead -of \lstinline!A!. So we can rewrite the above definition as: +of \lstinline!A!. So, we can rewrite the above definition as: \begin{lstlisting} sealed trait PTree[A] final case class Leaf[A](x: A) extends PTree[A] @@ -2119,10 +2115,11 @@ \subsection{Abstract syntax trees} \end{lstlisting} The code for the \textsf{``}safe division\textsf{''} is: \begin{lstlisting} -def div(x: Either[String, Int], y: Either[String, Int]): - Either[String, Int] = x.flatMap { r1 => y.flatMap(r2 => - if (r2 == 0) Left(s"error: $r1 / $r2") else Right(r1 / r2) ) -} +def div(x: Either[String, Int], y: Either[String, Int]): Either[String, Int] = + x.flatMap { r1 => y.flatMap { r2 => + if (r2 == 0) Left(s"error: $r1 / $r2") else Right(r1 / r2) + } + } \end{lstlisting} With this code, we can implement the runner as a recursive function: \begin{lstlisting} @@ -2194,9 +2191,9 @@ \subsubsection{Example \label{subsec:Example-disjunctive-1}\ref{subsec:Example-d \subsubsection{Example \label{subsec:Example-disjunctive-2}\ref{subsec:Example-disjunctive-2}} -Modify \lstinline!DayOfWeek! so that the values additionally represent -names of restaurants, the total amount for Fridays, and the wake-up -time on Saturdays. +Modify \lstinline!DayOfWeek! so that on Fridays the values additionally +represent names of restaurants and amounts paid, and on Saturdays +a wake-up time. \subparagraph{Solution} @@ -2238,12 +2235,12 @@ \subsubsection{Example \label{subsec:disj-Example-rootsofq-2}\ref{subsec:disj-Ex final case class OneRootQ(x: Double) extends RootsOfQ2 final case class TwoRootsQ(x: Double, y: Double) extends RootsOfQ2 \end{lstlisting} -This disjunctive type contains six parts, among which three parts -are empty tuples and two parts are single-element tuples; but this -is not a useless redundancy. We would lose information if we reused -\lstinline!Linear! for the two cases $a=0$, $b\neq0$ and $a\neq0$, -$b^{2}=4ac$, or if we reused \lstinline!NoRoots()! for representing -all three different no-roots cases. +This disjunctive type contains six parts: three parts are empty tuples +and two parts are single-element tuples; but this is not a useless +redundancy. We would lose information if we reused \lstinline!Linear! +for the two cases $a=0$, $b\neq0$ and $a\neq0$, $b^{2}=4ac$, or +if we reused \lstinline!NoRoots()! for all three different no-roots +cases. \subsubsection{Example \label{subsec:Example-disjunctive-3}\ref{subsec:Example-disjunctive-3}} @@ -2396,7 +2393,7 @@ \subsubsection{Example \label{subsec:Example-disjunctive-5}\ref{subsec:Example-d We execute the same argument as before: The return value must be \lstinline!Left(x)! for some \lstinline!x: A!, or \lstinline!Right(y)! for some \lstinline!y: Option[B]!. At this point, we have a value of type \lstinline!A! but no values -of type \lstinline!B!. So we have two possibilities: to return \lstinline!Left(a)! +of type \lstinline!B!. So, we have two possibilities: to return \lstinline!Left(a)! or to return \lstinline!Right(None)!. If we decide to return \lstinline!Left(a)!, the code is: \begin{lstlisting}[numbers=left] @@ -2411,8 +2408,8 @@ \subsubsection{Example \label{subsec:Example-disjunctive-5}\ref{subsec:Example-d Let us decide whether to return \lstinline!Left(a)! or \lstinline!Right(None)! in line 4. Both choices will satisfy the required return type \lstinline!Either[A, Option[B]]!. However, if we return \lstinline!Right(None)! in that line, we will -ignore the given value \lstinline!a: A!, i.e., we will lose information.\index{information loss} -So we return \lstinline!Left(a)! in line 4. +ignore the given value \lstinline!a: A!, which loses information.\index{information loss} +So, we return \lstinline!Left(a)! in line 4. Similarly, we find in line 5 that we may return \lstinline!Right(None)! or \lstinline!Right(Some(b))!. The first choice ignores the given @@ -2485,7 +2482,7 @@ \subsubsection{Example \label{subsec:Example-disjunctive-6}\ref{subsec:Example-d } \end{lstlisting} In lines 4\textendash 5, we find that there is no choice other than -returning \lstinline!None!. So we can simplify the code: +returning \lstinline!None!. So, we can simplify the code: \begin{lstlisting} def f2[A, B]: (Option[A], Option[B]) => Option[(A, B)] = { case (Some(a), Some(b)) => Some((a, b)) @@ -2619,7 +2616,7 @@ \subsection{Disjunctive types as mathematical sets} on a Cartesian plane (a two-dimensional space). The no-roots case corresponds to a zero-dimensional space, which is pictured as a single point in Figure~\ref{fig:RootsOfQ-disjoint-domain}. The point, the -line, and the plane do not intersect (i.e., have no common points. +line, and the plane do not intersect (i.e., have no common points). Together, they form the set of the possible roots of the quadratic equation $x^{2}+bx+c=0$. @@ -2649,16 +2646,16 @@ \subsection{Disjunctive types as mathematical sets} \[ \mathbb{R}^{0}\cup\mathbb{R}^{0}\cup\mathbb{R}^{1}\cup\mathbb{R}^{0}\cup\mathbb{R}^{1}\cup\mathbb{R}^{2}=\mathbb{R}^{0}\cup\mathbb{R}^{1}\cup\mathbb{R}^{2}\quad. \] -For instance, this representation has no distinction between \lstinline!Linear(x)! -and \lstinline!OneRootQ(x)!. +For instance, this representation has no distinction between the cases +\lstinline!Linear(x)! and \lstinline!OneRootQ(x)!. In the Scala code, each part of a disjunctive type must be distinguished by a unique name such as \lstinline!NoRoots!, \lstinline!OneRoot!, and \lstinline!TwoRoots!. To represent this mathematically, we can attach a distinct label to each part of the union. Labels are symbols -without any special meaning, and we can just assume that labels are -names of Scala case classes. Parts of the union are then represented -by sets of pairs such as $(\text{\texttt{OneRoot}},x)_{x\in\mathbb{R}^{1}}$. +without any special meaning, and we can assume that labels are names +of Scala case classes. Parts of the union are then represented by +sets of pairs such as $(\text{\texttt{OneRoot}},x)_{x\in\mathbb{R}^{1}}$. Then the domain \lstinline!RootsOfQ! is expressed as: \[ \text{\texttt{RootsOfQ}}=(\text{\texttt{NoRoots}},u)_{u\in\mathbb{R}^{0}}\cup(\text{\texttt{OneRoot}},x)_{x\in\mathbb{R}^{1}}\cup(\text{\texttt{TwoRoots}},\left(x,y\right))_{\left(x,y\right)\in\mathbb{R}^{2}}\quad. @@ -2704,7 +2701,7 @@ \subsection{Disjunctive types as mathematical sets} So, case classes with no parts are similar to \lstinline!Unit! except for an added name, e.g., \lstinline!NoRoots()! is the \lstinline!Unit! value \lstinline!()! with name \lstinline!NoRoots!. For this reason, -they can be viewed as \textsf{``}named unit\textsf{''} types.\index{unit type!named} +this book calls them \textsf{``}named unit\textsf{''} types.\index{unit type!named} \subsection{Disjunctive types in other programming languages} @@ -2727,7 +2724,7 @@ \subsection{Disjunctive types in other programming languages} \begin{lstlisting}[language=C] union { int x; double y; long z; } i_d_l; \end{lstlisting} -This type does not include any label telling us which of the values +This type does not include any labels telling us which of the values is present. Without a label, we (and the compiler) will not know whether a given value of type \lstinline!i_d_l! represents an \lstinline!int!, a \lstinline!double!, or a \lstinline!long!. This will lead to errors @@ -2781,7 +2778,8 @@ \subsection{Disjunctive types in other programming languages} This is more concise than the Scala syntax. When reasoning about disjunctive types, it is inconvenient to write out long type definitions. Chapter~\ref{chap:5-Curry-Howard} will introduce a mathematical notation designed for efficient reasoning -about types. That notation is even more concise than Haskell or OCaml. +about types. That notation is even more concise than the syntax of +Haskell or OCaml. \subsection{Disjunctions and conjunctions in formal logic\label{subsec:Disjunctions-and-conjunctions}} @@ -2800,8 +2798,8 @@ \subsection{Disjunctions and conjunctions in formal logic\label{subsec:Disjuncti rewrite the previous sentence as a logical formula. Denote by ${\cal CH}(A)$ the logical proposition \textsf{``}we ${\cal C}\!$an ${\cal H}\!$ave a value of type \lstinline!A! here\textsf{''}, where by \textsf{``}here\textsf{''} we mean a particular -point in a program. So, the proposition \textsf{``}the function\textsf{'}s body \emph{can} -compute a value of type \lstinline!RootsOfQ!\textsf{''} is denoted by ${\cal CH}(\text{\texttt{RootsOfQ}})$. +scope in a program. So, the proposition \textsf{``}the code \emph{can} compute +a value of type \lstinline!RootsOfQ!\textsf{''} is denoted by ${\cal CH}(\text{\texttt{RootsOfQ}})$. We can then write the above sentence about \lstinline!RootsOfQ! as a logical formula: \begin{equation} @@ -2810,9 +2808,9 @@ \subsection{Disjunctions and conjunctions in formal logic\label{subsec:Disjuncti There is a similar connection between logical \emph{conjunctions} and tuple types. Consider the named tuple (i.e., a case class) \lstinline!TwoRoots(x: Double, y: Double)!. -We have a value of type \lstinline!TwoRoots! only if we have two -values of type \lstinline!Double!. Rewriting this sentence as a logical -formula, we get: +We can have a value of type \lstinline!TwoRoots! only if we have +two values of type \lstinline!Double!. Rewriting this sentence as +a logical formula, we get: \[ {\cal CH}(\text{\texttt{TwoRoots}})={\cal CH}(\text{\texttt{Double}})\wedge{\cal CH}(\text{\texttt{Double}})\quad. \] @@ -2832,9 +2830,9 @@ \subsection{Disjunctions and conjunctions in formal logic\label{subsec:Disjuncti We find that tuples are related to logical conjunctions in the same way as disjunctive types are related to logical disjunctions. This -is the main reason for choosing the name \textsf{``}disjunctive types\textsf{''}.\footnote{Disjunctive types are also called variants, sum types, co-product -types, and tagged unions. This book uses the terms \textsf{``}disjunctive -types\textsf{''} and \textsf{``}co-product types\textsf{''} interchangeably.} +is the main reason for choosing the name \textsf{``}disjunctive types\textsf{''}.\footnote{Disjunctive types are also called sum types, co-product types, variants, +and tagged unions. This book uses the terms \textsf{``}disjunctive types\textsf{''} +and \textsf{``}co-product types\textsf{''} interchangeably.} The correspondence between disjunctions, conjunctions, and data types is explained in more detail in Chapter~\ref{chap:5-Curry-Howard}. diff --git a/sofp-src/sofp-essay1.lyx b/sofp-src/sofp-essay1.lyx index 53ef38325..1f5bb68cd 100644 --- a/sofp-src/sofp-essay1.lyx +++ b/sofp-src/sofp-essay1.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -324,6 +324,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://tinyurl.com/4wwsedrz" target "https://www.slideshare.net/noootsab/scala-the-unpredicted-lingua-franca-for-data-science" literal "false" @@ -548,8 +549,8 @@ The functional programming paradigm is based on mathematical principles: languages. This power of abstraction is not accidental. Since mathematics is the ultimate art of building abstractions, math-based - functional programming languages capitalize on having several millennia - of mathematical experience. + functional programming languages capitalize on several millennia of mathematica +l experience. \end_layout \begin_layout Standard @@ -737,7 +738,7 @@ implies \emph on incomplete \emph default - (you cannot derive some theorems). + (cannot derive some theorems). \end_layout \begin_layout Standard @@ -850,7 +851,7 @@ status open \begin_layout Plain Layout -(A,B) +(A, B) \end_layout \end_inset @@ -868,9 +869,9 @@ A => B \end_inset . - All modern functional languages such as OCaml, Haskell, Scala, F#, Swift, - Elm, and PureScript support these three type constructions and thus obey - the CH correspondence. + All modern functional languages such as OCaml, Haskell, Scala, F#, and + Swift support these three type constructions and thus obey the CH correspondenc +e. Having a \emph on complete @@ -1124,10 +1125,10 @@ academic status open \begin_layout Plain Layout -OCaml has arbitrary recursive product and co-product types that can be freely - combined with object-oriented types. - Haskell removes all side effects from the language and supports partial - type functions of arbitrarily high order. +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. \end_layout \end_inset @@ -1157,8 +1158,7 @@ parent \begin_inset Quotes erd \end_inset - platforms and languages (F# with C#, Scala with Java, and Swift with Objective- -C). + platform'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. @@ -1237,9 +1237,10 @@ object-oriented programming 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's parameterized modules and some other features. - Of all mentioned languages, only Scala and Haskell directly support typeclasses - and higher-order functions on types, which are helpful for expressing abstracti -ons such as automatically parallelized data sets or asynchronous data streams. + 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. \end_layout \begin_layout Standard diff --git a/sofp-src/sofp-essay2.lyx b/sofp-src/sofp-essay2.lyx index 48167ec95..01208501d 100644 --- a/sofp-src/sofp-essay2.lyx +++ b/sofp-src/sofp-essay2.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -561,14 +561,14 @@ Gibbs free energy in chemical reactor design. \begin_inset Foot -status collapsed +status open \begin_layout Plain Layout \family typewriter \begin_inset CommandInset href LatexCommand href -target "https://www.amazon.com/Introduction-Chemical-Engineering-Kinetics-Reactor/dp/1118368258" +target "https://amzn.com/dp/1118368258" literal "false" \end_inset @@ -819,6 +819,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://archive.is/MNlgT" target "https://hashnode.com/post/i-am-robert-c-martin-uncle-bob-ask-me-anything-cjr7pnh8g000k2cs18o5nhulp/2" literal "false" @@ -1007,7 +1008,8 @@ E.g., \begin_inset CommandInset href LatexCommand href -target "https://www.amazon.com/Object-Oriented-Software-Engineering-Unified-Methodology/dp/0073376256" +target "https://amzn.com/dp/0073376256" +literal "false" \end_inset @@ -1217,7 +1219,7 @@ noprefix "false" \begin_inset Formula $x:T$ \end_inset -, we find that the property +, the property \begin_inset Formula $\phi(c(y))$ \end_inset @@ -1384,14 +1386,14 @@ The Science of Programming \begin_inset Foot -status collapsed +status open \begin_layout Plain Layout \family typewriter \begin_inset CommandInset href LatexCommand href -target "https://www.amazon.com/Science-Programming-Monographs-Computer/dp/0387964800" +target "https://amzn.com/dp/0387964800" literal "false" \end_inset @@ -1411,14 +1413,14 @@ Program derivation \begin_inset Foot -status collapsed +status open \begin_layout Plain Layout \family typewriter \begin_inset CommandInset href LatexCommand href -target "https://www.amazon.com/Program-Derivation-Development-Specifications-International/dp/0201416247" +target "https://amzn.com/dp/0201416247" literal "false" \end_inset @@ -1457,6 +1459,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://archive.is/6D796" target "https://www.cs.cmu.edu/~adamchik/15-121/lectures/Algorithmic%20Complexity/complexity.html" literal "false" @@ -1555,7 +1558,7 @@ functor \begin_inset Quotes erd \end_inset -, + and \begin_inset Quotes eld \end_inset @@ -1563,14 +1566,6 @@ monad \begin_inset Quotes erd \end_inset -, or -\begin_inset Quotes eld -\end_inset - -lambda-functions -\begin_inset Quotes erd -\end_inset - : \end_layout @@ -1624,10 +1619,59 @@ free monads , and other arcane terminology. Indeed, that sort of terminology is intentionally avoided by most books and tutorials aimed at programmers. +\begin_inset Foot +status open + +\begin_layout Plain Layout +For example, the recent book +\begin_inset Quotes eld +\end_inset + +Grokking functional programming +\begin_inset Quotes erd +\end_inset + + +\emph on +never +\emph default + mentions +\begin_inset Quotes eld +\end_inset + +functors +\begin_inset Quotes erd +\end_inset + + or +\begin_inset Quotes eld +\end_inset + +monads +\begin_inset Quotes erd +\end_inset + +. + See +\family typewriter + +\begin_inset CommandInset href +LatexCommand href +target "https://www.manning.com/books/grokking-functional-programming" +literal "false" + +\end_inset + + +\end_layout + +\end_inset + + \end_layout \begin_layout Standard -But why would a software +But why would an \emph on engineer \emph default @@ -1639,11 +1683,11 @@ functors \begin_inset Quotes erd \end_inset - or at having to verify the laws of a + or at \begin_inset Quotes eld \end_inset -monad +free monads \begin_inset Quotes erd \end_inset @@ -1694,7 +1738,7 @@ phase diagrams \begin_inset Quotes erd \end_inset - or + and \begin_inset Quotes eld \end_inset @@ -1703,48 +1747,48 @@ Fourier's law \end_inset . - Electrical engineers do not avoid + Mechanical engineers take it for granted that they have to work with \begin_inset Quotes eld \end_inset -Fourier transforms +rank 4 tensors \begin_inset Quotes erd \end_inset - or +, \begin_inset Quotes eld \end_inset -delta functions +Lagrangians \begin_inset Quotes erd \end_inset - because those are weird things to say. - Mechanical engineers take it for granted that they need +, and \begin_inset Quotes eld \end_inset -rank 4 tensors +non-holonomic constraints \begin_inset Quotes erd \end_inset -, +. + Electrical engineers do not avoid \begin_inset Quotes eld \end_inset -Lagrangians +Fourier transforms \begin_inset Quotes erd \end_inset -, and + or \begin_inset Quotes eld \end_inset -non-holonomic constraints +delta functions \begin_inset Quotes erd \end_inset -. + 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. \end_layout @@ -1766,8 +1810,8 @@ Towards true engineering in software \begin_layout Standard 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 culture and processes are - that of a crafts guild. + They work using artisanal methods, and their education and design processes + are typical of a crafts guild. \end_layout \begin_layout Standard @@ -1796,8 +1840,8 @@ mathematical \emph on subject matter \emph default - (aerospace control, physics or astronomy simulations, or statistics) does - not mean that mathematics is used to guide the process of writing code. + (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. \end_layout @@ -1851,8 +1895,8 @@ noprefix "false" \end_layout \begin_layout Standard -To appreciate that functional programming, unlike any other programming - paradigm, is based on a +To appreciate that functional programming, unlike other paradigms, is based + on a \emph on theory that guides coding \emph default @@ -1999,37 +2043,28 @@ noprefix "false" This activity is similar to that of an engineer who performs some mathematical calculations before embarking on a design project. -\begin_inset Wrap figure -lines 0 -placement L -overhang 0in -width "50text%" +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false status open \begin_layout Plain Layout \align center \size footnotesize -\begin_inset VSpace 25baselineskip% -\end_inset - - \begin_inset Graphics filename ftt-example.jpg - width 100line% - -\end_inset + width 60line% - -\begin_inset VSpace -25baselineskip% \end_inset \end_layout \begin_layout Plain Layout - -\size footnotesize \begin_inset Caption Standard \begin_layout Plain Layout @@ -2049,19 +2084,15 @@ name "fig:Example-calculation-in-type-theory" \end_layout \begin_layout Plain Layout -\begin_inset VSpace -50baselineskip% -\end_inset - \end_layout \end_inset - + \end_layout \begin_layout Standard -\noindent A recent example of a development in applied functional type theory is the \begin_inset Quotes eld @@ -2120,6 +2151,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://archive.is/kwD2a" target "https://elvishjerricco.github.io/2016/04/08/applicative-effects-in-free-monads.html" literal "false" @@ -2272,6 +2304,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://archive.is/kVYYt" target "https://www.linkedin.com/pulse/40-year-gap-what-has-academic-computer-science-ever-done-winitzki" literal "false" @@ -2397,8 +2430,8 @@ out of control \begin_inset Quotes erd \end_inset -, and operating systems have been notorious for ever-appearing security - flaws +, and operating systems have been notorious for constantly appearing new + security flaws \begin_inset Foot status open @@ -2552,6 +2585,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href +name "https://archive.is/pA1hz" target "https://www.slideshare.net/nashjain/no-silver-bullets-in-functional-programming-by-brian-mckenna" literal "false" @@ -2614,10 +2648,10 @@ literal "false" \end_inset -) came as one of the features of the FORTRAN language. - That feature of FORTRAN (that still survives in virtually all programming +) 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 + With Fortran, for the first time, the programmer could write a formula such as \begin_inset listings inline true @@ -2703,7 +2737,7 @@ return \begin_layout Standard Instead of this quite tedious and error-prone sequence of instructions, - FORTRAN programmers could simply write + Fortran programmers could simply write \begin_inset listings inline true status open @@ -2720,7 +2754,7 @@ A = B * C - SQRT(D) \end_layout \begin_layout Standard -After FORTRAN, the LISP language enabled programmers to write recursive +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. @@ -2731,23 +2765,23 @@ After FORTRAN, the LISP language enabled programmers to write recursive \end_layout \begin_layout Standard -Another innovation was in the PROLOG language. - PROLOG implemented a backtracking search as a built-in feature that the +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 + 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 + Prolog, however, did not find a lot of use outside the European artificial intelligence community of 1970–1980s. Its best area of application (expert systems) has had its heyday and is now a distant memory. \end_layout \begin_layout Standard -Nevertheless, the legacy of PROLOG is alive and well in the form of SQL, +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 + 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. @@ -2816,27 +2850,12 @@ declarative programming \begin_inset Quotes erd \end_inset - when I started studying Haskell and then PROLOG. - Both languages are claimed up front to be -\begin_inset Quotes eld -\end_inset - -declarative -\begin_inset Quotes erd -\end_inset - -, in opposition to -\begin_inset Quotes eld -\end_inset - -imperative -\begin_inset Quotes erd -\end_inset - + 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 + 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 @@ -2856,7 +2875,7 @@ status open \family typewriter \begin_inset CommandInset href LatexCommand href -target "https://www.amazon.com/Real-World-Haskell-Code-Believe-ebook/dp/B0026OR2FY" +target "https://amzn.com/dp/B0026OR2FY" literal "false" \end_inset @@ -2959,16 +2978,16 @@ silver bullet 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 + 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. + One could plausibly argue that Fortran was as well adapted to programming + numerical expressions as Prolog to expert systems or Haskell to compilers. \end_layout \begin_layout Standard 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. + other problem domains! Prolog was not easily suitable for matrix multiplication +, nor Fortran for expert systems, nor Haskell for GUI programs. \end_layout \begin_layout Standard @@ -3014,14 +3033,14 @@ 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 + 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. \end_layout \begin_layout Standard -Here is an example showing how PROLOG is adapted to tasks involving logical +Here is an example showing how Prolog is adapted to tasks involving logical relations. Consider the following logic puzzle: \end_layout @@ -3077,7 +3096,7 @@ Lem.) \end_layout \begin_layout Standard -The following is the complete code of the PROLOG program that solves this +The following is the complete code of the Prolog program that solves this puzzle, together with an example execution command using SWI-Prolog: \begin_inset listings lstparams "language=bash" @@ -3147,7 +3166,7 @@ pgvdrk is intelligent. \end_inset -We could mechanically rewrite this code and replace PROLOG predicates such +We could mechanically rewrite this code and replace Prolog predicates such as \begin_inset listings inline true @@ -3180,7 +3199,7 @@ X \begin_inset Quotes erd \end_inset -, the PROLOG operator +, the Prolog operator \begin_inset listings inline true status open @@ -3223,7 +3242,7 @@ and . 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 + In this sense, Prolog programs can be viewed as \begin_inset Quotes eld \end_inset @@ -3236,7 +3255,7 @@ executable specifications \end_layout \begin_layout Standard -However, writing a matrix multiplication program in PROLOG would require +However, writing a matrix multiplication program in Prolog would require code that is far removed from any human-readable specification or mathematical notation. \begin_inset Foot @@ -3258,7 +3277,7 @@ literal "false" \end_inset - It is clear that PROLOG is + It is clear that Prolog is \emph on not \emph default @@ -3534,7 +3553,7 @@ executable 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 the great + expected a \begin_inset Quotes eld \end_inset diff --git a/sofp-src/sofp-essay3.lyx b/sofp-src/sofp-essay3.lyx index 144caf0c0..703d55a6a 100644 --- a/sofp-src/sofp-essay3.lyx +++ b/sofp-src/sofp-essay3.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -931,7 +931,7 @@ A monad is just a monoid in the category of endofunctors. \begin_inset Quotes erd \end_inset - as the well-known joke + is a well-known joke. \begin_inset Index idx status open @@ -941,14 +941,14 @@ jokes \end_inset - goes. + \begin_inset CommandInset label LatexCommand label name "fn:A-monad-is-a-monoid-in-category-of-endofunctors-big-deal" \end_inset - For background information about that joke, see + See \family typewriter \begin_inset CommandInset href @@ -959,7 +959,8 @@ target "https://stackoverflow.com/questions/3870088/" \family default -; a related joke is in footnote + for background information about that joke. + A related joke is in footnote \begin_inset space ~ \end_inset diff --git a/sofp-src/sofp-filterable.lyx b/sofp-src/sofp-filterable.lyx index 76c1479ef..1dc2dd49e 100644 --- a/sofp-src/sofp-filterable.lyx +++ b/sofp-src/sofp-filterable.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -18955,7 +18955,7 @@ q p\\ q \end{array}\\ - & =f\bef\,\begin{array}{||c|} + & =\,f\bef\,\begin{array}{||c|} 1\rightarrow1+\bbnum 0\\ b\rightarrow g(b) \end{array}\,\bef\,\begin{array}{||c|} @@ -18965,7 +18965,7 @@ q {\color{green}\text{apply }\,\,\begin{array}{||c|} p\\ q -\end{array}\,:}\quad & =\,f\bef\,\begin{array}{||c|} +\end{array}\,:}\quad & =f\bef\,\begin{array}{||c|} 1\rightarrow\gunderline{(1+\bbnum 0)\,\triangleright}\,\begin{array}{||c|} p\\ q diff --git a/sofp-src/sofp-filterable.tex b/sofp-src/sofp-filterable.tex index 247b72627..cf7ad63f9 100644 --- a/sofp-src/sofp-filterable.tex +++ b/sofp-src/sofp-filterable.tex @@ -3000,7 +3000,7 @@ \subsubsection{Statement \label{subsec:Statement-filterable-recursive-type}\ref{ p\\ q \end{array}\\ - & =f\bef\,\begin{array}{||c|} + & =\,f\bef\,\begin{array}{||c|} 1\rightarrow1+\bbnum 0\\ b\rightarrow g(b) \end{array}\,\bef\,\begin{array}{||c|} @@ -3010,7 +3010,7 @@ \subsubsection{Statement \label{subsec:Statement-filterable-recursive-type}\ref{ {\color{greenunder}\text{apply }\,\,\begin{array}{||c|} p\\ q -\end{array}\,:}\quad & =\,f\bef\,\begin{array}{||c|} +\end{array}\,:}\quad & =f\bef\,\begin{array}{||c|} 1\rightarrow\gunderline{(1+\bbnum 0)\,\triangleright}\,\begin{array}{||c|} p\\ q diff --git a/sofp-src/sofp-free-type.lyx b/sofp-src/sofp-free-type.lyx index e760c5df2..fdb37931d 100644 --- a/sofp-src/sofp-free-type.lyx +++ b/sofp-src/sofp-free-type.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -16054,7 +16054,11 @@ Take any free functor ( \begin_inset Formula $\rho\triangleq\text{runFFR}\,(\text{run})$ \end_inset -, to both sides of the laws: +,***replace +\begin_inset Formula $\rho$ +\end_inset + + with some other letter*** to both sides of the laws: \begin_inset Formula \begin{align*} \text{identity law}:\quad & \text{id}^{\uparrow\text{FFR}}\bef\text{runFFR}\,(\text{run})=\text{runFFR}\,(\text{run})\quad,\\ diff --git a/sofp-src/sofp-free-type.tex b/sofp-src/sofp-free-type.tex index a6329282c..0906eb5cc 100644 --- a/sofp-src/sofp-free-type.tex +++ b/sofp-src/sofp-free-type.tex @@ -2127,8 +2127,8 @@ \subsubsection{Statement \label{subsec:Statement-free-functor-raw-tree-encoding- ($\text{run}:\forall C.\,F^{C}\rightarrow G^{C}$), where $G$ is a lawful functor. Denote for brevity $f^{\uparrow\text{FFR}}\triangleq f^{\uparrow\text{FFR}^{F^{\bullet},\bullet}}$. The functor laws will hold if we apply the runner function, denoted -for brevity by $\rho\triangleq\text{runFFR}\,(\text{run})$, to both -sides of the laws: +for brevity by $\rho\triangleq\text{runFFR}\,(\text{run})$,{*}{*}{*}replace +$\rho$ with some other letter{*}{*}{*} to both sides of the laws: \begin{align*} {\color{greenunder}\text{identity law}:}\quad & \text{id}^{\uparrow\text{FFR}}\bef\text{runFFR}\,(\text{run})=\text{runFFR}\,(\text{run})\quad,\\ {\color{greenunder}\text{composition law}:}\quad & f^{\uparrow\text{FFR}}\bef g^{\uparrow\text{FFR}}\bef\text{runFFR}\,(\text{run})=(f\bef g)^{\uparrow\text{FFR}}\bef\text{runFFR}\,(\text{run})\quad. diff --git a/sofp-src/sofp-functors.lyx b/sofp-src/sofp-functors.lyx index 310b85c72..2d8272a0d 100644 --- a/sofp-src/sofp-functors.lyx +++ b/sofp-src/sofp-functors.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -3234,7 +3234,7 @@ V \end_inset . - The method is called + The functor's method is called \begin_inset listings inline true status open @@ -3301,8 +3301,8 @@ types!polynomial type constructors \end_inset -Type constructors built with primitive types, type parameters, products, - and disjunctions (or +Type constructors defined via primitive types, products, and disjunctions + (or \begin_inset Quotes eld \end_inset @@ -3311,29 +3311,31 @@ sums \end_inset ) are often used to represent application-specific data. - Consider the code: + As an example, consider this definition: \begin_inset listings inline false status open \begin_layout Plain Layout -final case class Counted[A](n: Int, a: A) { +final case class Counted[A](n: Int, a: A) \end_layout -\begin_layout Plain Layout +\end_inset - def map[B](f: A => B): Counted[B] = Counted(n, f(a)) -\end_layout +We may implement +\begin_inset listings +inline true +status open \begin_layout Plain Layout -} +map \end_layout \end_inset -The data type + for \begin_inset listings inline true status open @@ -3345,89 +3347,125 @@ Counted[A] \end_inset - may be used to describe + as a function: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -n +def map[A, B](c: Counted[A])(f: A => B): Counted[B] = c match { +\end_layout + +\begin_layout Plain Layout + + case Counted(n, a) => Counted(n, f(a)) +\end_layout + +\begin_layout Plain Layout + +} \end_layout \end_inset - repetitions of a given value +But it is often more convenient to implement \begin_inset listings inline true status open \begin_layout Plain Layout -a: A +map \end_layout \end_inset -. - The code already defines the method + as a class method: +\end_layout + +\begin_layout Standard \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -map +final case class Counted[A](n: Int, a: A) { +\end_layout + +\begin_layout Plain Layout + + def map[B](f: A => B): Counted[B] = Counted(n, f(a)) +\end_layout + +\begin_layout Plain Layout + +} \end_layout \end_inset - for the + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +The data type \begin_inset listings inline true status open \begin_layout Plain Layout -Counted +Counted[A] \end_layout \end_inset - class, which can be used like this: + may be used to describe \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -scala> Counted(10, -\begin_inset Quotes eld -\end_inset +n +\end_layout -abc -\begin_inset Quotes erd \end_inset -).map(s => -\begin_inset Quotes eld -\end_inset + repetitions of a given value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +a: A +\end_layout -prefix -\begin_inset Quotes eld \end_inset - + s) +. + \end_layout +\end_inset + +This code defines both the type +\begin_inset listings +inline true +status open + \begin_layout Plain Layout -res0: Counted[String] = Counted(10,prefix abc) +Counted \end_layout \end_inset -It is often more convenient to implement + and the method \begin_inset listings inline true status open @@ -3439,24 +3477,35 @@ map \end_inset - as a class method rather than as a function such as: +, which can be used like this: \begin_inset listings inline false status open \begin_layout Plain Layout -def map[A, B](c: Counted[A])(f: A => B): Counted[B] = c match { -\end_layout +scala> Counted(10, +\begin_inset Quotes eld +\end_inset -\begin_layout Plain Layout +abc +\begin_inset Quotes erd +\end_inset - case Counted(n, a) => Counted(n, f(a)) +).map(s => +\begin_inset Quotes eld +\end_inset + +prefix +\begin_inset Quotes eld +\end_inset + + + s) \end_layout \begin_layout Plain Layout -} +res0: Counted[String] = Counted(10,prefix abc) \end_layout \end_inset @@ -3523,7 +3572,7 @@ Counted[_] \end_inset is a functor. - We still need to check that the functor laws hold for it. + Let us now verify that the functor laws hold for it. \end_layout \begin_layout Subsubsection diff --git a/sofp-src/sofp-functors.tex b/sofp-src/sofp-functors.tex index be5552e2a..11cb01f8a 100644 --- a/sofp-src/sofp-functors.tex +++ b/sofp-src/sofp-functors.tex @@ -424,9 +424,9 @@ \subsection{Functors: definition and examples\label{subsec:Functors:-definition- and \lstinline!Concurrent! (provided by the \texttt{cats-effect} library), \lstinline!ZIO! (provided by the \texttt{zio} library). \item Dictionaries: \lstinline!Map[K, V]! with respect to the type parameter -\lstinline!V!. The method is called \lstinline!mapValues! instead -of \lstinline!map!: it transforms the values in the dictionary, leaving -the keys unchanged. +\lstinline!V!. The functor\textsf{'}s method is called \lstinline!mapValues! +instead of \lstinline!map!: it transforms the values in the dictionary, +leaving the keys unchanged. \end{itemize} Application-specific, custom type constructors defined by the programmer, such as case classes with type parameters, are often functors. Their @@ -436,30 +436,34 @@ \subsection{Functors: definition and examples\label{subsec:Functors:-definition- \paragraph{Polynomial functors} -\index{types!polynomial type constructors}Type constructors built -with primitive types, type parameters, products, and disjunctions -(or \textsf{``}sums\textsf{''}) are often used to represent application-specific data. -Consider the code: +\index{types!polynomial type constructors}Type constructors defined +via primitive types, products, and disjunctions (or \textsf{``}sums\textsf{''}) are +often used to represent application-specific data. As an example, +consider this definition: +\begin{lstlisting} +final case class Counted[A](n: Int, a: A) +\end{lstlisting} +We may implement \lstinline!map! for \lstinline!Counted[A]! as a +function: +\begin{lstlisting} +def map[A, B](c: Counted[A])(f: A => B): Counted[B] = c match { + case Counted(n, a) => Counted(n, f(a)) +} +\end{lstlisting} +But it is often more convenient to implement \lstinline!map! as a +class method: + \begin{lstlisting} final case class Counted[A](n: Int, a: A) { def map[B](f: A => B): Counted[B] = Counted(n, f(a)) } \end{lstlisting} -The data type \lstinline!Counted[A]! may be used to describe \lstinline!n! -repetitions of a given value \lstinline!a: A!. The code already defines -the method \lstinline!map! for the \lstinline!Counted! class, which -can be used like this: +This code defines both the type \lstinline!Counted! and the method +\lstinline!map!, which can be used like this: \begin{lstlisting} scala> Counted(10, "abc").map(s => "prefix " + s) res0: Counted[String] = Counted(10,prefix abc) \end{lstlisting} -It is often more convenient to implement \lstinline!map! as a class -method rather than as a function such as: -\begin{lstlisting} -def map[A, B](c: Counted[A])(f: A => B): Counted[B] = c match { - case Counted(n, a) => Counted(n, f(a)) -} -\end{lstlisting} The type notation for \lstinline!Counted! is: \[ @@ -467,8 +471,7 @@ \subsection{Functors: definition and examples\label{subsec:Functors:-definition- \] showing that \lstinline!Counted[_]! is a polynomial type constructor. The existence of a \lstinline!map! method suggests that \lstinline!Counted[_]! -is a functor. We still need to check that the functor laws hold for -it. +is a functor. Let us now verify that the functor laws hold for it. \subsubsection{Example \label{subsec:f-Example-Int-x-A}\ref{subsec:f-Example-Int-x-A}\index{examples (with code)}} diff --git a/sofp-src/sofp-higher-order-functions.lyx b/sofp-src/sofp-higher-order-functions.lyx index db11738b0..1d2e9a3f6 100644 --- a/sofp-src/sofp-higher-order-functions.lyx +++ b/sofp-src/sofp-higher-order-functions.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -942,7 +942,7 @@ closures \end_inset . - It would be clearer to say that nameless functions + One could also say that nameless functions \begin_inset Quotes eld \end_inset @@ -1466,7 +1466,7 @@ Unit \end_inset - and having a function of type + and having a single argument of type \begin_inset listings inline true status open @@ -1478,8 +1478,12 @@ String => String \end_inset - as its argument. - When an argument's type is a function type, e.g., +. + +\end_layout + +\begin_layout Standard +When an argument's type is a function type, e.g., \begin_inset listings inline true status open @@ -1495,7 +1499,19 @@ String => String \emph on must \emph default - be enclosed in parentheses. + be enclosed in parentheses, as in +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(String => String) => Unit +\end_layout + +\end_inset + +. \end_layout \begin_layout Standard @@ -1902,7 +1918,7 @@ status open \end_inset could not possibly work for a nameless function because matching a function - with the pattern + against the pattern \begin_inset listings inline true status open @@ -2000,7 +2016,7 @@ x => (y => z) \end_inset - is the only sensible way of inserting parentheses into + is the only sensible way of adding parentheses to \begin_inset listings inline true status open @@ -2048,7 +2064,7 @@ status open \begin_layout Plain Layout -(A=>B)=>C +(A => B) => C \end_layout \end_inset @@ -4639,7 +4655,7 @@ before \begin_inset Quotes erd \end_inset -) as: +) by: \begin_inset Formula \begin{equation} f\bef g\triangleq x\rightarrow g(f(x))\quad.\label{eq:def-of-forward-composition} @@ -4663,7 +4679,7 @@ is defined as \begin_inset Quotes eld \end_inset -is equal by definition +is equal by definition to \begin_inset Quotes erd \end_inset @@ -4671,7 +4687,7 @@ is equal by definition \end_layout \begin_layout Standard -We could implement the forward composition as a fully parametric function: +We may implement the forward composition as a fully parametric function: \begin_inset listings inline false status open @@ -4741,7 +4757,7 @@ backward composition \end_inset . - Using the symbol + This operation is denoted by the symbol \begin_inset Formula $\circ$ \end_inset @@ -4753,7 +4769,7 @@ after \begin_inset Quotes erd \end_inset -) for this operation, we can write: +): \begin_inset Formula \begin{equation} f\circ g\triangleq x\rightarrow f(g(x))\quad.\label{eq:def-of-backward-composition} @@ -4826,7 +4842,7 @@ uncurried \end_inset - defined by the Scala library. + from the Scala library. As an illustration, here is the code for the \series bold uncurrying @@ -4981,8 +4997,7 @@ laws \begin_inset Quotes erd \end_inset - that follow directly from the definitions. - These laws are: +: \end_layout \begin_layout Itemize @@ -5096,9 +5111,9 @@ The composition of the identity function with an arbitrary function \end_inset -To prove that these laws hold, we need to show that both sides of the laws, - which are functions, give the same result when applied to an arbitrary - value +To prove that these laws hold, we need to show that the functions at both + sides of the laws give the same result when applied to an arbitrary value + \begin_inset Formula $x$ \end_inset @@ -5617,7 +5632,7 @@ noprefix "false" \end_inset . - Using the definition + Using definition \begin_inset space ~ \end_inset @@ -5631,7 +5646,7 @@ noprefix "false" \end_inset -) of the forward composition, we find: +) for the forward composition, we find: \begin_inset Formula \begin{align*} \left((f\bef g)\bef h\right)(x) & =h\left(\left(f\bef g\right)(x)\right)=h(g(f(x)))\quad,\\ @@ -5640,7 +5655,7 @@ noprefix "false" \end_inset -Both sides of the law are now equal when applied to an arbitrary value +Both sides of the law are equal when applied to an arbitrary value \begin_inset Formula $x$ \end_inset @@ -6507,8 +6522,7 @@ Curried function calls such as \end_layout \begin_layout Standard -Consider a curried nameless function being applied to arguments, such as - +Consider the expression \begin_inset listings inline true status open @@ -6520,8 +6534,7 @@ status open \end_inset -, and compute the result of this function application. - Begin with the argument +, and begin with the curried argument \begin_inset listings inline true status open @@ -6949,8 +6962,8 @@ status open can be written as: \begin_inset Formula \begin{align*} - & (x^{:\text{Int}}\rightarrow y^{:\text{Int}}\rightarrow\gunderline x-y)\left(20\right)\left(4\right)\\ -\text{apply function and substitute }x=20:\quad & =(y^{:\text{Int}}\rightarrow20-\gunderline y)\left(4\right)\\ + & (\gunderline{x^{:\text{Int}}}\rightarrow y^{:\text{Int}}\rightarrow\gunderline x-y)\gunderline{\left(20\right)}\left(4\right)\\ +\text{apply function and substitute }x=20:\quad & =(\gunderline{y^{:\text{Int}}}\rightarrow20-\gunderline y)\gunderline{\left(4\right)}\\ \text{apply function and substitute }y=4:\quad & =20-4=16\quad. \end{align*} @@ -7256,11 +7269,12 @@ In the following examples, some arguments are themselves functions. \end_inset -The result of this expression is a function +The result of this expression cannot be simplified any more. + It is the function \begin_inset Formula $p\rightarrow p(2)$ \end_inset - that will apply + that applies \emph on its \emph default @@ -7297,7 +7311,7 @@ noprefix "false" \end_inset ) to -\begin_inset Formula $p\rightarrow p(2)$ +\begin_inset Formula $x\rightarrow x+4$ \end_inset : @@ -7379,7 +7393,7 @@ Int \end_inset . - Thus, the type of the expression + So, the type of the expression \begin_inset Formula $x\rightarrow x+4$ \end_inset @@ -7387,11 +7401,11 @@ Int \begin_inset Formula $\text{Int}\rightarrow\text{Int}$ \end_inset -, and so must be the type of the argument +, and the type of the argument \begin_inset Formula $p$ \end_inset -. + must be the same. We write \begin_inset Formula $p^{:\text{Int}\rightarrow\text{Int}}$ \end_inset @@ -8625,7 +8639,7 @@ status open \begin_layout Plain Layout -twice(twice)(x => x+3)(10) +twice(twice)(x => x + 3)(10) \end_layout \end_inset @@ -9023,7 +9037,7 @@ status open \begin_layout Plain Layout -twice(twice)(x => x+3) +twice(twice)(x => x + 3) \end_layout \end_inset @@ -9049,7 +9063,7 @@ status open \begin_layout Plain Layout -x => x+3 +x => x + 3 \end_layout \end_inset @@ -9122,7 +9136,7 @@ status open \begin_layout Plain Layout -twice(twice)(x => x+3) +twice(twice)(x => x + 3) \end_layout \end_inset @@ -9139,44 +9153,6 @@ x => x + 12 \end_inset -, unlike -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -twice(twice(x => x+3)) -\end_layout - -\end_inset - -, which equals the function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -x => x + 6 -\end_layout - -\end_inset - - as shown in Example -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-hof-derive-types-2" -plural "false" -caps "false" -noprefix "false" - -\end_inset - . \end_layout @@ -12570,7 +12546,7 @@ noprefix "false" ): \begin_inset Formula \begin{equation} -(f^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(f))(x^{:C}\rightarrow y^{:C\rightarrow D}\rightarrow y(x))(h^{:\text{Int}\rightarrow E}\rightarrow h(10)\quad.\label{eq:example-hof-curried-function-solved2} +(f^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(f))(x^{:C}\rightarrow y^{:C\rightarrow D}\rightarrow y(x))(h^{:\text{Int}\rightarrow E}\rightarrow h(10))\quad.\label{eq:example-hof-curried-function-solved2} \end{equation} \end_inset @@ -13076,12 +13052,29 @@ body : \begin_inset Formula \begin{align*} -\text{substitute }y=f(x):\quad & \left(x\rightarrow f(x)\right)\bef(y\rightarrow\gunderline{g(y)})=\left(x\rightarrow g(f(x))\right)\quad. +\text{substitute }y=f(x):\quad & (x\rightarrow f(x))\bef(\gunderline y\rightarrow\gunderline{g(y)})=\left(x\rightarrow g(f(x))\right)\quad. \end{align*} \end_inset -This allows us to compute the forward compositions left to right: +Here, we substituted +\begin_inset Formula $f(x)$ +\end_inset + + instead of +\begin_inset Formula $y$ +\end_inset + + in +\begin_inset Formula $g(y)$ +\end_inset + + and obtained +\begin_inset Formula $g(f(x))$ +\end_inset + +. + This shows how to compute the forward compositions left to right: \begin_inset Formula \begin{align*} & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef(p\rightarrow p(2))=x\rightarrow(y\rightarrow x(x(y)))(2)=x\rightarrow x(x(2))\quad.\\ @@ -13093,14 +13086,30 @@ This allows us to compute the forward compositions left to right: Computing the pairwise combinations in another order, we get the same result: \begin_inset Formula \begin{align*} - & \left(p\rightarrow p(2)\right)\bef\left(z\rightarrow z+3\right)=p\rightarrow p(2)+3\quad.\\ - & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef\left(p\rightarrow p(2)+3\right)=x\rightarrow\left(y\rightarrow x(x(y))\right)(2)+3\\ +\text{first compute}:\quad & \left(p\rightarrow p(2)\right)\bef\left(z\rightarrow z+3\right)=p\rightarrow p(2)+3\quad.\\ +\text{then compute}:\quad & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef\left(p\rightarrow p(2)+3\right)\\ + & \quad=x\rightarrow\left(y\rightarrow x(x(y))\right)(2)+3\\ & \quad=x\rightarrow x(x(2))+3\quad. \end{align*} \end_inset -Types are inferred as: +This is to be expected due to the associativity law +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:associativity-of-function-composition" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +). + Types are inferred as: \begin_inset Formula \[ \left(x\rightarrow y\rightarrow x(x(y))\right)^{:(\text{Int}\rightarrow\text{Int})\rightarrow(\text{Int}\rightarrow\text{Int})}\bef\left(p\rightarrow p(2)\right)^{:(\text{Int}\rightarrow\text{Int})\rightarrow\text{Int}}\bef\left(z\rightarrow z+3\right)^{:\text{Int}\rightarrow\text{Int}}\quad. @@ -13137,7 +13146,7 @@ We are given a function \begin_inset Formula $q^{:A\rightarrow A}$ \end_inset - and we only know that for any +, and we only know that for any \begin_inset Formula $f^{:A\rightarrow A}$ \end_inset @@ -13599,6 +13608,94 @@ const(const) ? Simplify these code expressions by symbolic calculations. \end_layout +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-hof-simple-1-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-hof-simple-1-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +For the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +twice +\end_layout + +\end_inset + + from Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-hof-derive-types-2" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, show that the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +twice(twice(f))) +\end_layout + +\end_inset + + is the same as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +twice(twice)(f) +\end_layout + +\end_inset + + for any +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f: Int => Int +\end_layout + +\end_inset + +. + +\end_layout + \begin_layout Subsubsection Exercise \begin_inset CommandInset label @@ -13820,7 +13917,7 @@ flip(f) \end_inset - that swaps arguments for any given function + that swaps arguments for any given uncurried function \begin_inset listings inline true status open @@ -14301,7 +14398,7 @@ not \end_inset . - We know only that + We only know that \begin_inset Formula $g$ \end_inset diff --git a/sofp-src/sofp-higher-order-functions.tex b/sofp-src/sofp-higher-order-functions.tex index 5ab4dc296..13550c85d 100644 --- a/sofp-src/sofp-higher-order-functions.tex +++ b/sofp-src/sofp-higher-order-functions.tex @@ -80,8 +80,8 @@ \subsection{Motivation and first examples} functions: the function\textsf{'}s body keeps copies of all the outer-scope values it uses. One sometimes says that the function\textsf{'}s body \textsf{``}closes over\textsf{''} those values; for this reason, nameless functions are also -called \textsf{``}\textbf{\index{closure}closures}\textsf{''}. It would be clearer -to say that nameless functions \textsf{``}capture\textsf{''} values from outer scopes. +called \textsf{``}\textbf{\index{closure}closures}\textsf{''}. One could also say +that nameless functions \textsf{``}capture\textsf{''} values from outer scopes. As another example of the capture of values, consider this code: \begin{lstlisting} @@ -137,9 +137,10 @@ \subsection{Curried and uncurried functions} The type \lstinline!String => String => Unit! is different from \lstinline!(String => String) => Unit!, which is the type of a function returning \lstinline!Unit! and having -a function of type \lstinline!String => String! as its argument. +a single argument of type \lstinline!String => String!. + When an argument\textsf{'}s type is a function type, e.g., \lstinline!String => String!, -it \emph{must} be enclosed in parentheses. +it \emph{must} be enclosed in parentheses, as in \lstinline!(String => String) => Unit!. In general, a curried function takes an argument and returns another function that again takes an argument and returns another function, @@ -192,17 +193,17 @@ \subsection{Curried and uncurried functions} visually corresponds to the curried function\textsf{'}s type signature \lstinline!A => B => C!, which uses the same syntax convention. Also, the syntax \lstinline!(x => y) => z! could not possibly work for a nameless function because matching -a function with the pattern \lstinline!x => y! makes no sense. If -we matched a function such as \lstinline!{ t => t + 20 }! against +a function against the pattern \lstinline!x => y! makes no sense. +If we matched a function such as \lstinline!{ t => t + 20 }! against the pattern \lstinline!x => y! by setting \lstinline!x = t! and \lstinline!y = t + 20!, we would have no value for the bound variable \lstinline!t!. (What would be the integer value of \lstinline!y!?) -So, \lstinline!x => (y => z)! is the only sensible way of inserting -parentheses into \lstinline!x => y => z!. +So, \lstinline!x => (y => z)! is the only sensible way of adding +parentheses to \lstinline!x => y => z!. Although the code \lstinline!(x => y) => z! is invalid, the type expression \lstinline!(A => B) => C! is valid. We may write a nameless -function of type \lstinline!(A=>B)=>C! as \lstinline!f => expr! +function of type \lstinline!(A => B) => C! as \lstinline!f => expr! where \lstinline!f: A => B! is the argument and \lstinline!expr! the body. @@ -506,14 +507,14 @@ \subsection{Function composition\label{subsec:Examples-of-fully-parametric}} This book denotes the forward composition by the symbol ${\displaystyle \bef}$ (which can be read as \textsf{``}before\textsf{''}). We define $f\bef g$ (reads \textsf{``}$f$ -before $g$\textsf{''}) as: +before $g$\textsf{''}) by: \begin{equation} f\bef g\triangleq x\rightarrow g(f(x))\quad.\label{eq:def-of-forward-composition} \end{equation} The symbol $\triangleq$ means \textsf{``}is defined as\textsf{''} or \textsf{``}is equal -by definition\textsf{''}. +by definition to\textsf{''}. -We could implement the forward composition as a fully parametric function: +We may implement the forward composition as a fully parametric function: \begin{lstlisting} def andThen[X, Y, Z](f: X => Y)(g: Y => Z): X => Z = { x => g(f(x)) } \end{lstlisting} @@ -525,8 +526,8 @@ \subsection{Function composition\label{subsec:Examples-of-fully-parametric}} The \textbf{backward composition}\index{backward composition} of two functions $f$ and $g$ works in the opposite order: first $g$ -is applied and then $f$. Using the symbol $\circ$ (pronounced \textsf{``}after\textsf{''}) -for this operation, we can write: +is applied and then $f$. This operation is denoted by the symbol +$\circ$ (pronounced \textsf{``}after\textsf{''}): \begin{equation} f\circ g\triangleq x\rightarrow f(g(x))\quad.\label{eq:def-of-backward-composition} \end{equation} @@ -538,8 +539,8 @@ \subsection{Function composition\label{subsec:Examples-of-fully-parametric}} \end{lstlisting} We have already seen the methods \lstinline!curried! and \lstinline!uncurried! -defined by the Scala library. As an illustration, here is the code -for the \textbf{uncurrying}\index{uncurrying} transformation (converting +from the Scala library. As an illustration, here is the code for the +\textbf{uncurrying}\index{uncurrying} transformation (converting curried functions to uncurried): \begin{lstlisting} def uncurry[A, B, R](f: A => B => R): ((A, B)) => R = { case (a, b) => f(a)(b) } @@ -559,8 +560,7 @@ \subsection{Function composition\label{subsec:Examples-of-fully-parametric}} \subsection{Laws of function composition\label{subsec:Laws-of-function-composition}} The operations of function composition, introduced in Section~\ref{subsec:Examples-of-fully-parametric}, -have three important properties or \textsf{``}laws\textsf{''} that follow directly -from the definitions. These laws are: +have three important properties or \textsf{``}laws\textsf{''}: \begin{itemize} \item The two \textbf{identity laws}\index{identity laws!of function composition}: the composition of any function $f$ with the identity function (\lstinline!identity[A]!) @@ -584,9 +584,9 @@ \subsection{Laws of function composition\label{subsec:Laws-of-function-compositi {\color{greenunder}\text{left identity law of composition}:}\quad & \text{id}\bef f=f\quad,\\ {\color{greenunder}\text{right identity law of composition}:}\quad & f\bef\text{id}=f\quad. \end{align*} -To prove that these laws hold, we need to show that both sides of -the laws, which are functions, give the same result when applied to -an arbitrary value $x$. Let us first clarify how the type parameters +To prove that these laws hold, we need to show that the functions +at both sides of the laws give the same result when applied to an +arbitrary value $x$. Let us first clarify how the type parameters must be set for all types to match consistently. The laws must hold for an arbitrary function $f$. Assume that $f$ @@ -676,13 +676,13 @@ \subsection{Laws of function composition\label{subsec:Laws-of-function-compositi are functions of type $A\rightarrow D$. To prove that two functions are equal means to prove that they return the same results when applied to the same arguments. So, let us apply both sides of Eq.~(\ref{eq:associativity-law-for-function-composition-with-types}) -to an arbitrary value $x^{:A}$. Using the definition~(\ref{eq:def-of-forward-composition}) -of the forward composition, we find: +to an arbitrary value $x^{:A}$. Using definition~(\ref{eq:def-of-forward-composition}) +for the forward composition, we find: \begin{align*} \left((f\bef g)\bef h\right)(x) & =h\left(\left(f\bef g\right)(x)\right)=h(g(f(x)))\quad,\\ \left(f\bef(g\bef h)\right)(x) & =\left(g\bef h\right)(f(x))=h(g(f(x)))\quad. \end{align*} -Both sides of the law are now equal when applied to an arbitrary value +Both sides of the law are equal when applied to an arbitrary value $x$. This concludes the proof. Because of the associativity law, we do not need parentheses when @@ -851,17 +851,15 @@ \subsection{Calculations with curried functions} may look unfamiliar and confusing. We need to get some experience working with them. -Consider a curried nameless function being applied to arguments, such -as \lstinline!(x => y => x - y)(20)(4)!, and compute the result of -this function application. Begin with the argument \lstinline!20!. -Applying a nameless function of the form \lstinline!(x => ...)! to -\lstinline!20! means substituting \lstinline!x = 20! into the body -of the function. After that substitution, we obtain the expression -\lstinline!y => 20 - y!, which is again a nameless function. Applying -that function to the remaining argument \lstinline!(4)! means substituting -\lstinline!y = 4! into the body of \lstinline!y => 20 - y!. We get -the expression \lstinline!20 - 4!, which equals \lstinline!16!. -Check the result in Scala: +Consider the expression \lstinline!(x => y => x - y)(20)(4)!, and +begin with the curried argument \lstinline!20!. Applying a nameless +function of the form \lstinline!(x => ...)! to \lstinline!20! means +substituting \lstinline!x = 20! into the body of the function. After +that substitution, we obtain the expression \lstinline!y => 20 - y!, +which is again a nameless function. Applying that function to the +remaining argument \lstinline!(4)! means substituting \lstinline!y = 4! +into the body of \lstinline!y => 20 - y!. We get the expression \lstinline!20 - 4!, +which equals \lstinline!16!. Check the result in Scala: \begin{lstlisting} scala> ((x: Int) => (y: Int) => x - y)(20)(4) res1: Int = 16 @@ -895,8 +893,8 @@ \subsection{Calculations with curried functions} The symbolic evaluation of the Scala code \lstinline!((x: Int) => (y: Int) => x - y)(20)(4)! can be written as: \begin{align*} - & (x^{:\text{Int}}\rightarrow y^{:\text{Int}}\rightarrow\gunderline x-y)\left(20\right)\left(4\right)\\ -{\color{greenunder}\text{apply function and substitute }x=20:}\quad & =(y^{:\text{Int}}\rightarrow20-\gunderline y)\left(4\right)\\ + & (\gunderline{x^{:\text{Int}}}\rightarrow y^{:\text{Int}}\rightarrow\gunderline x-y)\gunderline{\left(20\right)}\left(4\right)\\ +{\color{greenunder}\text{apply function and substitute }x=20:}\quad & =(\gunderline{y^{:\text{Int}}}\rightarrow20-\gunderline y)\gunderline{\left(4\right)}\\ {\color{greenunder}\text{apply function and substitute }y=4:}\quad & =20-4=16\quad. \end{align*} In the above step-by-step calculation, the colored underlines and @@ -975,11 +973,11 @@ \subsection{Calculations with curried functions} {\color{greenunder}\text{substitute }f=\left(g\rightarrow g(2)\right):}\quad & =p\rightarrow(g\rightarrow\gunderline g(2))\,(p)\nonumber \\ {\color{greenunder}\text{substitute }g=p:}\quad & =p\rightarrow p(2)\quad.\label{eq:higher-order-functions-derivation1} \end{align} -The result of this expression is a function $p\rightarrow p(2)$ that -will apply \emph{its} argument $p$ to the value $2$. A possible -value for $p$ is the function $x\rightarrow x+4$. So, let us apply -the expression in Eq.~(\ref{eq:higher-order-functions-derivation0}) -to $p\rightarrow p(2)$: +The result of this expression cannot be simplified any more. It is +the function $p\rightarrow p(2)$ that applies \emph{its} argument +$p$ to the value $2$. A possible value for $p$ is the function +$x\rightarrow x+4$. So, let us apply the expression in Eq.~(\ref{eq:higher-order-functions-derivation0}) +to $x\rightarrow x+4$: \begin{align*} & \gunderline{\left(f\rightarrow p\rightarrow f(p)\right)\left(g\rightarrow g(2)\right)}\left(x\rightarrow x+4\right)\\ {\color{greenunder}\text{use Eq.~(\ref{eq:higher-order-functions-derivation1})}:}\quad & =(p\rightarrow\gunderline p(2))\left(x\rightarrow x+4\right)\\ @@ -997,8 +995,8 @@ \subsection{Calculations with curried functions} a function that takes $p$ as an argument. The variable $x$ in $x\rightarrow x+4$ must be of type \lstinline!Int!. -Thus, the type of the expression $x\rightarrow x+4$ is $\text{Int}\rightarrow\text{Int}$, -and so must be the type of the argument $p$. We write $p^{:\text{Int}\rightarrow\text{Int}}$. +So, the type of the expression $x\rightarrow x+4$ is $\text{Int}\rightarrow\text{Int}$, +and the type of the argument $p$ must be the same. We write $p^{:\text{Int}\rightarrow\text{Int}}$. Finally, we need to make sure that the types match in the function $f\rightarrow p\rightarrow f(p)$. Types match in $f(p)$ if the type @@ -1167,7 +1165,7 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-3}\ref{subsec:Exam Consider the fully parametric function \lstinline!twice! defined in Example~\ref{subsec:Example-hof-derive-types-2}. What is the most general type of \lstinline!twice(twice)!, and what computation -does it perform? Test your answer on the expression \lstinline!twice(twice)(x => x+3)(10)!. +does it perform? Test your answer on the expression \lstinline!twice(twice)(x => x + 3)(10)!. What are the type parameters in that expression? \subparagraph{Solution} @@ -1214,8 +1212,8 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-3}\ref{subsec:Exam This clearly shows that \lstinline!twice(twice)! is a function applying its (function-typed) argument \emph{four} times. -The types in \lstinline!twice(twice)(x => x+3)! follow from Eq.~(\ref{eq:hof-twice-example-solved3}): -since \lstinline!x => x+3! has type \lstinline!Int => Int!, types +The types in \lstinline!twice(twice)(x => x + 3)! follow from Eq.~(\ref{eq:hof-twice-example-solved3}): +since \lstinline!x => x + 3! has type \lstinline!Int => Int!, types will match only if we set $B=\text{Int}$. The result is \lstinline!twice[Int => Int](twice[Int])!. To test, we need to write at least one type parameter in the code, or else Scala cannot correctly infer the types in \lstinline!twice(twice)!: @@ -1223,9 +1221,8 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-3}\ref{subsec:Exam scala> twice(twice[Int])(x => x + 3)(10) // Or write `twice[Int => Int](twice)(x => x + 3)(10)` . res0: Int = 22 \end{lstlisting} -This confirms that \lstinline!twice(twice)(x => x+3)! equals the -function \lstinline!x => x + 12!, unlike \lstinline!twice(twice(x => x+3))!, -which equals the function \lstinline!x => x + 6! as shown in Example~\ref{subsec:Example-hof-derive-types-2}. +This confirms that \lstinline!twice(twice)(x => x + 3)! equals the +function \lstinline!x => x + 12!. \subsubsection{Example \label{subsec:Example-hof-derive-types-4}\ref{subsec:Example-hof-derive-types-4}} @@ -1621,7 +1618,7 @@ \subsubsection{Example \label{subsec:Example-hof-curried}\ref{subsec:Example-hof The types must match in the entire expression~(\ref{eq:example-hof-curried-function-solved1}): \begin{equation} -(f^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(f))(x^{:C}\rightarrow y^{:C\rightarrow D}\rightarrow y(x))(h^{:\text{Int}\rightarrow E}\rightarrow h(10)\quad.\label{eq:example-hof-curried-function-solved2} +(f^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(f))(x^{:C}\rightarrow y^{:C\rightarrow D}\rightarrow y(x))(h^{:\text{Int}\rightarrow E}\rightarrow h(10))\quad.\label{eq:example-hof-curried-function-solved2} \end{equation} It follows that $f$ must have the same type as $x\rightarrow y\rightarrow y(x)$, while $g$ must have the same type as $h\rightarrow h(10)$. The type @@ -1702,9 +1699,11 @@ \subsubsection{Example \label{subsec:Example-hof-composition}\ref{subsec:Example The forward composition $f\bef g$ substitutes the \emph{body} of $f$ into the argument of $g$: \begin{align*} -{\color{greenunder}\text{substitute }y=f(x):}\quad & \left(x\rightarrow f(x)\right)\bef(y\rightarrow\gunderline{g(y)})=\left(x\rightarrow g(f(x))\right)\quad. +{\color{greenunder}\text{substitute }y=f(x):}\quad & (x\rightarrow f(x))\bef(\gunderline y\rightarrow\gunderline{g(y)})=\left(x\rightarrow g(f(x))\right)\quad. \end{align*} -This allows us to compute the forward compositions left to right: +Here, we substituted $f(x)$ instead of $y$ in $g(y)$ and obtained +$g(f(x))$. This shows how to compute the forward compositions left +to right: \begin{align*} & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef(p\rightarrow p(2))=x\rightarrow(y\rightarrow x(x(y)))(2)=x\rightarrow x(x(2))\quad.\\ & \left(x\rightarrow x(x(2))\right)\bef\left(z\rightarrow z+3\right)=x\rightarrow x(x(2))+3\quad. @@ -1712,10 +1711,12 @@ \subsubsection{Example \label{subsec:Example-hof-composition}\ref{subsec:Example Computing the pairwise combinations in another order, we get the same result: \begin{align*} - & \left(p\rightarrow p(2)\right)\bef\left(z\rightarrow z+3\right)=p\rightarrow p(2)+3\quad.\\ - & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef\left(p\rightarrow p(2)+3\right)=x\rightarrow\left(y\rightarrow x(x(y))\right)(2)+3\\ +{\color{greenunder}\text{first compute}:}\quad & \left(p\rightarrow p(2)\right)\bef\left(z\rightarrow z+3\right)=p\rightarrow p(2)+3\quad.\\ +{\color{greenunder}\text{then compute}:}\quad & \left(x\rightarrow y\rightarrow x(x(y))\right)\bef\left(p\rightarrow p(2)+3\right)\\ + & \quad=x\rightarrow\left(y\rightarrow x(x(y))\right)(2)+3\\ & \quad=x\rightarrow x(x(2))+3\quad. \end{align*} +This is to be expected due to the associativity law~(\ref{eq:associativity-of-function-composition}). Types are inferred as: \[ \left(x\rightarrow y\rightarrow x(x(y))\right)^{:(\text{Int}\rightarrow\text{Int})\rightarrow(\text{Int}\rightarrow\text{Int})}\bef\left(p\rightarrow p(2)\right)^{:(\text{Int}\rightarrow\text{Int})\rightarrow\text{Int}}\bef\left(z\rightarrow z+3\right)^{:\text{Int}\rightarrow\text{Int}}\quad. @@ -1724,7 +1725,7 @@ \subsubsection{Example \label{subsec:Example-hof-composition}\ref{subsec:Example \subsubsection{Example \label{subsec:Example-hof-const-function}\ref{subsec:Example-hof-const-function}} -We are given a function $q^{:A\rightarrow A}$ and we only know that +We are given a function $q^{:A\rightarrow A}$, and we only know that for any $f^{:A\rightarrow A}$ the law $f\bef q=q\bef f$ holds (i.e., $q$ commutes with every function). Show that $q$ must be an identity function. @@ -1790,6 +1791,12 @@ \subsubsection{Exercise \label{subsec:Exercise-hof-simple-1}\ref{subsec:Exercise \lstinline!id(const)!, and \lstinline!const(const)!? Simplify these code expressions by symbolic calculations. +\subsubsection{Exercise \label{subsec:Exercise-hof-simple-1-1}\ref{subsec:Exercise-hof-simple-1-1}} + +For the function \lstinline!twice! from Example~\ref{subsec:Example-hof-derive-types-2}, +show that the function \lstinline!twice(twice(f)))! is the same as +\lstinline!twice(twice)(f)! for any \lstinline!f: Int => Int!. + \subsubsection{Exercise \label{subsec:Exercise-hof-simple-3}\ref{subsec:Exercise-hof-simple-3}} For the function \lstinline!twice! from Example~\ref{subsec:Example-hof-derive-types-2}, @@ -1811,8 +1818,8 @@ \subsubsection{Exercise \label{subsec:Exercise-hof-simple-5}\ref{subsec:Exercise \subsubsection{Exercise \label{subsec:Exercise-hof-simple-6}\ref{subsec:Exercise-hof-simple-6}} Define a fully parametric function \lstinline!flip(f)! that swaps -arguments for any given function \lstinline!f! having two arguments. -To test: +arguments for any given uncurried function \lstinline!f! having two +arguments. To test: \begin{lstlisting} def f(x: Int, y: Int) = x - y // Expect f(10, 2) == 8. @@ -1886,7 +1893,7 @@ \subsubsection{Exercise \label{subsec:Exercise-hof-composition-1}\ref{subsec:Exe ignore its argument and return a fixed value of type $B$. \textbf{(b)} We are given two functions $g^{:A\rightarrow A}$ and -$h^{:B\rightarrow B}$. We know only that $g$ and $h$ satisfy the +$h^{:B\rightarrow B}$. We only know that $g$ and $h$ satisfy the law $f^{:A\rightarrow B}\bef h^{:B\rightarrow B}=g^{:A\rightarrow A}\bef f^{:A\rightarrow B}$ for any function $f^{:A\rightarrow B}$. Prove that both $g$ and $h$ must be equal to identity functions of suitable types: $g^{:A\rightarrow A}=\text{id}^{A}$ diff --git a/sofp-src/sofp-induction.lyx b/sofp-src/sofp-induction.lyx index 9c08c582b..e002fe9ac 100644 --- a/sofp-src/sofp-induction.lyx +++ b/sofp-src/sofp-induction.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -1362,12 +1362,13 @@ status open \begin_layout Plain Layout -{case (a, b, c) => ...} +{ case (a, b, c) => ... + } \end_layout \end_inset - called a + is called a \series bold case expression \series default @@ -3072,7 +3073,8 @@ res1: Map[String,Int] = Map(apples -> 6, pears -> 4, lemons -> 0) \begin_layout Plain Layout -scala> fruitBasket.map { case (fruit, count) => (fruit, count, count*2) }. +scala> fruitBasket.map { case (fruit, count) => (fruit, count, count * 2) + }. \end_layout \begin_layout Plain Layout @@ -3590,8 +3592,8 @@ flatMap \end_inset - operation transforms a sequence by mapping each element to possibly a different - number of new elements. + operation transforms a sequence by replacing each element by some number + (zero or more) of new elements. \end_layout \begin_layout Standard @@ -3972,7 +3974,7 @@ sortBy function \emph default that computes the sorting key from a sequence element. - In this way, we can sort elements in an arbitrary way: + This gives us flexibility to elements in a custom way: \begin_inset listings inline false status open @@ -4189,7 +4191,7 @@ For a given sequence \end_inset , compute the sequence of pairs of values -\begin_inset Formula $\left(\cos x_{i},\sin x_{i}\right)$ +\begin_inset Formula $\left(\cos x_{i},\,\sin x_{i}\right)$ \end_inset . @@ -4675,11 +4677,7 @@ ps.tail \end_inset . - The result is a sequence that is -\begin_inset Formula $1$ -\end_inset - - element shorter than + The result is a sequence that is one element shorter than \begin_inset listings inline true status open @@ -4775,7 +4773,7 @@ res1: Seq[(Int, Int)] = List((1,2), (2,3), (3,4)) \end_inset -Note that +Because \begin_inset listings inline true status open @@ -4799,7 +4797,7 @@ ps \end_inset -, and the resulting sequence of pairs is also one element shorter than +, the resulting sequence of pairs is also one element shorter than \begin_inset listings inline true status open @@ -5757,7 +5755,7 @@ s: List[((Int, Int), Int)] = List(((1,1),1), ((1,2),2), ((1,3),3), ((2,1),2), \end_inset -It remains to convert this list of tuples to a dictionary with +Applying \begin_inset listings inline true status open @@ -5769,8 +5767,8 @@ toMap \end_inset -. - Also, for better readability, we can use Scala's pair syntax, +, we convert this list of tuples to a dictionary. + Also, for better readability, we use Scala's pair syntax, \begin_inset listings inline true status open @@ -5919,8 +5917,7 @@ status open \begin_layout Plain Layout -scala> val xs = List(0.1, 0.5, 0.9) // An example list of some `Double` - numbers. +scala> val xs = List(0.1, 0.5, 0.9) // An example list of `Double` values. \end_layout \begin_layout Plain Layout @@ -6310,9 +6307,7 @@ noprefix "false" \end_inset ; only the type signature changes. - This is because the procedure for reversing a dictionary works in the same - way for dictionaries of any type. - So the body of the function + This is because the function \begin_inset listings inline true status open @@ -6324,8 +6319,7 @@ rev \end_inset - does not actually need to know the types of the keys and values in the - dictionary. + works in the same way for dictionaries of any type. For this reason, it was easy for us to change the specific type \begin_inset listings inline true @@ -10811,7 +10805,7 @@ def digitsToInt(s: Seq[Int]): Int = if (s.isEmpty) 0 else { \begin_layout Plain Layout - val x = s.last // To split s = xs :+ x, compute x + val x = s.last // To split s = xs :+ x, compute x \end_layout \begin_layout Plain Layout @@ -10821,7 +10815,7 @@ def digitsToInt(s: Seq[Int]): Int = if (s.isEmpty) 0 else { \begin_layout Plain Layout - digitsToInt(xs) * 10 + x // Call digitsToInt(...) recursively. + digitsToInt(xs) * 10 + x // Call digitsToInt(...) recursively. \end_layout \begin_layout Plain Layout @@ -11063,17 +11057,7 @@ status open \begin_layout Plain Layout -def lengthS(s: Seq[Int]): Int = -\end_layout - -\begin_layout Plain Layout - - if (s.isEmpty) 0 -\end_layout - -\begin_layout Plain Layout - - else 1 + lengthS(s.tail) +def lengthS(s: Seq[Int]): Int = if (s.isEmpty) 0 else 1 + lengthS(s.tail) \end_layout \begin_layout Plain Layout @@ -11188,7 +11172,7 @@ status open \end_inset . - So, we can visualize how the computer evaluates that code: + Let us visualize how the computer evaluates that code: \begin_inset listings inline false status open @@ -11268,10 +11252,10 @@ if/else \end_inset , about -\begin_inset Formula $100$ +\begin_inset Formula $100000$ \end_inset - thousand times. + times. Each time, the intermediate sub-expression with nested computations \begin_inset listings inline true @@ -12339,7 +12323,7 @@ status open \begin_layout Plain Layout -@tailrec def fromDigits(s: Seq[Int], res: Int = 0):Int = +@tailrec def fromDigits(s: Seq[Int], res: Int = 0): Int = \end_layout \begin_layout Plain Layout @@ -13161,7 +13145,7 @@ def f[A, B](s: Seq[A]): B = \end_inset -We can now refactor this code into a generic utility function, by making +We can now refactor this code into a generic utility function, by turning \begin_inset listings inline true @@ -15062,7 +15046,7 @@ foldLeft \emph on be \emph default - the accumulator value. + that accumulator value. So, we need to update the accumulator by appending the value \begin_inset listings inline true @@ -18643,7 +18627,7 @@ status open \end_inset -, +: \begin_inset listings inline false status open @@ -18701,7 +18685,7 @@ Stream.iterate \end_inset - can be written as + can be written as: \begin_inset listings inline false status open @@ -18852,7 +18836,7 @@ scanLeft implements a general sequence-to-sequence transformation defined in this way. - The code implementing the partial sums is + The code implementing the partial sums is: \begin_inset listings inline false status open @@ -19463,8 +19447,8 @@ What problems cannot be solved with these tools? \end_layout \begin_layout Standard -We cannot implement a non-tail-recursive function without stack overflow - (i.e., without unlimited growth of intermediate expressions). +There is no automatic recipe for converting an arbitrary function into a + tail-recursive one. The accumulator trick does not always work! In some cases, it is impossible to implement tail recursion in a given recursive computation. An example of such a computation is the @@ -19905,10 +19889,9 @@ scanLeft \end_inset values that we sort and truncate each time. - Second, to use a specialized data structure such as a priority queue that - automatically keeps values sorted and its length bounded. - For the purposes of this example, let us avoid using specialized data structure -s: + Second, to use a data structure such as a priority queue that automatically + keeps values sorted and its length bounded. + For the purposes of this example, let us avoid using special data structures: \begin_inset listings inline false status open @@ -20285,7 +20268,7 @@ s.split( \end_inset -, and apply a + and apply a \begin_inset listings inline true status open @@ -20350,14 +20333,19 @@ def countWords(s: String): Map[String, Int] = { \end_inset -An alternative, shorter implementation of the same function is +An alternative, shorter implementation of the same function is: \begin_inset listings inline false status open \begin_layout Plain Layout -def countWords(s: String): Map[String, Int] = s.split( +def countWords(s: String): Map[String, Int] = +\end_layout + +\begin_layout Plain Layout + + s.split( \begin_inset Quotes eld \end_inset @@ -20365,7 +20353,7 @@ def countWords(s: String): Map[String, Int] = s.split( \begin_inset Quotes eld \end_inset -).groupBy(w => w).mapValues(_.length) +).groupBy(w => w).map { case (w, xs) => (w, xs.length) } \end_layout \end_inset @@ -20391,12 +20379,12 @@ status open \begin_layout Plain Layout -mapValues +map \end_layout \end_inset -: + to compute the length of each word list: \begin_inset listings inline false status open @@ -20418,7 +20406,7 @@ res0: Map[String,Array[String]] = Map(b -> Array(b, b, b), a -> Array(a, \begin_layout Plain Layout -scala> res0.mapValues(_.length) +scala> res0.map { case (w, xs) => (w, xs.length) } \end_layout \begin_layout Plain Layout @@ -20595,26 +20583,7 @@ binary search \end_inset - algorithm -\begin_inset Foot -status open - -\begin_layout Plain Layout - -\family typewriter -\begin_inset CommandInset href -LatexCommand href -target "https://en.wikipedia.org/wiki/Binary_search_algorithm" -literal "false" - -\end_inset - - -\end_layout - -\end_inset - - for a sorted sequence + algorithm for a sorted sequence \begin_inset listings inline true status open @@ -21719,7 +21688,33 @@ None \end_inset . - An example test: + (The type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Option +\end_layout + +\end_inset + + is explained in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Standard-disjunctive-types:" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +.) An example test: \begin_inset listings inline false status open @@ -22913,23 +22908,12 @@ dynamic programming \end_inset -dynamic programming -\begin_inset Foot -status open - -\begin_layout Plain Layout - -\family typewriter -\begin_inset CommandInset href -LatexCommand href -target "https://en.wikipedia.org/wiki/Dynamic_programming" -literal "false" +\begin_inset Quotes eld \end_inset - -\end_layout - +dynamic programming +\begin_inset Quotes erd \end_inset problem. @@ -22946,23 +22930,8 @@ foldLeft \end_inset . - The accumulator represents the current -\begin_inset Quotes eld -\end_inset - -state -\begin_inset Quotes erd -\end_inset - - of the dynamic programming solution, and the -\begin_inset Quotes eld -\end_inset - -state -\begin_inset Quotes erd -\end_inset - - is updated with each new element of the input sequence. + The accumulator represents the current state of the dynamic programming + solution, and the state is updated with each new element of the input sequence. \end_layout \begin_layout Standard @@ -24500,6 +24469,10 @@ not . +\end_layout + +\begin_layout Standard + \series bold (b) \series default @@ -24512,7 +24485,10 @@ not \end_inset with the largest sum of decimal digits. - +\end_layout + +\begin_layout Standard + \series bold (c) \series default @@ -24534,19 +24510,23 @@ perfect numbers \end_inset - if it is equal to the sum of its divisors (other integers + if it is equal to the sum of its divisors (integers \begin_inset Formula $k$ \end_inset such that -\begin_inset Formula $k Option[(A,B)]): Stream[B] +def unfold2[A, B](init: A)(next: A => Option[(A, B)]): Stream[B] \end_layout \end_inset @@ -25025,7 +25005,7 @@ status open \begin_layout Plain Layout -xs:Seq[Double] +xs: Seq[Double] \end_layout \end_inset @@ -25084,7 +25064,7 @@ dynamic programming \end_inset -dynamic programming and +dynamic programming techniques and \begin_inset listings inline true status open @@ -25209,8 +25189,7 @@ max \end_inset method: it only works for non-empty sequences. - Trying to evaluate it on an empty sequence generates an error called an - + Trying to evaluate it on an empty sequence generates an error (an \begin_inset Quotes eld \end_inset @@ -25228,7 +25207,7 @@ exception \begin_inset Quotes erd \end_inset -: +): \begin_inset listings lstparams "mathescape=false" inline false @@ -25298,9 +25277,9 @@ run-time error \end_inset - occur while the program is running, and only when some partial function - happens to get an incorrect input. - The incorrect input may occur at any point after the program started running, + occur while the program is running and only when an invalid situation actually + happens — say, when some partial function gets an incorrect input. + The incorrect input may occur at any time after the program started running, which may crash the entire program in the middle of a long computation. \end_layout @@ -25335,7 +25314,7 @@ If a pattern matching expression fails, the code will throw an exception it makes it much harder to reason about program correctness. In most cases, programs can be written to avoid the possibility of match errors. - An example of an unsafe pattern matching expression is + An example of an unsafe pattern matching expression is: \begin_inset listings lstparams "mathescape=false" inline false @@ -25387,7 +25366,7 @@ scala> h( (1,2) ) \end_inset -Here the pattern contains a pattern variable +Here, the pattern contains a pattern variable \begin_inset listings inline true status open @@ -25456,7 +25435,7 @@ status open \end_inset -, because a pattern variable will always match a value. +, because each pattern variable will always match a value. So, pattern matching with a pattern such as \begin_inset listings inline true @@ -25505,13 +25484,13 @@ p match { \begin_layout Plain Layout case (x, 0) => ... - // This only matches some tuples. + // This only matches certain tuples. \end_layout \begin_layout Plain Layout case _ => ... - // This matches everything. + // This matches everything else. \end_layout \begin_layout Plain Layout @@ -25620,8 +25599,8 @@ local scope \series default - variables — that is, variables defined only on the right-hand side of the - pattern match expression. + variables — that is, variables accessible only within the right-hand side + of the pattern match expression. As an example, consider this code: \begin_inset listings inline false @@ -25759,7 +25738,7 @@ x:(Int,Int) \end_inset - is a completely different variable whose value has a different type. + is a completely different variable that has a different type. \end_layout \begin_layout Standard @@ -26263,7 +26242,7 @@ on-call value \end_inset is re-computed every time it is used. - In Scala, a + In Scala, on-call values are denoted via \begin_inset listings inline true status open @@ -26275,7 +26254,7 @@ def \end_inset - declaration does that (as well as call-by-name arguments). + declarations as well as via call-by-name function arguments. \end_layout \begin_layout Standard @@ -27062,10 +27041,20 @@ functional purity \end_inset . - After applying a pure function, we can be sure that, for instance, no hidden + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +After applying a pure function, we can be sure that, for instance, no hidden values in memory have been modified. \end_layout +\end_inset + + +\end_layout + \begin_layout Standard When we set \begin_inset Formula $x=100$ diff --git a/sofp-src/sofp-induction.tex b/sofp-src/sofp-induction.tex index 8be037aa9..ed5c2eef3 100644 --- a/sofp-src/sofp-induction.tex +++ b/sofp-src/sofp-induction.tex @@ -151,18 +151,19 @@ \subsection{Pattern matching for tuples} scala> (1, 2, 3) match { case (a, b, c) => a + b + c } res0: Int = 6 \end{lstlisting} -The expression \lstinline!{case (a, b, c) => ...}! called a \textbf{case -expression}\index{case expression@\texttt{case} expression}. It performs -pattern matching on its argument. The pattern matching will \textsf{``}destructure\textsf{''} -(i.e., decompose) a tuple and try to match it to the given pattern -\lstinline!(a, b, c)!. In this pattern, \lstinline!a!, \lstinline!b!, -\lstinline!c! are as yet undefined new variables, \textemdash{} that -is, they are \index{pattern variables}pattern variables. If the pattern -matching succeeds, the pattern variables \lstinline!a!, \lstinline!b!, -\lstinline!c! are assigned their values, and the function body can -proceed to perform its computation. In this example, the pattern variables -\lstinline!a!, \lstinline!b!, \lstinline!c! will be assigned values -$1$, $2$, and $3$, and so the expression evaluates to $6$. +The expression \lstinline!{ case (a, b, c) => ... }! is called a +\textbf{case expression}\index{case expression@\texttt{case} expression}. +It performs pattern matching on its argument. The pattern matching +will \textsf{``}destructure\textsf{''} (i.e., decompose) a tuple and try to match +it to the given pattern \lstinline!(a, b, c)!. In this pattern, \lstinline!a!, +\lstinline!b!, \lstinline!c! are as yet undefined new variables, +\textemdash{} that is, they are \index{pattern variables}pattern +variables. If the pattern matching succeeds, the pattern variables +\lstinline!a!, \lstinline!b!, \lstinline!c! are assigned their +values, and the function body can proceed to perform its computation. +In this example, the pattern variables \lstinline!a!, \lstinline!b!, +\lstinline!c! will be assigned values $1$, $2$, and $3$, and so +the expression evaluates to $6$. Pattern matching is especially convenient for nested tuples. Here is an example where a nested tuple \lstinline!p! is destructured @@ -376,7 +377,7 @@ \subsection{Treating dictionaries as collections} scala> fruitBasket.map { case (fruit, count) => (fruit, count * 2) } res1: Map[String,Int] = Map(apples -> 6, pears -> 4, lemons -> 0) -scala> fruitBasket.map { case (fruit, count) => (fruit, count, count*2) }. +scala> fruitBasket.map { case (fruit, count) => (fruit, count, count * 2) }. map { case (fruit, _, count2) => (fruit, count2 / 2) }.toMap res2: Map[String,Int] = Map(apples -> 3, pears -> 2, lemons -> 0) \end{lstlisting} @@ -469,8 +470,8 @@ \subsection{Treating dictionaries as collections} scala> List(1, 2, 3, 4).flatMap(n => (1 to n).toList) res11: List[Int] = List(1, 1, 2, 1, 2, 3, 1, 2, 3, 4) \end{lstlisting} -The \lstinline!flatMap! operation transforms a sequence by mapping -each element to possibly a different number of new elements. +The \lstinline!flatMap! operation transforms a sequence by replacing +each element by some number (zero or more) of new elements. At first sight it may be unclear why \lstinline!flatMap! is useful, as \lstinline!map! and \lstinline!flatten! appear to be unrelated. @@ -531,7 +532,7 @@ \subsection{Treating dictionaries as collections} sorts a sequence according to a sorting key. The argument of \lstinline!sortBy! is a \emph{function} that computes the sorting key from a sequence -element. In this way, we can sort elements in an arbitrary way: +element. This gives us flexibility to elements in a custom way: \begin{lstlisting} scala> Seq(1, 2, 3).sortBy(x => -x) res0: Seq[Int] = List(3, 2, 1) @@ -558,7 +559,7 @@ \subsection{Examples: Tuples and collections\index{examples (with code)}} \subsubsection{Example \label{enu:tuples-Example1-for}\ref{enu:tuples-Example1-for}} For a given sequence $x_{i}$, compute the sequence of pairs of values -$\left(\cos x_{i},\sin x_{i}\right)$. +$\left(\cos x_{i},\,\sin x_{i}\right)$. Hint: use \lstinline!map!, assume \lstinline!xs: Seq[Double]!. @@ -628,7 +629,7 @@ \subsubsection{Example \label{enu:tuples-Example4-in}\ref{enu:tuples-Example4-in \subparagraph{Solution} Given \lstinline!ps: Seq[Double]!, we can compute \lstinline!ps.tail!. -The result is a sequence that is $1$ element shorter than \lstinline!ps!, +The result is a sequence that is one element shorter than \lstinline!ps!, for example: \begin{lstlisting} scala> val ps = Seq(1,2,3,4) @@ -643,11 +644,10 @@ \subsubsection{Example \label{enu:tuples-Example4-in}\ref{enu:tuples-Example4-in scala> ps.zip(ps.tail) res1: Seq[(Int, Int)] = List((1,2), (2,3), (3,4)) \end{lstlisting} -Note that \lstinline!ps.tail! is one element shorter than \lstinline!ps!, -and the resulting sequence of pairs is also one element shorter than -\lstinline!ps!. So, it is not necessary to truncate \lstinline!ps! -before computing \lstinline!ps.zip(ps.tail)!. Now apply the \lstinline!count! -method: +Because \lstinline!ps.tail! is one element shorter than \lstinline!ps!, +the resulting sequence of pairs is also one element shorter than \lstinline!ps!. +So, it is not necessary to truncate \lstinline!ps! before computing +\lstinline!ps.zip(ps.tail)!. Now apply the \lstinline!count! method: \begin{lstlisting} ps.zip(ps.tail).count { case (a, b) => a > b } @@ -769,8 +769,8 @@ \subsubsection{Example \label{subsec:tuples-Example6}\ref{subsec:tuples-Example6 scala> val s = List(1, 2, 3).flatMap(x => List(1, 2, 3).map { y => ((x, y), x * y) } ) s: List[((Int, Int), Int)] = List(((1,1),1), ((1,2),2), ((1,3),3), ((2,1),2), ((2,2),4), ((2,3),6), ((3,1),3), ((3,2),6), ((3,3),9)) \end{lstlisting} -It remains to convert this list of tuples to a dictionary with \lstinline!toMap!. -Also, for better readability, we can use Scala\textsf{'}s pair syntax, \lstinline!key -> value!, +Applying \lstinline!toMap!, we convert this list of tuples to a dictionary. +Also, for better readability, we use Scala\textsf{'}s pair syntax, \lstinline!key -> value!, which is equivalent to writing the tuple \lstinline!(key, value)!: \begin{lstlisting} @@ -791,7 +791,7 @@ \subsubsection{Example \label{subsec:tuples-Example7}\ref{subsec:tuples-Example7 of the list \lstinline!xs: Seq[Double]! into a sequence of three numbers: \begin{lstlisting} -scala> val xs = List(0.1, 0.5, 0.9) // An example list of some `Double` numbers. +scala> val xs = List(0.1, 0.5, 0.9) // An example list of `Double` values. xs: List[Double] = List(0.1, 0.5, 0.9) scala> xs.map { x => Seq(x, x*x, math.cos(x), math.sin(x)) } @@ -854,11 +854,9 @@ \subsubsection{Example \label{subsec:tuples-Example-9}\ref{subsec:tuples-Example dict.map { case (name, addr) => (addr, name) } \end{lstlisting} The body of the function \lstinline!rev! remains the same as in Example~\ref{subsec:tuples-Example8}; -only the type signature changes. This is because the procedure for -reversing a dictionary works in the same way for dictionaries of any -type. So the body of the function \lstinline!rev! does not actually -need to know the types of the keys and values in the dictionary. For -this reason, it was easy for us to change the specific type \lstinline!String! +only the type signature changes. This is because the function \lstinline!rev! +works in the same way for dictionaries of any type. For this reason, +it was easy for us to change the specific type \lstinline!String! into type parameters in that function. When the function \lstinline!rev! is applied to a dictionary of a @@ -1351,9 +1349,9 @@ \subsection{Implementing functions by recursion} definition shown in Section~\ref{subsec:Inductive-definitions-of-aggregation-functions}: \begin{lstlisting} def digitsToInt(s: Seq[Int]): Int = if (s.isEmpty) 0 else { - val x = s.last // To split s = xs :+ x, compute x + val x = s.last // To split s = xs :+ x, compute x val xs = s.take(s.length - 1) // and xs. - digitsToInt(xs) * 10 + x // Call digitsToInt(...) recursively. + digitsToInt(xs) * 10 + x // Call digitsToInt(...) recursively. } \end{lstlisting} In this example, it is important to split the sequence \lstinline!s! @@ -1383,9 +1381,7 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} To see why, consider an inductive definition of the \lstinline!length! method as a function \lstinline!lengthS!: \begin{lstlisting} -def lengthS(s: Seq[Int]): Int = - if (s.isEmpty) 0 - else 1 + lengthS(s.tail) +def lengthS(s: Seq[Int]): Int = if (s.isEmpty) 0 else 1 + lengthS(s.tail) scala> lengthS((1 to 1000).toList) res0: Int = 1000 @@ -1404,7 +1400,7 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} able to compute and hold in memory the entire sequence \lstinline!s!. The problem is with the code of the function \lstinline!lengthS!. This function calls itself \emph{inside} the expression \lstinline!1 + lengthS(...)!. -So, we can visualize how the computer evaluates that code: +Let us visualize how the computer evaluates that code: \begin{lstlisting} lengthS(Seq(1, 2, ..., 100000)) = 1 + lengthS(Seq(2, ..., 100000)) @@ -1413,7 +1409,7 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} \end{lstlisting} The code of \lstinline!lengthS! will repeat the inductive step, that is, the \textsf{``}\lstinline!else!\textsf{''} part of the \textsf{``}\lstinline!if/else!\textsf{''}, -about $100$ thousand times. Each time, the intermediate sub-expression +about $100000$ times. Each time, the intermediate sub-expression with nested computations \lstinline!1 + (1 + (...))! will get larger. That sub-expression needs to be held somewhere in memory until the function body goes into the base case, with no more recursive calls. @@ -1586,7 +1582,7 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} the \emph{leftmost} digit and the rest, \lstinline!s == s.head +: s.tail!. So, a tail-recursive implementation of the above formula is: \begin{lstlisting} -@tailrec def fromDigits(s: Seq[Int], res: Int = 0):Int = +@tailrec def fromDigits(s: Seq[Int], res: Int = 0): Int = // `res` is the accumulator. if (s.isEmpty) res else fromDigits(s.tail, 10 * res + s.head) @@ -1718,7 +1714,7 @@ \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:im else g(s.last, f(s.take(s.length - 1))) \end{lstlisting} We can now refactor this code into a generic utility function, by -making \lstinline!b0! and \lstinline!g! into parameters. A possible +turning \lstinline!b0! and \lstinline!g! into parameters. A possible implementation is: \begin{lstlisting} def f[A, B](s: Seq[A], b: B, g: (A, B) => B): B = @@ -1939,7 +1935,7 @@ \subsubsection{Example \label{subsec:Example-foldleft-6}\ref{subsec:Example-fold of iterating over the input sequence and accumulating some result value, which is updated at each iteration. Since the result of a \lstinline!foldLeft! is always equal to the last computed accumulator value, it follows -that the new sequence should \emph{be} the accumulator value. So, +that the new sequence should \emph{be} that accumulator value. So, we need to update the accumulator by appending the value \lstinline!f(x)!, where \lstinline!x! is the current element of the input sequence: \begin{lstlisting} @@ -2382,7 +2378,7 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin } \end{lstlisting} We can shorten the code by using the syntax \lstinline!(_ % 10)! -instead of \lstinline!{ nk => nk % 10 }!, +instead of \lstinline!{ nk => nk % 10 }!: \begin{lstlisting} def digitsOf(n: Int): Seq[Int] = if (n == 0) Seq(0) else { // n == 0 is a special case. @@ -2394,7 +2390,7 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin \end{lstlisting} The type signature of the method \lstinline!Stream.iterate! can be -written as +written as: \begin{lstlisting} def iterate[A](init: A)(next: A => A): Stream[A] \end{lstlisting} @@ -2421,7 +2417,7 @@ \section{Transforming a sequence into another sequence\label{sec:Transforming-a- \end{itemize} The Scala library method \lstinline!scanLeft! implements a general sequence-to-sequence transformation defined in this way. The code -implementing the partial sums is +implementing the partial sums is: \begin{lstlisting} def partialSums(xs: Seq[Int]): Seq[Int] = xs.scanLeft(0){ (x, y) => x + y } @@ -2520,14 +2516,13 @@ \section{Summary} \paragraph*{What problems cannot be solved with these tools?} -We cannot implement a non-tail-recursive function without stack overflow -(i.e., without unlimited growth of intermediate expressions). The -accumulator trick does not always work! In some cases, it is impossible -to implement tail recursion in a given recursive computation. An example -of such a computation is the \textsf{``}merge-sort\textsf{''} algorithm where the -function body must contain two recursive calls within a single expression. -(It is impossible to rewrite \emph{two} recursive calls as \emph{one} -tail call.) +There is no automatic recipe for converting an arbitrary function +into a tail-recursive one. The accumulator trick does not always work! +In some cases, it is impossible to implement tail recursion in a given +recursive computation. An example of such a computation is the \textsf{``}merge-sort\textsf{''} +algorithm where the function body must contain two recursive calls +within a single expression. (It is impossible to rewrite \emph{two} +recursive calls as \emph{one} tail call.) What if our recursive code cannot be transformed into tail-recursive code via the accumulator trick, but the recursion depth is so large @@ -2597,10 +2592,10 @@ \subsubsection{Example \label{subsec:ch2Example-seq-2}\ref{subsec:ch2Example-seq \textbf{(b)} We again use \lstinline!scanLeft!, where now the accumulator needs to keep the largest $k$ values seen so far. There are two ways of maintaining this accumulator: First, to have a sequence of $k$ -values that we sort and truncate each time. Second, to use a specialized -data structure such as a priority queue that automatically keeps values +values that we sort and truncate each time. Second, to use a data +structure such as a priority queue that automatically keeps values sorted and its length bounded. For the purposes of this example, let -us avoid using specialized data structures: +us avoid using special data structures: \begin{lstlisting} def maxKSoFar(xs: Stream[Int], k: Int): Stream[Seq[Int]] = { // The initial value of the accumulator is an empty Seq() of type Seq[Int]. @@ -2655,7 +2650,7 @@ \subsubsection{Example \label{subsec:ch2Example-seq-9}\ref{subsec:ch2Example-seq \subparagraph{Solution} -\textbf{(a)} We split the string into an array of words via \lstinline!s.split(" ")!, +\textbf{(a)} We split the string into an array of words via \lstinline!s.split(" ")! and apply a \lstinline!foldLeft! to that array, since the computation is a kind of aggregation over the array of words. The accumulator of the aggregation will be the dictionary of word counts for all the @@ -2669,18 +2664,20 @@ \subsubsection{Example \label{subsec:ch2Example-seq-9}\ref{subsec:ch2Example-seq } } \end{lstlisting} -An alternative, shorter implementation of the same function is +An alternative, shorter implementation of the same function is: \begin{lstlisting} -def countWords(s: String): Map[String, Int] = s.split(" ").groupBy(w => w).mapValues(_.length) +def countWords(s: String): Map[String, Int] = + s.split(" ").groupBy(w => w).map { case (w, xs) => (w, xs.length) } \end{lstlisting} The \lstinline!groupBy! creates a dictionary in one function call rather than one entry at a time. But the resulting dictionary contains -word lists instead of word counts, so we use \lstinline!mapValues!: +word lists instead of word counts, so we use \lstinline!map! to compute +the length of each word list: \begin{lstlisting} scala> "a a b b b c".split(" ").groupBy(w => w) res0: Map[String,Array[String]] = Map(b -> Array(b, b, b), a -> Array(a, a), c -> Array(c)) -scala> res0.mapValues(_.length) +scala> res0.map { case (w, xs) => (w, xs.length) } res1: Map[String,Int] = Map(b -> 3, a -> 2, c -> 1) \end{lstlisting} @@ -2704,7 +2701,7 @@ \subsubsection{Example \label{subsec:ch2Example-seq-9}\ref{subsec:ch2Example-seq \subsubsection{Example \label{subsec:ch2Example-binary-search-seq-4}\ref{subsec:ch2Example-binary-search-seq-4}} -\textbf{(a)} Implement the binary search\index{binary search} algorithm\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Binary_search_algorithm}{https://en.wikipedia.org/wiki/Binary\_search\_algorithm}}} +\textbf{(a)} Implement the binary search\index{binary search} algorithm for a sorted sequence \lstinline!xs: Seq[Int]! as a function returning the index of the requested value \lstinline!goal! (assume that \lstinline!xs! always contains \lstinline!goal!): @@ -2875,7 +2872,8 @@ \subsubsection{Example \label{subsec:ch2Example-stream}\ref{subsec:ch2Example-st The function should create a stream of values of type \lstinline!A! with the initial value \lstinline!init!. Next elements are computed from previous ones via the function \lstinline!next! until it returns -\lstinline!None!. An example test: +\lstinline!None!. (The type \lstinline!Option! is explained in Section~\ref{subsec:Standard-disjunctive-types:}.) +An example test: \begin{lstlisting} scala> unfold(0) { x => if (x > 5) None else Some(x + 2) } res0: Stream[Int] = Stream(0, ?) @@ -3071,11 +3069,11 @@ \subsubsection{Example \label{subsec:ch2Example-seq-10-1}\ref{subsec:ch2Example- \subparagraph{Solution} -This is a \index{dynamic programming}dynamic programming\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Dynamic_programming}{https://en.wikipedia.org/wiki/Dynamic\_programming}}} -problem. Many such problems are solved with a single \lstinline!foldLeft!. -The accumulator represents the current \textsf{``}state\textsf{''} of the dynamic -programming solution, and the \textsf{``}state\textsf{''} is updated with each new -element of the input sequence. +This is a \index{dynamic programming}\textsf{``}dynamic programming\textsf{''} problem. +Many such problems are solved with a single \lstinline!foldLeft!. +The accumulator represents the current state of the dynamic programming +solution, and the state is updated with each new element of the input +sequence. We first need to determine the type of the accumulator value, or the \textsf{``}state\textsf{''}. The task is to find the longest subsequence without adjacent @@ -3304,17 +3302,20 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-8-1}\ref{subsec:ch2Exercis \textbf{(a)} For a given integer interval $\left[n_{1},n_{2}\right]$, find the largest integer $k\in\left[n_{1},n_{2}\right]$ such that the decimal representation of $k$ does \emph{not} contain any of -the digits $3$, $5$, or $7$. \textbf{(b)} For a given integer interval -$\left[n_{1},n_{2}\right]$, find the integer $k\in\left[n_{1},n_{2}\right]$ -with the largest sum of decimal digits. \textbf{(c)} A positive integer -$n$ is called a \textbf{perfect number}\index{perfect numbers} if -it is equal to the sum of its divisors (other integers $k$ such that -$k Option[(A,B)]): Stream[B] +def unfold2[A, B](init: A)(next: A => Option[(A, B)]): Stream[B] \end{lstlisting} The function should create a stream of values of type \lstinline!B! by repeatedly applying the given function \lstinline!next! until @@ -3369,7 +3370,7 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-11}\ref{subsec:ch2Exercise \subsubsection{Exercise \label{subsec:ch2Exercise-seq-10}\ref{subsec:ch2Exercise-seq-10}} -For a given sequence \lstinline!xs:Seq[Double]!, find a subsequence +For a given sequence \lstinline!xs: Seq[Double]!, find a subsequence that has the largest sum of values. The sequence \lstinline!xs! is not sorted, and its values may be positive or negative. The required type signature and a sample test: @@ -3380,7 +3381,8 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-10}\ref{subsec:ch2Exercise res0: Seq[Double] = List(2.0, 3.0, -0.5, 2.0, 1.0) \end{lstlisting} -Hint: use \index{dynamic programming}dynamic programming and \lstinline!foldLeft!. +Hint: use \index{dynamic programming}dynamic programming techniques +and \lstinline!foldLeft!. \subsubsection{Exercise \label{subsec:ch2Exercise-seq-12}\ref{subsec:ch2Exercise-seq-12}} @@ -3405,7 +3407,7 @@ \subsection{Total and partial functions} A simple example of a partial function in Scala is the \lstinline!max! method: it only works for non-empty sequences. Trying to evaluate -it on an empty sequence generates an error called an \textsf{``}exception\index{exception}\textsf{''}: +it on an empty sequence generates an error (an \textsf{``}exception\index{exception}\textsf{''}): \begin{lstlisting}[mathescape=false] scala> Seq(1).tail res0: Seq[Int] = List() @@ -3418,10 +3420,11 @@ \subsection{Total and partial functions} This kind of error may crash the entire program at run time. Unlike the type errors\index{type error} we saw before, which occur at compilation time (i.e., before the program can start), \textbf{run-time errors}\index{run-time error} -occur while the program is running, and only when some partial function -happens to get an incorrect input. The incorrect input may occur at -any point after the program started running, which may crash the entire -program in the middle of a long computation. +occur while the program is running and only when an invalid situation +actually happens \textemdash{} say, when some partial function gets +an incorrect input. The incorrect input may occur at any time after +the program started running, which may crash the entire program in +the middle of a long computation. So, it seems clear that we should write code that does not generate such errors. For instance, it is safe to apply \lstinline!max! to @@ -3436,7 +3439,7 @@ \subsection{Total and partial functions} this situation because it makes it much harder to reason about program correctness. In most cases, programs can be written to avoid the possibility of match errors. An example of an unsafe pattern matching expression -is +is: \begin{lstlisting}[mathescape=false] def h(p: (Int, Int)): Int = p match { case (x, 0) => x } @@ -3448,14 +3451,14 @@ \subsection{Total and partial functions} at .h(:12) ... 32 elided \end{lstlisting} -Here the pattern contains a pattern variable \lstinline!x! and a +Here, the pattern contains a pattern variable \lstinline!x! and a constant \lstinline!0!. This pattern only matches tuples whose second part is equal to \lstinline!0!. If the second argument is nonzero, a match error occurs and the program crashes. So, \lstinline!h! is a partial function. Pattern matching failures never happen if we match a tuple of correct -size with a pattern such as \lstinline!(x, y, z)!, because a pattern +size with a pattern such as \lstinline!(x, y, z)!, because each pattern variable will always match a value. So, pattern matching with a pattern such as \lstinline!(x, y, z)! is \textbf{infallible}\index{pattern matching!infallible} (never fails at run time) when applied to a tuple with $3$ elements. @@ -3464,8 +3467,8 @@ \subsection{Total and partial functions} including a pattern that matches everything: \begin{lstlisting} p match { - case (x, 0) => ... // This only matches some tuples. - case _ => ... // This matches everything. + case (x, 0) => ... // This only matches certain tuples. + case _ => ... // This matches everything else. } \end{lstlisting} If the first pattern \lstinline!(x, 0)! fails to match the value @@ -3478,9 +3481,9 @@ \subsection{Total and partial functions} \subsection{Scope and shadowing of pattern matching variables\label{subsec:Scope-and-shadowing-variables}} Pattern matching introduces \textbf{locally scoped\index{local scope}} -variables \textemdash{} that is, variables defined only on the right-hand -side of the pattern match expression. As an example, consider this -code: +variables \textemdash{} that is, variables accessible only within +the right-hand side of the pattern match expression. As an example, +consider this code: \begin{lstlisting} def f(x: (Int, Int)): Int = x match { case (x, y) => x + y } @@ -3493,8 +3496,8 @@ \subsection{Scope and shadowing of pattern matching variables\label{subsec:Scope matches the first part of the tuple and has type \lstinline!Int!. Because variables are locally scoped, the pattern variable \lstinline!x! is only defined within the expression \lstinline!x + y!. The argument -\lstinline!x:(Int,Int)! is a completely different variable whose -value has a different type. +\lstinline!x:(Int,Int)! is a completely different variable that has +a different type. The code works correctly but is confusing to read because of the name clash between the two quite different variables, both named \lstinline!x!. @@ -3559,8 +3562,8 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v Once computed, a lazy value stays in memory and will not be re-computed. An \textsf{``}on-call\textsf{''} value\index{on-call value} is re-computed every -time it is used. In Scala, a \lstinline!def! declaration does that -(as well as call-by-name arguments). +time it is used. In Scala, on-call values are denoted via \lstinline!def! +declarations as well as via call-by-name function arguments. Most collection types in Scala (such as \lstinline!List!, \lstinline!Array!, \lstinline!Set!, and \lstinline!Map!) are \textbf{eager}\index{eager collection}. @@ -3675,8 +3678,7 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v and obtain the correct result. We could also set $y=f(x)$ and compute $y+y=20$, with the same result. This property is called \index{referential transparency}\textbf{referential transparency} or \index{pure function}\textbf{functional purity} -of the function $f$. After applying a pure function, we can be sure -that, for instance, no hidden values in memory have been modified. +of the function $f$. When we set $x=100$ and compute $f(x)+f(x)$, the number $100$ does not \textsf{``}become empty\textsf{''} after the first use; its value remains the diff --git a/sofp-src/sofp-monads.lyx b/sofp-src/sofp-monads.lyx index 1791a9fa9..f0f662dc3 100644 --- a/sofp-src/sofp-monads.lyx +++ b/sofp-src/sofp-monads.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -11979,22 +11979,18 @@ Writer \end_inset - monad represents a function of type + monad's effect adds extra functionality to a computation of type \begin_inset Formula $A\rightarrow B$ \end_inset - that returns its result (of type -\begin_inset Formula $B$ -\end_inset - -) and additionally outputs some information (say, logging data) about the - computation just performed. +: it will additionally output some information (say, logging data) that + is somehow connected with the computation. Let \begin_inset Formula $W$ \end_inset be the type of the logging data. - To model this situation, we then need a function + To model this situation, we need a function \begin_inset Formula $f:A\rightarrow B$ \end_inset @@ -12031,11 +12027,11 @@ Writer \end_inset -Since this type has be of the form +To rewrite this type as \begin_inset Formula $A\rightarrow L^{B}$ \end_inset -, we must define the functor +, we must define \begin_inset Formula $L$ \end_inset @@ -12076,15 +12072,7 @@ Writer \end_inset - monad, the logging information should be -\begin_inset Quotes eld -\end_inset - -accumulated -\begin_inset Quotes erd -\end_inset - - in some way. + monad, the logging information should be accumulated in some way. In the logging example, additional lines are simply appended to the log file. It means that we must be able somehow to combine several values of type @@ -12181,7 +12169,7 @@ final case class Writer[A, W: Semigroup](a: A, log: W) { In the code notation: \begin_inset Formula \[ -\text{flm}_{\text{Write}}(f^{:A\rightarrow B\times W})\triangleq a\times w\rightarrow\left(f(a)\triangleright\pi_{1}\right)\times\left(w\oplus f(a)\triangleright\pi_{2}\right)\quad. +\text{flm}_{\text{Writer}}(f^{:A\rightarrow B\times W})\triangleq a\times w\rightarrow\left(f(a)\triangleright\pi_{1}\right)\times\left(w\oplus f(a)\triangleright\pi_{2}\right)\quad. \] \end_inset @@ -18457,7 +18445,7 @@ S^{A}\ar[ru]\sp(0.5){f^{\uparrow S}}\ar[rr]\sb(0.5){\text{flm}\,(f^{:A\rightarro \end_inset -In the code notation, we write this law in the point-free style +In the code notation, we write this law using the point-free style \begin_inset Index idx status open @@ -26037,21 +26025,6 @@ pure \end_inset : -\end_layout - -\begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "55col%" -status open - -\begin_layout Plain Layout -\begin_inset VSpace -60baselineskip% -\end_inset - - \begin_inset listings inline false status open @@ -26084,29 +26057,6 @@ def gamma[A]: L[A] => F[A] = { \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset VSpace -50baselineskip% -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\begin_inset space ~ -\end_inset - - -\begin_inset VSpace -40baselineskip% -\end_inset - - \begin_inset Formula \[ \gamma^{A}\triangleq\,\begin{array}{|c||c|} @@ -26150,7 +26100,7 @@ flatten \end_inset - method + method: \begin_inset listings inline false status open @@ -26385,12 +26335,12 @@ But this is the right identity law of the monad \begin_inset Formula $F$ \end_inset -, which (by assumption) is a lawful monad. +, which holds by assumption. \end_layout \begin_layout Standard -The next step is to verify the associativity law for +Next, we verify the associativity law for \begin_inset Formula $L$ \end_inset @@ -26435,7 +26385,7 @@ F^{L^{L^{A}}} & \bbnum 0 & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F} \begin_inset Note Note -status open +status collapsed \begin_layout Plain Layout \begin_inset Formula @@ -26494,14 +26444,7 @@ F^{L^{L^{A}}} & \bbnum 0 & \bbnum 0 & \text{ftn}_{L}^{\uparrow F} \hline A & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & \text{id}\\ F^{L^{A}} & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F} -\end{array}\\ - & \quad=\,\begin{array}{|c||cc|} - & A & F^{A}\\ -\hline A & \text{id} & \bbnum 0\\ -F^{A} & \bbnum 0 & \text{id}\\ -F^{L^{A}} & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F}\\ -F^{L^{L^{A}}} & \bbnum 0 & \text{ftn}_{L}^{\uparrow F}\bef\gamma^{\uparrow F}\bef\text{ftn}_{F} -\end{array}\quad, +\end{array} \end{align*} \end_inset @@ -26509,6 +26452,13 @@ F^{L^{L^{A}}} & \bbnum 0 & \text{ftn}_{L}^{\uparrow F}\bef\gamma^{\uparrow F}\be \begin_inset Formula \begin{align*} + & \quad=\,\begin{array}{|c||cc|} + & A & F^{A}\\ +\hline A & \text{id} & \bbnum 0\\ +F^{A} & \bbnum 0 & \text{id}\\ +F^{L^{A}} & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F}\\ +F^{L^{L^{A}}} & \bbnum 0 & \text{ftn}_{L}^{\uparrow F}\bef\gamma^{\uparrow F}\bef\text{ftn}_{F} +\end{array}\quad,\\ & \text{ftn}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} & A & F^{A} & F^{L^{A}}\\ \hline A & \text{id} & \bbnum 0 & \bbnum 0\\ @@ -28426,7 +28376,7 @@ Some examples of monads obtained with these constructions for \begin_inset Formula $G^{A}\triangleq\bbnum 1+A$ \end_inset - are: +: \begin_inset Formula \begin{align*} \text{selector monad}:\quad & \text{Sel}^{Z,A}\triangleq\left(A\rightarrow Z\right)\rightarrow A\quad,\\ @@ -28587,7 +28537,7 @@ Proof \end_layout \begin_layout Standard -Begin by implementing the monad methods for +Implement the monad methods for \begin_inset Formula $L$ \end_inset @@ -28694,7 +28644,7 @@ To verify the monad laws for \end_inset . - The lifting code is + The lifting code is: \begin_inset Formula \[ (f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} @@ -28723,10 +28673,6 @@ In order to compute function compositions such as \end_inset , so that their output types are fully split: -\begin_inset Note Note -status open - -\begin_layout Plain Layout \begin_inset Formula \begin{align*} & \text{pu}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} @@ -28754,11 +28700,10 @@ F^{L^{L^{L^{A}}}} & \bbnum 0 & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparro \end_inset -\end_layout - -\end_inset - +\begin_inset Note Note +status open +\begin_layout Plain Layout \begin_inset Formula \[ \text{pu}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} @@ -28792,6 +28737,11 @@ F^{L^{L^{L^{A}}}} & \bbnum 0 & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparro \end_inset + +\end_layout + +\end_inset + We can now verify the identity and associativity laws of \begin_inset Formula $\text{pu}_{L}$ \end_inset @@ -28802,6 +28752,10 @@ We can now verify the identity and associativity laws of . Identity laws: +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout \begin_inset Formula \begin{align*} & \text{pu}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} @@ -28842,10 +28796,11 @@ F^{L^{A}} & \bbnum 0 & \text{id} \end_inset -\begin_inset Note Note -status open +\end_layout + +\end_inset + -\begin_layout Plain Layout \begin_inset Formula \[ \text{pu}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} @@ -28899,11 +28854,6 @@ F^{L^{A}} & \bbnum 0 & \text{id} \end_inset - -\end_layout - -\end_inset - In the last line, we used the inductive assumption: \begin_inset Formula $\big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F}\bef\overline{\text{ftn}}_{L}^{\uparrow F}=\text{id}$ \end_inset @@ -29058,7 +29008,7 @@ For any functor \begin_inset Formula $L^{A}\triangleq F^{A}+F^{L^{A}}$ \end_inset - (representing a tree with + (a tree with \begin_inset Formula $F$ \end_inset @@ -29249,6 +29199,64 @@ F^{L^{L^{L^{A}}}} & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^ \end_inset + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +\begin_inset Formula +\begin{align*} + & \text{ftn}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||cc|} + & F^{L^{A}} & F^{L^{L^{A}}}\\ +\hline F^{L^{L^{A}}} & \bbnum 0 & \text{id}\\ +F^{L^{L^{L^{A}}}} & \bbnum 0 & \overline{\text{ftn}_{L}}^{\uparrow F} +\end{array}\,\bef\,\begin{array}{|c||cc|} + & F^{A} & F^{L^{A}}\\ +\hline F^{L^{A}} & \bbnum 0 & \text{id}\\ +F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}_{L}}^{\uparrow F} +\end{array}\\ + & \quad=\,\begin{array}{|c||cc|} + & F^{A} & F^{L^{A}}\\ +\hline F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}}^{\uparrow F}\\ +F^{L^{L^{L^{A}}}} & \bbnum 0 & \overline{\text{ftn}_{L}}^{\uparrow F}\bef\overline{\text{ftn}_{L}}^{\uparrow F} +\end{array}\quad, +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} + & \text{ftn}_{L}^{\uparrow L}\bef\text{ftn}_{L}=\,\begin{array}{|c||cc|} + & F^{L^{A}} & F^{L^{L^{A}}}\\ +\hline F^{L^{L^{A}}} & \overline{\text{ftn}_{L}}^{\uparrow F} & \bbnum 0\\ +F^{L^{L^{L^{A}}}} & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} +\end{array}\,\bef\,\begin{array}{|c||cc|} + & F^{A} & F^{L^{A}}\\ +\hline F^{L^{A}} & \bbnum 0 & \text{id}\\ +F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}_{L}}^{\uparrow F} +\end{array} +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} + & \quad=\,\begin{array}{|c||cc|} + & F^{A} & F^{L^{A}}\\ +\hline F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}_{L}}^{\uparrow F}\\ +F^{L^{L^{L^{A}}}} & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F}\bef\overline{\text{ftn}_{L}}^{\uparrow F} +\end{array}\quad. +\end{align*} + +\end_inset + + +\end_layout + +\end_inset + The two resulting matrices are equal due to the inductive assumption: \begin_inset Formula $\overline{\text{ftn}}_{L}^{\uparrow F}\bef\overline{\text{ftn}}_{L}^{\uparrow F}=\big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F}\bef\overline{\text{ftn}}_{L}^{\uparrow F}$ \end_inset @@ -35073,7 +35081,14 @@ A & \bbnum 0 & \text{id} \hline Z & \_\rightarrow1 & \bbnum 0\\ Z & \_\rightarrow1 & \bbnum 0\\ A & \bbnum 0 & \text{id} -\end{array}\quad,\\ +\end{array}\quad, +\end{align*} + +\end_inset + + +\begin_inset Formula +\begin{align*} & \quad\text{right-hand side}:\quad\\ & \phi^{\uparrow\text{Either}}\bef\phi\bef\text{ftn}_{\text{Opt}}\\ & \quad=\,\begin{array}{|c||ccc|} @@ -35114,7 +35129,7 @@ A & \bbnum 0 & \text{id} \begin_inset Note Note -status open +status collapsed \begin_layout Plain Layout \begin_inset Formula @@ -35184,7 +35199,7 @@ A & \bbnum 0 & \text{id} \begin_inset Note Note -status open +status collapsed \begin_layout Plain Layout \begin_inset Formula @@ -35422,8 +35437,12 @@ status open \begin_layout Plain Layout -def toCont[W: Monoid, A]: ((A, W)) => (A => W) => W = { case (a, w) => k - => k(a) |+| w } +def toCont[W: Monoid, A]: ((A, W)) => (A => W) => W = +\end_layout + +\begin_layout Plain Layout + + { case (a, w) => k => k(a) |+| w } \end_layout \end_inset @@ -35557,8 +35576,12 @@ status open \begin_layout Plain Layout -def flatten[W, A]: ((((A => W) => W) => W) => W) => (A => W) => W = { g - => k => g(c => c(k)) } +def flatten[W, A]: ((((A => W) => W) => W) => W) => (A => W) => W = +\end_layout + +\begin_layout Plain Layout + + { g => k => g(c => c(k)) } \end_layout \end_inset diff --git a/sofp-src/sofp-monads.tex b/sofp-src/sofp-monads.tex index aad2f8344..802a00be3 100644 --- a/sofp-src/sofp-monads.tex +++ b/sofp-src/sofp-monads.tex @@ -1707,27 +1707,27 @@ \subsection{The \texttt{Reader} monad\label{subsec:The-Reader-monad}} \subsection{The \texttt{Writer} monad} \index{monads!Writer monad@\texttt{Writer} monad}The \lstinline!Writer! -monad represents a function of type $A\rightarrow B$ that returns -its result (of type $B$) and additionally outputs some information -(say, logging data) about the computation just performed. Let $W$ -be the type of the logging data. To model this situation, we then -need a function $f:A\rightarrow B$ and additionally a function $g:A\rightarrow W$ -that computes the logging output. So, we can define the type of a -\textsf{``}computation with the \lstinline!Writer! effect\textsf{''} via the product -of the two function types: +monad\textsf{'}s effect adds extra functionality to a computation of type $A\rightarrow B$: +it will additionally output some information (say, logging data) that +is somehow connected with the computation. Let $W$ be the type of +the logging data. To model this situation, we need a function $f:A\rightarrow B$ +and additionally a function $g:A\rightarrow W$ that computes the +logging output. So, we can define the type of a \textsf{``}computation with +the \lstinline!Writer! effect\textsf{''} via the product of the two function +types: \[ \left(A\rightarrow B\right)\times\left(A\rightarrow W\right)\cong A\rightarrow B\times W\quad. \] -Since this type has be of the form $A\rightarrow L^{B}$, we must -define the functor $L$ as $L^{A}\triangleq A\times W$. This is the -type constructor of the \lstinline!Writer! monad, denoted by $\text{Writer}^{A,W}\triangleq A\times W$. +To rewrite this type as $A\rightarrow L^{B}$, we must define $L$ +as $L^{A}\triangleq A\times W$. This is the type constructor of the +\lstinline!Writer! monad, denoted by $\text{Writer}^{A,W}\triangleq A\times W$. If several computations are performed one after another in the \lstinline!Writer! -monad, the logging information should be \textsf{``}accumulated\textsf{''} in some -way. In the logging example, additional lines are simply appended -to the log file. It means that we must be able somehow to combine -several values of type $W$ into one. A general way of doing that -is to require $W$ to be a semigroup (see Example~\ref{subsec:tc-Example-Semigroups}) +monad, the logging information should be accumulated in some way. +In the logging example, additional lines are simply appended to the +log file. It means that we must be able somehow to combine several +values of type $W$ into one. A general way of doing that is to require +$W$ to be a semigroup (see Example~\ref{subsec:tc-Example-Semigroups}) with a binary operation $\oplus$. We can then implement the \lstinline!flatMap! method for \lstinline!Writer! like this: \begin{lstlisting} @@ -1740,7 +1740,7 @@ \subsection{The \texttt{Writer} monad} \end{lstlisting} In the code notation: \[ -\text{flm}_{\text{Write}}(f^{:A\rightarrow B\times W})\triangleq a\times w\rightarrow\left(f(a)\triangleright\pi_{1}\right)\times\left(w\oplus f(a)\triangleright\pi_{2}\right)\quad. +\text{flm}_{\text{Writer}}(f^{:A\rightarrow B\times W})\triangleq a\times w\rightarrow\left(f(a)\triangleright\pi_{1}\right)\times\left(w\oplus f(a)\triangleright\pi_{2}\right)\quad. \] The logging type $W$ is often a monoid (a semigroup with an \textsf{``}empty\textsf{''} @@ -4240,7 +4240,7 @@ \subsection{Motivating the semi-monad laws} S^{A}\ar[ru]\sp(0.5){f^{\uparrow S}}\ar[rr]\sb(0.5){\text{flm}\,(f^{:A\rightarrow B}\bef\,g^{:B\rightarrow S^{C}})\,} & & S^{C} } \] -In the code notation, we write this law in the point-free style\index{point-free style} +In the code notation, we write this law using the point-free style\index{point-free style} by omitting the argument \lstinline!c!: \begin{equation} @@ -5741,9 +5741,6 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-monad} method to create a value of type $F^{A}$ out of $A$. This allows us to convert $A+F^{A}$ into $F^{A}$ using the function we will denote $\gamma$: - -\begin{wrapfigure}{l}{0.55\columnwidth}% -\vspace{-0.6\baselineskip} \begin{lstlisting} type L[A] = Either[A, F[A]] def gamma[A]: L[A] => F[A] = { @@ -5751,11 +5748,6 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-monad} case Right(fa) => fa } \end{lstlisting} - -\vspace{-0.5\baselineskip} -\end{wrapfigure}% - -~\vspace{-0.4\baselineskip} \[ \gamma^{A}\triangleq\,\begin{array}{|c||c|} & F^{A}\\ @@ -5765,7 +5757,7 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-monad} \] Lifting this function to $F$, we can convert $F^{A+F^{A}}$ into $F^{F^{A}}$ and finally into $F^{A}$ via $F$\textsf{'}s \lstinline!flatten! -method +method: \begin{lstlisting} def flatten_L[A]: L[L[A]] => L[A] = { case Left(Left(a)) => Left(a) @@ -5864,11 +5856,11 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-monad} \[ \text{id}\overset{?}{=}(\text{pu}_{L}\bef\gamma)^{\uparrow F}\bef\text{ftn}_{F}=\text{pu}_{F}^{\uparrow F}\bef\text{ftn}_{F}\quad. \] -But this is the right identity law of the monad $F$, which (by assumption) -is a lawful monad. +But this is the right identity law of the monad $F$, which holds +by assumption. -The next step is to verify the associativity law for $L$. Write the -code for $\text{ftn}_{L}^{\uparrow L}$ and $\text{ftn}_{L}^{L^{A}}$: +Next, we verify the associativity law for $L$. Write the code for +$\text{ftn}_{L}^{\uparrow L}$ and $\text{ftn}_{L}^{L^{A}}$: \begin{align*} & \text{ftn}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} & L^{A} & F^{L^{A}}\\ @@ -5908,16 +5900,16 @@ \subsubsection{Statement \label{subsec:Statement-co-product-with-identity-monad} \hline A & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & \text{id}\\ F^{L^{A}} & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F} -\end{array}\\ +\end{array} +\end{align*} +\begin{align*} & \quad=\,\begin{array}{|c||cc|} & A & F^{A}\\ \hline A & \text{id} & \bbnum 0\\ F^{A} & \bbnum 0 & \text{id}\\ F^{L^{A}} & \bbnum 0 & \gamma^{\uparrow F}\bef\text{ftn}_{F}\\ F^{L^{L^{A}}} & \bbnum 0 & \text{ftn}_{L}^{\uparrow F}\bef\gamma^{\uparrow F}\bef\text{ftn}_{F} -\end{array}\quad, -\end{align*} -\begin{align*} +\end{array}\quad,\\ & \text{ftn}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} & A & F^{A} & F^{L^{A}}\\ \hline A & \text{id} & \bbnum 0 & \bbnum 0\\ @@ -6320,8 +6312,7 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-3}\ref{subse Both sides of the associativity law are now converted into identical expressions. $\square$ -Some examples of monads obtained with these constructions for $G^{A}\triangleq\bbnum 1+A$ -are: +Some examples of monads obtained with these constructions for $G^{A}\triangleq\bbnum 1+A$: \begin{align*} {\color{greenunder}\text{selector monad}:}\quad & \text{Sel}^{Z,A}\triangleq\left(A\rightarrow Z\right)\rightarrow A\quad,\\ {\color{greenunder}\text{search monad}:}\quad & \text{Search}^{Z,A}\triangleq\left(A\rightarrow\bbnum 1+Z\right)\rightarrow\bbnum 1+A\quad,\\ @@ -6347,8 +6338,7 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad \subparagraph{Proof} -Begin by implementing the monad methods for $L$ as usual for a tree-like -monad: +Implement the monad methods for $L$ as usual for a tree-like monad: \begin{lstlisting} type L[A] = Either[A, F[L[A]]] // The functor F must be already defined. def pure_L[A](a: A): L[A] = Left(a) @@ -6375,7 +6365,7 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad \] To verify the monad laws for $L$, we need to lift $\text{pu}_{L}$ -and $\text{ftn}_{L}$ to the functor $L$. The lifting code is +and $\text{ftn}_{L}$ to the functor $L$. The lifting code is: \[ (f^{:A\rightarrow B})^{\uparrow L}=\,\begin{array}{|c||cc|} & B & F^{L^{B}}\\ @@ -6387,8 +6377,8 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad and $\text{ftn}_{L}^{\uparrow L}\bef\text{ftn}$ in the matrix notation, we need to expand the matrices of $\text{pu}_{L}$ and $\text{ftn}_{L}$, so that their output types are fully split: -\[ -\text{pu}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} +\begin{align*} + & \text{pu}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} & L^{A} & F^{L^{L^{A}}}\\ \hline A & \text{pu}_{L} & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} @@ -6396,10 +6386,8 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad & A & F^{L^{A}} & F^{L^{L^{A}}}\\ \hline A & \text{id} & \bbnum 0 & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \bbnum 0 & \big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} -\end{array}\quad, -\] -\[ -\text{ftn}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} +\end{array}\quad,\\ + & \text{ftn}_{L}^{\uparrow L}=\,\begin{array}{|c||cc|} & L^{A} & F^{L^{L^{A}}}\\ \hline L^{L^{A}} & \text{ftn}_{L} & \bbnum 0\\ F^{L^{L^{L^{A}}}} & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} @@ -6410,11 +6398,11 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}}_{L}^{\uparrow F} & \bbnum 0\\ F^{L^{L^{L^{A}}}} & \bbnum 0 & \bbnum 0 & \big(\text{ftn}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} \end{array}\quad. -\] +\end{align*} We can now verify the identity and associativity laws of $\text{pu}_{L}$ and $\text{ftn}_{L}$. Identity laws: -\begin{align*} - & \text{pu}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} +\[ +\text{pu}_{L}^{L^{A}}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} & A & F^{L^{A}} & F^{L^{L^{A}}}\\ \hline A & \text{id} & \bbnum 0 & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \text{id} & \bbnum 0 @@ -6427,8 +6415,10 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad & A & F^{L^{A}}\\ \hline A & \text{id} & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \text{id} -\end{array}\,=\text{id}\quad,\\ - & \text{pu}_{L}^{\uparrow L}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} +\end{array}\,=\text{id}\quad, +\] +\[ +\text{pu}_{L}^{\uparrow L}\bef\text{ftn}_{L}=\,\begin{array}{|c||ccc|} & A & F^{L^{A}} & F^{L^{L^{A}}}\\ \hline A & \text{id} & \bbnum 0 & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \bbnum 0 & \big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F} @@ -6437,8 +6427,10 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad \hline A & \text{id} & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \text{id}\\ F^{L^{L^{A}}} & \bbnum 0 & \overline{\text{ftn}}_{L}^{\uparrow F} -\end{array}\\ - & \quad=\,\begin{array}{|c||cc|} +\end{array} +\] +\[ +\quad=\,\begin{array}{|c||cc|} & A & F^{L^{A}}\\ \hline A & \text{id} & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \gunderline{\big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F}\bef\overline{\text{ftn}}_{L}^{\uparrow F}} @@ -6446,8 +6438,8 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad & A & F^{L^{A}}\\ \hline A & \text{id} & \bbnum 0\\ F^{L^{A}} & \bbnum 0 & \text{id} -\end{array}\,=\text{id}\quad. -\end{align*} +\end{array}\,=\text{id}\quad, +\] In the last line, we used the inductive assumption: $\big(\text{pu}_{L}^{\overline{\uparrow L}}\big)^{\uparrow F}\bef\overline{\text{ftn}}_{L}^{\uparrow F}=\text{id}$. To verify the associativity law, simplify its both sides separately @@ -6501,8 +6493,8 @@ \subsubsection{Statement \label{subsec:Statement-monad-construction-4-free-monad \subsubsection{Statement \label{subsec:Statement-monad-construction-5}\ref{subsec:Statement-monad-construction-5}} For any functor $F$, the recursive functor $L^{A}\triangleq F^{A}+F^{L^{A}}$ -(representing a tree with $F$-shaped leaves and branches) is a semi-monad -but not a monad. +(a tree with $F$-shaped leaves and branches) is a semi-monad but +not a monad. \subparagraph{Proof} @@ -7478,7 +7470,9 @@ \subsubsection{Example \label{subsec:Example-monad-morphism-either-option}\ref{s \hline Z & \_\rightarrow1 & \bbnum 0\\ Z & \_\rightarrow1 & \bbnum 0\\ A & \bbnum 0 & \text{id} -\end{array}\quad,\\ +\end{array}\quad, +\end{align*} +\begin{align*} & \quad{\color{greenunder}\text{right-hand side}:}\quad\\ & \phi^{\uparrow\text{Either}}\bef\phi\bef\text{ftn}_{\text{Opt}}\\ & \quad=\,\begin{array}{|c||ccc|} @@ -7533,7 +7527,8 @@ \subsubsection{Example \label{subsec:monad-morphism-writer-state}\ref{subsec:mon Show that \lstinline!toCont! is a monad morphism between the \lstinline!Writer! and the \lstinline!Cont! monads: \begin{lstlisting} -def toCont[W: Monoid, A]: ((A, W)) => (A => W) => W = { case (a, w) => k => k(a) |+| w } +def toCont[W: Monoid, A]: ((A, W)) => (A => W) => W = + { case (a, w) => k => k(a) |+| w } \end{lstlisting} \[ \phi:A\times W\rightarrow\left(A\rightarrow W\right)\rightarrow W\quad,\quad\quad\phi\triangleq a^{:A}\times w^{:W}\rightarrow k^{:A\rightarrow W}\rightarrow k\left(a\right)\oplus w\quad, @@ -7555,7 +7550,8 @@ \subsubsection{Example \label{subsec:monad-morphism-writer-state}\ref{subsec:mon To verify the composition law, we need an implementation of \lstinline!flatten! for the \lstinline!Cont! monad: \begin{lstlisting} -def flatten[W, A]: ((((A => W) => W) => W) => W) => (A => W) => W = { g => k => g(c => c(k)) } +def flatten[W, A]: ((((A => W) => W) => W) => W) => (A => W) => W = + { g => k => g(c => c(k)) } \end{lstlisting} \[ \text{ftn}_{\text{Cont}}=g^{:\left(\left(\left(A\rightarrow W\right)\rightarrow W\right)\rightarrow W\right)\rightarrow W}\rightarrow k^{:A\rightarrow W}\rightarrow g\,(c^{:\left(A\rightarrow W\right)\rightarrow W}\rightarrow c\left(k\right))\quad. diff --git a/sofp-src/sofp-nameless-functions.lyx b/sofp-src/sofp-nameless-functions.lyx index 8352224c3..8f76aa77a 100644 --- a/sofp-src/sofp-nameless-functions.lyx +++ b/sofp-src/sofp-nameless-functions.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -331,7 +331,7 @@ noprefix "false" \end_inset -: Factorial of 10 + \end_layout \begin_layout Standard @@ -490,8 +490,8 @@ status open \begin_layout Plain Layout -scala> 100 + (1 to 10).product + 100 // This code contains `(1 to 10).product` - as a sub-expression. +scala> 100 + (1 to 10).product + 100 // The code `(1 to 10).product` is + a sub-expression. \end_layout \begin_layout Plain Layout @@ -606,7 +606,7 @@ noprefix "false" \end_inset -: Factorial as a function + \end_layout \begin_layout Standard @@ -658,8 +658,8 @@ def \family default - syntax, we need to specify the type of a function's argument; in this case, - we write + syntax, we need to specify the type of a function's argument; here, we + wrote \begin_inset listings inline true status open @@ -735,7 +735,7 @@ domain of a function \end_inset - (the set of admissible values of an argument). + (the set of admissible values of a a function's argument). \end_layout \begin_layout Standard @@ -938,7 +938,7 @@ maps to status open \begin_layout Plain Layout -In mathematics, the standard symbol for +In mathematics, an often used symbol for \begin_inset Quotes eld \end_inset @@ -967,7 +967,7 @@ x\rightarrow\left(\text{some formula}\right)\quad. \end_inset -So, the mathematical notation for the nameless factorial function is: +So, a mathematical notation for the nameless factorial function is: \begin_inset Formula \[ n\rightarrow\prod_{k=1}^{n}k\quad. @@ -1374,11 +1374,7 @@ res1: Int = 3628800 \end_inset - -\end_layout - -\begin_layout Standard -However, functions can be used without naming them. +Functions can be also used without naming them. We may directly apply a nameless factorial function to an integer argument \begin_inset listings @@ -1648,7 +1644,7 @@ noprefix "false" \end_inset -: prime numbers + \end_layout \begin_layout Standard @@ -1685,8 +1681,7 @@ forall \end_inset -This formula has two clearly separated parts: first, a range of integers - from +This formula has two parts: first, a range of integers from \begin_inset Formula $2$ \end_inset @@ -1971,7 +1966,7 @@ predicate \begin_layout Standard In Scala, it is strongly recommended (although often not mandatory) to specify - the return type of named functions. + the return types of named functions. The required syntax looks like this: \begin_inset listings inline false @@ -2284,7 +2279,7 @@ status open \family default - we have seen before. + shown before. \end_layout \begin_layout Standard @@ -2425,7 +2420,7 @@ Let us investigate the role of \begin_inset Formula $k$ \end_inset - is actually defined + is accessible \emph on only inside \emph default @@ -2434,7 +2429,7 @@ only inside \end_inset -\begin_inset Formula $\forall k:...$ +\begin_inset Formula $\forall k.\,...$ \end_inset @@ -2470,8 +2465,8 @@ reference "eq:is_prime_def" \begin_inset Quotes erd \end_inset - is defined only in the right-hand side, where it is first mentioned as - the arbitrary element + is accessible only in the right-hand side, where it is first mentioned + as the arbitrary element \begin_inset Formula $k\in\left[2,n-1\right]$ \end_inset @@ -2526,7 +2521,7 @@ noprefix "false" \begin_inset Formula $(n\%k)\neq0$ \end_inset -, which can be viewed as a certain given +, which can be viewed as a certain \emph on function \emph default @@ -2551,8 +2546,8 @@ Boolean \end_inset value. - Translating the mathematical notation into code, it is therefore natural - to use the nameless function + Translating the mathematical notation into code, it is natural to use the + nameless function \begin_inset Formula $k\rightarrow(n\%k)\neq0$ \end_inset @@ -2628,7 +2623,7 @@ k => n % k != 0 \end_inset - is defined only within that function's body and cannot be used in any code + is defined within that function's body and cannot be used in any code outside the expression \begin_inset listings inline true @@ -2696,18 +2691,23 @@ variables occurring free in an expression These concepts apply equally well to mathematical formulas and to Scala code. For example, in the mathematical expression -\begin_inset Formula $k\rightarrow(n\%k)\neq0$ +\begin_inset Formula $\forall k.\,(n\%k)\neq0$ \end_inset - (which is a nameless function), the variable +, the variable \begin_inset Formula $k$ \end_inset - is bound (it is defined only within that expression) but the variable + is bound (defined and only visible within that expression's scope) but + the variable \begin_inset Formula $n$ \end_inset - is free (it is defined outside that expression). + is free: it must be defined somewhere outside the expression +\begin_inset Formula $\forall k.\,(n\%k)\neq0$ +\end_inset + +. \end_layout \begin_layout Standard @@ -2798,7 +2798,19 @@ n \end_inset - is a free variable (it is not defined inside the function). + is a free variable within +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +z => n % z != 0 +\end_layout + +\end_inset + + (it is not defined inside that function, so it must be defined outside). If we wanted to rename \begin_inset listings inline true @@ -2835,11 +2847,7 @@ n \end_inset - -\emph on -outside -\emph default - that sub-expression, or else the program would become incorrect. + outside that sub-expression, or else the program would become incorrect. \end_layout \begin_layout Standard @@ -2864,7 +2872,7 @@ Mathematical formulas use bound variables in constructions such as \end_inset , and -\begin_inset Formula $\text{argmax}_{k}f\left(k\right)$ +\begin_inset Formula $\text{argmax}_{k}f(k)$ \end_inset . @@ -2902,7 +2910,7 @@ k => f(k) \begin_layout Standard As an example, the mathematical formula -\begin_inset Formula $\forall k\in\left[1,n\right].\,p\left(k\right)$ +\begin_inset Formula $\forall k\in\left[1,n\right].\,p(k)$ \end_inset has a bound variable @@ -3003,19 +3011,7 @@ x \end_inset - or additional hidden arguments of the function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -f -\end_layout - -\end_inset - -. +, default argument values, or implicit arguments. In those cases, replacing the code \begin_inset listings inline true @@ -3041,7 +3037,7 @@ f \end_inset will fail to compile. - This problem does not appear when working with simple functions. + \end_layout \end_inset @@ -3054,8 +3050,11 @@ Aggregating data from sequences \end_layout \begin_layout Standard -Consider the task of counting how many even numbers there are in a given - list +Consider the task of counting the +\emph on +even +\emph default + numbers contained in a given list \begin_inset Formula $L$ \end_inset @@ -3173,7 +3172,15 @@ def isEven(k: Int): Int = (k % 2) match { \begin_layout Plain Layout - case _ => 0 // The underscore matches everything else. + case _ => 0 // The underscore means +\begin_inset Quotes eld +\end_inset + +otherwise +\begin_inset Quotes erd +\end_inset + +. \end_layout \begin_layout Plain Layout @@ -3209,7 +3216,7 @@ val isEven = (k: Int) => if (k % 2 == 0) 1 else 0 \begin_layout Standard Given this function, we now need to translate into Scala code the expression -\begin_inset Formula $\sum_{k\in L}\text{is\_even}\left(k\right)$ +\begin_inset Formula $\sum_{k\in L}\text{isEven}\left(k\right)$ \end_inset . @@ -3234,7 +3241,7 @@ List[Int] \begin_layout Standard To compute -\begin_inset Formula $\sum_{k\in L}\text{is\_even}\left(k\right)$ +\begin_inset Formula $\sum_{k\in L}\text{isEven}\left(k\right)$ \end_inset , we must apply the function @@ -3522,7 +3529,7 @@ status open \begin_layout Plain Layout -scala> def func1(x: Int): Int = x*x + 100*x +scala> def func1(x: Int): Int = x * x + 100 * x \end_layout \begin_layout Plain Layout @@ -4262,6 +4269,14 @@ true \end_inset + +\end_layout + +\begin_layout Standard +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout Operations such as \begin_inset Quotes eld \end_inset @@ -4274,7 +4289,8 @@ removing elements from a list mathematical notation. \end_layout -\begin_layout Standard +\end_inset + The \begin_inset listings inline true @@ -4826,7 +4842,7 @@ def isPrime(n: Int): Boolean = { \begin_layout Plain Layout - .takeWhile(k => k*k <= n) + .takeWhile(k => k * k <= n) \end_layout \begin_layout Plain Layout @@ -5226,8 +5242,8 @@ status open \begin_layout Plain Layout -def wallis_frac(i: Int): Double = ((2*i).toDouble/(2*i - 1))*((2*i).toDouble/(2*i - + 1)) +def wallis_frac(i: Int): Double = ((2 * i).toDouble / (2 * i - 1)) * ((2 + * i).toDouble / (2 * i + 1)) \end_layout \begin_layout Plain Layout @@ -5314,7 +5330,7 @@ noprefix "false" \end_layout \begin_layout Standard -Check numerically the infinite product formula: +Check numerically the following infinite product formula: \begin_inset Formula \[ \prod_{k=1}^{\infty}\left(1-\frac{x^{2}}{k^{2}}\right)=\frac{\sin\pi x}{\pi x}\quad. @@ -5353,8 +5369,8 @@ status open \begin_layout Plain Layout -def sine_product(n: Int, x: Double): Double = (1 to n).map(k => 1.0 - x*x/k/k).prod -uct +def sine_product(n: Int, x: Double): Double = (1 to n).map(k => 1.0 - x * + x / k / k).product \end_layout \begin_layout Plain Layout @@ -5879,19 +5895,7 @@ noprefix "false" summarizes the tools explained in this chapter and gives implementations of some mathematical constructions in Scala. - We have also shown the methods -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -size -\end_layout - -\end_inset - - and + We have also shown methods such as \begin_inset listings inline true status open @@ -5966,7 +5970,7 @@ status open \begin_layout Plain Layout -x => math.sqrt(x*x + 1) +x => math.sqrt(x * x + 1) \end_layout \end_inset @@ -6068,7 +6072,7 @@ status open \begin_layout Plain Layout -(1 to n).map(k => k*k).sum +(1 to n).map(k => k * k).sum \end_layout \end_inset @@ -6391,7 +6395,20 @@ noprefix "false" \end_inset - will explain how to implement these tasks using recursion. + will explain how to implement these tasks using recursion as well as using + library methods such as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +foldLeft +\end_layout + +\end_inset + +. \end_layout \begin_layout Standard @@ -6501,7 +6518,7 @@ takeWhile \end_inset 1 as a formula by using mathematical induction, but we have not yet seen - how to implement that in Scala code. + how to translate that into Scala code. \end_layout @@ -6758,7 +6775,7 @@ Implement a function that computes the series for \begin_inset Formula $12$ \end_inset - terms of the series are already sufficient for a full-precision + terms of the series are sufficient for a full-precision \begin_inset listings inline true status open @@ -6913,7 +6930,7 @@ Riemann's zeta function \end_inset -\begin_inset Formula $\zeta\left(4\right)$ +\begin_inset Formula $\zeta(4)$ \end_inset . @@ -6938,13 +6955,13 @@ literal "false" \end_inset that -\begin_inset Formula $\zeta\left(4\right)=\frac{\pi^{4}}{90}$ +\begin_inset Formula $\zeta(4)=\frac{\pi^{4}}{90}$ \end_inset : \begin_inset Formula \[ -\zeta\left(4\right)=\prod_{k\geq2;~k\text{ is prime}}\frac{1}{1-\frac{1}{k^{4}}}=\frac{\pi^{4}}{90}\quad. +\zeta(4)=\prod_{k\geq2;~k\text{ is prime}}\frac{1}{1-\frac{1}{k^{4}}}=\frac{\pi^{4}}{90}\quad. \] \end_inset @@ -7086,7 +7103,7 @@ An integer \end_inset such that -\begin_inset Formula $1 Boolean \end_inset if there are only three different integers -\begin_inset Formula $1 x * x).sum +\end_layout + +\begin_layout Plain Layout + + math.sqrt(x2sum / (n - 1) - xsum * xsum / n / (n - 1)) +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> sigma(Seq(10, 20, 30)) +\end_layout + +\begin_layout Plain Layout + +res0: Double = 10.0 +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The programmer can avoid writing loops because all iterative computations + are delegated to functions such as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +map +\end_layout + +\end_inset + +, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +filter +\end_layout + +\end_inset + +, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +sum +\end_layout + +\end_inset + +, and others. + It is the job of the library and the compiler to translate those high-level + functions into low-level machine code. + The machine code +\emph on +will +\emph default + likely contain loops, but the programmer does not need to see that machine + code or to reason about it. +\end_layout + +\begin_layout Subsection +The mathematical meaning of +\begin_inset Quotes eld +\end_inset + +variables +\begin_inset Quotes erd +\end_inset + + +\end_layout + +\begin_layout Standard +The usage of variables in functional programming is similar to how mathematical + literature uses variables. + In mathematics, +\series bold +variables +\series default + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +variable +\end_layout + +\end_inset + + are used first of all as +\emph on +arguments +\emph default + of functions; e.g., the formula: +\begin_inset Formula +\[ +f(x)=x^{2}+x +\] + +\end_inset + +contains the variable +\begin_inset Formula $x$ +\end_inset + + and defines a function +\begin_inset Formula $f$ +\end_inset + + that takes +\begin_inset Formula $x$ +\end_inset + + as its argument (to be definite, assume that +\begin_inset Formula $x$ +\end_inset + + is an integer) and computes the value +\begin_inset Formula $x^{2}+x$ +\end_inset + +. + The body of the function is the expression +\begin_inset Formula $x^{2}+x$ +\end_inset + +. + +\end_layout + +\begin_layout Standard +Mathematics has the convention that a variable, such as +\begin_inset Formula $x$ +\end_inset + +, does not change its value within a formula. + Indeed, there is no mathematical notation even to talk about +\begin_inset Quotes eld +\end_inset + +changing +\begin_inset Quotes erd +\end_inset + + the value of +\begin_inset Formula $x$ +\end_inset + + +\emph on +inside +\emph default + the formula +\begin_inset Formula $x^{2}+x$ +\end_inset + +. + It would be quite confusing if a mathematics textbook said +\begin_inset Quotes eld +\end_inset + +before adding the last +\begin_inset Formula $x$ +\end_inset + + in the formula +\begin_inset Formula $x^{2}+x$ +\end_inset + +, we change that +\begin_inset Formula $x$ +\end_inset + + by adding +\begin_inset Formula $4$ +\end_inset + + to it +\begin_inset Quotes erd +\end_inset + +. + If the +\begin_inset Quotes eld +\end_inset + +last +\begin_inset Formula $x$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + in +\begin_inset Formula $x^{2}+x$ +\end_inset + + needs to have a +\begin_inset Formula $4$ +\end_inset + + added to it, a mathematics textbook will just write the formula +\begin_inset Formula $x^{2}+x+4$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Arguments of nameless functions are also immutable. + Consider, for example: +\begin_inset Formula +\[ +f(n)=\sum_{k=0}^{n}\,(k^{2}+k)\quad. +\] + +\end_inset + +Here, +\begin_inset Formula $n$ +\end_inset + + is the argument of the function +\begin_inset Formula $f$ +\end_inset + +, while +\begin_inset Formula $k$ +\end_inset + + is the argument of the nameless function +\begin_inset Formula $k\rightarrow k^{2}+k$ +\end_inset + +. + Neither \begin_inset Formula $n$ \end_inset @@ -8000,7 +8254,11 @@ val x: Int = 123 \end_inset -or we could omit the type annotation +We could also omit the type annotation +\begin_inset Quotes eld +\end_inset + + \begin_inset listings inline true status open @@ -8010,6 +8268,10 @@ status open :Int \end_layout +\end_inset + + +\begin_inset Quotes erd \end_inset and write more concisely: @@ -8108,255 +8370,6 @@ scala> val x: Int = "123" \end_layout -\begin_layout Subsection -Iteration without loops -\end_layout - -\begin_layout Standard -A distinctive feature of the FP paradigm is handling of iteration -\emph on -without -\emph default - writing loops, just as iterative computations are written in mathematical - notation. -\end_layout - -\begin_layout Standard -As an example, consider the formula for the standard deviation ( -\begin_inset Formula $\sigma$ -\end_inset - -) estimated from a data sample -\begin_inset Formula $\left[x_{1},...,x_{n}\right]$ -\end_inset - -: -\begin_inset Formula -\[ -\sigma=\sqrt{\frac{1}{n-1}\sum_{i=1}^{n}x_{i}^{2}-\frac{1}{n\left(n-1\right)}\left(\sum_{i=1}^{n}x_{i}\right)^{2}}\quad. -\] - -\end_inset - -Here the index -\begin_inset Formula $i$ -\end_inset - - goes over the integer range -\begin_inset Formula $\left[1,...,n\right]$ -\end_inset - -. - And yet no mathematics textbook would define this formula via loops or - by saying -\begin_inset Quotes eld -\end_inset - -now repeat equation -\begin_inset Formula $X$ -\end_inset - - ten times -\begin_inset Quotes erd -\end_inset - -. - Indeed, it is unnecessary to evaluate a formula such as -\begin_inset Formula $x_{i}^{2}$ -\end_inset - - ten times: the value of -\begin_inset Formula $x_{i}^{2}$ -\end_inset - - remains the same every time. - It is just as unnecessary to -\begin_inset Quotes eld -\end_inset - -repeat -\begin_inset Quotes erd -\end_inset - - a mathematical equation. -\end_layout - -\begin_layout Standard -Instead of loops, mathematicians write -\emph on -expressions -\emph default - such as -\begin_inset Formula $\sum_{i=1}^{n}s_{i}$ -\end_inset - -, where symbols such as -\begin_inset Formula $\sum_{i=1}^{n}$ -\end_inset - - denote the results of entire iterative computations. - Such computations are defined using mathematical induction -\begin_inset Index idx -status open - -\begin_layout Plain Layout -mathematical induction -\end_layout - -\end_inset - -. - The FP paradigm has developed rich tools for translating mathematical induction - into code. - This chapter focuses on methods such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -map -\end_layout - -\end_inset - -, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -filter -\end_layout - -\end_inset - -, and -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -sum -\end_layout - -\end_inset - -. - The next chapter shows more general methods for implementing inductive - computations. - These methods can be combined in flexible ways, enabling programmers to - write iterative code without loops. - For example, the value -\begin_inset Formula $\sigma$ -\end_inset - - defined by the formula shown above is computed by code that looks like - this: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def sigma(xs: Seq[Double]): Double = { -\end_layout - -\begin_layout Plain Layout - - val n = xs.length.toDouble -\end_layout - -\begin_layout Plain Layout - - val xsum = xs.sum -\end_layout - -\begin_layout Plain Layout - - val x2sum = xs.map(x => x * x).sum -\end_layout - -\begin_layout Plain Layout - - math.sqrt(x2sum / (n - 1) - xsum * xsum / n / (n - 1)) -\end_layout - -\begin_layout Plain Layout - -} -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\begin_layout Plain Layout - -scala> sigma(Seq(10, 20, 30)) -\end_layout - -\begin_layout Plain Layout - -res0: Double = 10.0 -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -The programmer can avoid writing loops because all iterative computations - are delegated to functions such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -map -\end_layout - -\end_inset - -, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -filter -\end_layout - -\end_inset - -, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -sum -\end_layout - -\end_inset - -, and others. - It is the job of the library and the compiler to translate those high-level - functions into low-level machine code. - The machine code -\emph on -will -\emph default - likely contain loops, but the programmer does not need to see that machine - code or to reason about it. -\end_layout - \begin_layout Subsection Nameless functions in mathematical notation \begin_inset CommandInset label @@ -8374,7 +8387,7 @@ Functions in mathematics are mappings from one set to another. \emph on need \emph default - a name; the mapping just needs to be defined. + a name; we just need to define the mapping. However, nameless functions have not been widely used in the conventional mathematical notation. It turns out that nameless functions are important in functional programming @@ -8403,7 +8416,7 @@ The mathematical convention is that one may rename the integration variable \end_layout \begin_layout Standard -In programming, the only situation when a variable +In programming, one situation when a variable \begin_inset Quotes eld \end_inset @@ -8412,7 +8425,7 @@ may be renamed at will \end_inset is when the variable represents an argument of a function. - It follows that the notations + We can see that the notations \begin_inset Formula $\frac{dx}{1+x}$ \end_inset @@ -8562,8 +8575,7 @@ In the new notation, the summation symbol functions \emph default that take functions as arguments. - The above summation may be written in a consistent and straightforward - manner as a Scala function: + The above summation may be written as a Scala function: \begin_inset listings inline false status open @@ -8658,7 +8670,7 @@ literal "false" gives the following formulas for numerical integration: \begin_inset Formula \begin{align*} -\text{Simpson}\left(a,b,g,\varepsilon\right) & =\frac{\delta}{3}\big(g(a)+g(b)+4s_{1}+2s_{2}\big)\quad,\\ +\text{simpson}\left(a,b,g,\varepsilon\right) & =\frac{\delta}{3}\big(g(a)+g(b)+4s_{1}+2s_{2}\big)\quad,\\ \text{where }~~~n & =2\left\lfloor \frac{b-a}{\varepsilon}\right\rfloor \quad,\quad\quad\delta_{x}=\frac{b-a}{n}\quad,\\ s_{1}=\sum_{k=1,3,...,n-1}g(a+k\delta_{x}) & \quad,\quad\quad s_{2}=\sum_{k=2,4,...,n-2}g(a+k\delta_{x})\quad. \end{align*} @@ -10117,7 +10129,7 @@ status open \begin_layout Plain Layout -function(k:: Int) k + 1 end +function(k :: Int) k + 1 end \end_layout \end_inset diff --git a/sofp-src/sofp-nameless-functions.tex b/sofp-src/sofp-nameless-functions.tex index c04045036..13b5c2d39 100644 --- a/sofp-src/sofp-nameless-functions.tex +++ b/sofp-src/sofp-nameless-functions.tex @@ -7,8 +7,7 @@ \subsection{First examples} We begin by implementing some computational tasks in Scala. -\subsubsection{Example \label{subsec:Example-Factorial-of-10}\ref{subsec:Example-Factorial-of-10}: -Factorial of 10} +\subsubsection{Example \label{subsec:Example-Factorial-of-10}\ref{subsec:Example-Factorial-of-10}} Find the product of integers from $1$ to $10$ (the \textbf{factorial\index{factorial function}} of 10, usually denoted by $10!$). @@ -34,7 +33,7 @@ \subsubsection{Example \label{subsec:Example-Factorial-of-10}\ref{subsec:Example and (2) the code can be used inside a larger expression. For example, we could write: \begin{lstlisting} -scala> 100 + (1 to 10).product + 100 // This code contains `(1 to 10).product` as a sub-expression. +scala> 100 + (1 to 10).product + 100 // The code `(1 to 10).product` is a sub-expression. res0: Int = 3629000 scala> 3628800 == (1 to 10).product @@ -49,8 +48,7 @@ \subsubsection{Example \label{subsec:Example-Factorial-of-10}\ref{subsec:Example \end{lstlisting} -\subsubsection{Example \label{subsec:Example-Factorial-as-a-function}\ref{subsec:Example-Factorial-as-a-function}: -Factorial as a function} +\subsubsection{Example \label{subsec:Example-Factorial-as-a-function}\ref{subsec:Example-Factorial-as-a-function}} Define a function to compute the factorial of an integer $n$. @@ -64,7 +62,7 @@ \subsubsection{Example \label{subsec:Example-Factorial-as-a-function}\ref{subsec \end{lstlisting} In Scala\textsf{'}s \texttt{}\lstinline!def! syntax, we need to specify the -type of a function\textsf{'}s argument; in this case, we write \lstinline!n: Int!. +type of a function\textsf{'}s argument; here, we wrote \lstinline!n: Int!. In the usual mathematical notation, types of function arguments are either not written at all, or written separately from the formula: \begin{equation} @@ -75,7 +73,7 @@ \subsubsection{Example \label{subsec:Example-Factorial-as-a-function}\ref{subsec mathematics. This is similar to specifying the type \texttt{(}\lstinline!n: Int!\texttt{)} in the Scala code. So, the argument\textsf{'}s type in the code specifies the \textbf{domain} of a function\index{domain of a function} (the set -of admissible values of an argument). +of admissible values of a a function\textsf{'}s argument). Having defined the function \lstinline!f!, we can now apply it to an integer value \lstinline!10! (or, as programmers say, \textsf{``}call\textsf{''} @@ -100,14 +98,13 @@ \subsection{Nameless functions\label{subsec:Nameless-functions}} involve \emph{naming} the function as \textsf{``}$f$\textsf{''}. Sometimes a function does not really need a name, \textemdash{} say, if the function is used only once. \textsf{``}Nameless\textsf{''} mathematical functions may be denoted -using the symbol $\rightarrow$ (pronounced \textsf{``}maps to\textsf{''}) like this:\footnote{In mathematics, the standard symbol for \textsf{``}maps to\textsf{''} is $\mapsto$, +using the symbol $\rightarrow$ (pronounced \textsf{``}maps to\textsf{''}) like this:\footnote{In mathematics, an often used symbol for \textsf{``}maps to\textsf{''} is $\mapsto$, but this book uses a simpler arrow symbol ($\rightarrow$) that is visually similar.} \[ x\rightarrow\left(\text{some formula}\right)\quad. \] -So, the mathematical notation for the nameless factorial function -is: +So, a mathematical notation for the nameless factorial function is: \[ n\rightarrow\prod_{k=1}^{n}k\quad. \] @@ -155,9 +152,8 @@ \subsection{Nameless functions\label{subsec:Nameless-functions}} scala> fac(10) res1: Int = 3628800 \end{lstlisting} - -However, functions can be used without naming them. We may directly -apply a nameless factorial function to an integer argument \lstinline!10! +Functions can be also used without naming them. We may directly apply +a nameless factorial function to an integer argument \lstinline!10! instead of writing \lstinline!fac(10)!: \begin{lstlisting} scala> ((n: Int) => (1 to n).product)(10) @@ -199,8 +195,7 @@ \subsection{Nameless functions\label{subsec:Nameless-functions}} Nameless functions are convenient when they are themselves arguments of other functions, as we will see next. -\subsubsection{Example \label{subsec:Example-prime-numbers}\ref{subsec:Example-prime-numbers}: -prime numbers} +\subsubsection{Example \label{subsec:Example-prime-numbers}\ref{subsec:Example-prime-numbers}} Define a function that takes an integer argument $n$ and determines whether $n$ is a prime number. @@ -210,9 +205,9 @@ \subsubsection{Example \label{subsec:Example-prime-numbers}\ref{subsec:Example-p \begin{equation} \text{isPrime}\left(n\right)=\forall k\in\left[2,n-1\right].\ (n\%k)\neq0\quad.\label{eq:is_prime_def} \end{equation} -This formula has two clearly separated parts: first, a range of integers -from $2$ to $n-1$, and second, a requirement that all these integers -$k$ should satisfy the given condition: $(n\%k)\neq0$. Formula~(\ref{eq:is_prime_def}) +This formula has two parts: first, a range of integers from $2$ to +$n-1$, and second, a requirement that all these integers $k$ should +satisfy the given condition: $(n\%k)\neq0$. Formula~(\ref{eq:is_prime_def}) is translated into Scala code as: \begin{lstlisting} def isPrime(n: Int) = (2 to n-1).forall(k => n % k != 0) @@ -242,7 +237,7 @@ \subsubsection{Example \label{subsec:Example-prime-numbers}\ref{subsec:Example-p A function that returns a \lstinline!Boolean! value is called a \textbf{predicate}\index{predicate}. In Scala, it is strongly recommended (although often not mandatory) -to specify the return type of named functions. The required syntax +to specify the return types of named functions. The required syntax looks like this: \begin{lstlisting} def isPrime(n: Int): Boolean = (2 to n-1).forall(k => n % k != 0) @@ -274,7 +269,7 @@ \subsection{Nameless functions and bound variables} A single-argument function could be also defined as a method, and then the syntax is \lstinline!x.f!, as in the expression \texttt{}\lstinline!(1 to n).product! -we have seen before. +shown before. The methods \texttt{}\lstinline!product! and \texttt{}\lstinline!forall! are already provided in the Scala standard library, so it is natural @@ -297,23 +292,23 @@ \subsection{Nameless functions and bound variables} is then used for writing the predicate $(n\%k)\neq0$. Let us investigate the role of $k$ more closely. The mathematical -variable $k$ is actually defined \emph{only inside} the expression -\textsf{``}$\forall k:...$\textsf{''} and makes no sense outside that expression. -This becomes clear by looking at Eq.\ (\ref{eq:is_prime_def}): The -variable $k$ is not present in the left-hand side and could not possibly -be used there. The name \textsf{``}$k$\textsf{''} is defined only in the right-hand -side, where it is first mentioned as the arbitrary element $k\in\left[2,n-1\right]$ +variable $k$ is accessible \emph{only inside} the expression \textsf{``}$\forall k.\,...$\textsf{''} +and makes no sense outside that expression. This becomes clear by +looking at Eq.\ (\ref{eq:is_prime_def}): The variable $k$ is not +present in the left-hand side and could not possibly be used there. +The name \textsf{``}$k$\textsf{''} is accessible only in the right-hand side, where +it is first mentioned as the arbitrary element $k\in\left[2,n-1\right]$ and then used in the sub-expression \textsf{``}$n\%k$\textsf{''}. So, the mathematical notation in Eq.~(\ref{eq:prime-formula-function}) says two things: First, we use the name $k$ for integers from $2$ to $n-1$. Second, for each of those $k$ we evaluate the expression -$(n\%k)\neq0$, which can be viewed as a certain given \emph{function} -\emph{of} $k$ that returns a \lstinline!Boolean! value. Translating -the mathematical notation into code, it is therefore natural to use -the nameless function $k\rightarrow(n\%k)\neq0$ and to write Scala -code applying this nameless function to each element of the range -$\left[2,n-1\right]$ and checking that all result values be \lstinline!true!: +$(n\%k)\neq0$, which can be viewed as a certain \emph{function} \emph{of} +$k$ that returns a \lstinline!Boolean! value. Translating the mathematical +notation into code, it is natural to use the nameless function $k\rightarrow(n\%k)\neq0$ +and to write Scala code applying this nameless function to each element +of the range $\left[2,n-1\right]$ and checking that all result values +be \lstinline!true!: \begin{lstlisting} (2 to n-1).forall(k => n % k != 0) \end{lstlisting} @@ -321,8 +316,8 @@ \subsection{Nameless functions and bound variables} Just as the mathematical notation defines the variable $k$ only in the right-hand side of Eq.\ (\ref{eq:is_prime_def}), the argument \lstinline!k! of the nameless Scala function \lstinline*k => n % k != 0* -is defined only within that function\textsf{'}s body and cannot be used in -any code outside the expression \lstinline*n % k != 0*. +is defined within that function\textsf{'}s body and cannot be used in any +code outside the expression \lstinline*n % k != 0*. Variables that are defined only inside an expression and are invisible outside are called \textbf{bound variables}\index{bound variable|textit}, @@ -331,9 +326,9 @@ \subsection{Nameless functions and bound variables} variables}\index{free variable}, or \textsf{``}variables occurring free in an expression\textsf{''}. These concepts apply equally well to mathematical formulas and to Scala code. For example, in the mathematical expression -$k\rightarrow(n\%k)\neq0$ (which is a nameless function), the variable -$k$ is bound (it is defined only within that expression) but the -variable $n$ is free (it is defined outside that expression). +$\forall k.\,(n\%k)\neq0$, the variable $k$ is bound (defined and +only visible within that expression\textsf{'}s scope) but the variable $n$ +is free: it must be defined somewhere outside the expression $\forall k.\,(n\%k)\neq0$. The main difference between free and bound variables is that bound variables can be \emph{locally renamed} at will, unlike free variables. @@ -348,23 +343,24 @@ \subsection{Nameless functions and bound variables} The argument \lstinline!z! in the nameless function \lstinline*z => n % z != 0* is a bound variable: it may be renamed without changing any code outside -that function. But \lstinline!n! is a free variable (it is not defined -inside the function). If we wanted to rename \lstinline!n! in the -sub-expression \lstinline*z => n % z != 0*, we would also need to -change all the code that involves the variable \lstinline!n! \emph{outside} -that sub-expression, or else the program would become incorrect. +that function. But \lstinline!n! is a free variable within \lstinline*z => n % z != 0* +(it is not defined inside that function, so it must be defined outside). +If we wanted to rename \lstinline!n! in the sub-expression \lstinline*z => n % z != 0*, +we would also need to change all the code that involves the variable +\lstinline!n! outside that sub-expression, or else the program would +become incorrect. Mathematical formulas use bound variables in constructions such as $\forall k.\,p(k)$, $\exists k.\,p(k)$, $\sum_{k=a}^{b}f(k)$, $\int_{0}^{1}k^{2}dk$, -$\lim_{n\rightarrow\infty}f(n)$, and $\text{argmax}_{k}f\left(k\right)$. -When translating mathematical expressions into code, we need to recognize +$\lim_{n\rightarrow\infty}f(n)$, and $\text{argmax}_{k}f(k)$. When +translating mathematical expressions into code, we need to recognize the bound variables present in the mathematical notation. For each bound variable, we create a nameless function whose argument is that variable, e.g., \lstinline!k => p(k)! or \lstinline!k => f(k)! for the examples just shown. Then our code will correctly reproduce the behavior of bound variables in mathematical expressions. -As an example, the mathematical formula $\forall k\in\left[1,n\right].\,p\left(k\right)$ +As an example, the mathematical formula $\forall k\in\left[1,n\right].\,p(k)$ has a bound variable $k$ and is translated into Scala code as: \begin{lstlisting} @@ -383,15 +379,14 @@ \subsection{Nameless functions and bound variables} The simplification of $x\rightarrow f(x)$ to just $f$ is always possible for functions $f$ of a single argument.\footnote{Certain features of Scala allow programmers to write code that looks like \lstinline!f(x)! but actually uses an automatic conversion for -the argument \lstinline!x! or additional hidden arguments of the -function \lstinline!f!. In those cases, replacing the code \lstinline!x => f(x)! -by \lstinline!f! will fail to compile. This problem does not appear -when working with simple functions.} +the argument \lstinline!x!, default argument values, or implicit +arguments. In those cases, replacing the code \lstinline!x => f(x)! +by \lstinline!f! will fail to compile. } \section{Aggregating data from sequences} -Consider the task of counting how many even numbers there are in a -given list $L$ of integers. For example, the list $\left[5,6,7,8,9\right]$ +Consider the task of counting the \emph{even} numbers contained in +a given list $L$ of integers. For example, the list $\left[5,6,7,8,9\right]$ contains \emph{two} even numbers: $6$ and $8$. A mathematical formula for this task can be written using the \textsf{``}sum\textsf{''} @@ -415,7 +410,7 @@ \section{Aggregating data from sequences} \begin{lstlisting} def isEven(k: Int): Int = (k % 2) match { case 0 => 1 // First, check if it is zero. - case _ => 0 // The underscore matches everything else. + case _ => 0 // The underscore means "otherwise". } \end{lstlisting} @@ -427,14 +422,14 @@ \section{Aggregating data from sequences} \end{lstlisting} Given this function, we now need to translate into Scala code the -expression $\sum_{k\in L}\text{is\_even}\left(k\right)$. We can represent +expression $\sum_{k\in L}\text{isEven}\left(k\right)$. We can represent the list $L$ using the data type \lstinline!List[Int]! from the Scala standard library. -To compute $\sum_{k\in L}\text{is\_even}\left(k\right)$, we must -apply the function \texttt{}\lstinline!isEven! to each element of -the list $L$, which will produce a list of some (integer) results, -and then we will need to add all those results together. It is convenient +To compute $\sum_{k\in L}\text{isEven}\left(k\right)$, we must apply +the function \texttt{}\lstinline!isEven! to each element of the +list $L$, which will produce a list of some (integer) results, and +then we will need to add all those results together. It is convenient to perform these two steps separately. This can be done with the functions \texttt{}\lstinline!map! and \lstinline!sum!, defined in the Scala standard library as methods for the data type \lstinline!List!. @@ -466,7 +461,7 @@ \section{Aggregating data from sequences} It is equally possible to define the transforming function separately, give it a name, and then use it as the argument to \lstinline!map!: \begin{lstlisting} -scala> def func1(x: Int): Int = x*x + 100*x +scala> def func1(x: Int): Int = x * x + 100 * x func1: (x: Int)Int scala> List(1, 2, 3).map(func1) @@ -561,12 +556,9 @@ \section{Filtering and truncating a sequence } \text{forall}\left(S,p\right) & =\forall k\in S.\,\big(p(k)=\text{true}\big)\quad,\\ \text{exists}\left(S,p\right) & =\exists k\in S.\,\big(p(k)=\text{true}\big)\quad. \end{align*} -Operations such as \textsf{``}removing elements from a list\textsf{''} will be written -in the Scala syntax because they do not have a concise mathematical -notation. -The \lstinline!filter! method returns a list that contains only the -values for which a predicate returns \texttt{}\lstinline!true!: +The \lstinline!filter! method returns a list that contains only +the values for which a predicate returns \texttt{}\lstinline!true!: \begin{lstlisting} scala> List(1, 2, 3, 4, 5).filter(k => k != 3) // Exclude the value 3. @@ -630,7 +622,7 @@ \subsubsection{Example \label{subsec:ch1-aggr-Example-1}\ref{subsec:ch1-aggr-Exa \begin{lstlisting} def isPrime(n: Int): Boolean = { (2 to n-1) - .takeWhile(k => k*k <= n) + .takeWhile(k => k * k <= n) .forall(k => n % k != 0) } \end{lstlisting} @@ -708,7 +700,7 @@ \subsubsection{Example \label{subsec:ch1-aggr-Example-5-Wallis-product}\ref{subs the $i^{\text{th}}$ fraction. The method \texttt{}\lstinline!toDouble! converts integers to \texttt{}\lstinline!Double! numbers: \begin{lstlisting} -def wallis_frac(i: Int): Double = ((2*i).toDouble/(2*i - 1))*((2*i).toDouble/(2*i + 1)) +def wallis_frac(i: Int): Double = ((2 * i).toDouble / (2 * i - 1)) * ((2 * i).toDouble / (2 * i + 1)) def wallis(n: Int) = (1 to n).map(wallis_frac).product @@ -723,7 +715,7 @@ \subsubsection{Example \label{subsec:ch1-aggr-Example-5-Wallis-product}\ref{subs \subsubsection{Example \label{subsec:ch1-aggr-Example-7}\ref{subsec:ch1-aggr-Example-7}} -Check numerically the infinite product formula: +Check numerically the following infinite product formula: \[ \prod_{k=1}^{\infty}\left(1-\frac{x^{2}}{k^{2}}\right)=\frac{\sin\pi x}{\pi x}\quad. \] @@ -734,7 +726,7 @@ \subsubsection{Example \label{subsec:ch1-aggr-Example-7}\ref{subsec:ch1-aggr-Exa Compute this product up to $k=n$ for $x=0.1$ with a large value of $n$, say $n=10^{5}$, and compare with the right-hand side: \begin{lstlisting} -def sine_product(n: Int, x: Double): Double = (1 to n).map(k => 1.0 - x*x/k/k).product +def sine_product(n: Int, x: Double): Double = (1 to n).map(k => 1.0 - x * x / k / k).product scala> sine_product(n = 100000, x = 0.1) // Arguments may be named, for clarity. res0: Double = 0.9836317414461351 @@ -821,9 +813,9 @@ \section{Summary} Functional programs are mathematical formulas translated into code. Table~\ref{tab:translating-mathematics-into-code} summarizes the tools explained in this chapter and gives implementations of some -mathematical constructions in Scala. We have also shown the methods -\lstinline!size! and \lstinline!takeWhile! that do not correspond -to widely used mathematical symbols. +mathematical constructions in Scala. We have also shown methods such +as \lstinline!takeWhile! that do not correspond to widely used mathematical +symbols. \begin{table} \begin{centering} @@ -832,13 +824,13 @@ \section{Summary} \textbf{Mathematical notation} & \textbf{Scala code}\tabularnewline \hline \hline -$x\rightarrow\sqrt{x^{2}+1}$ & \lstinline!x => math.sqrt(x*x + 1)!\tabularnewline +$x\rightarrow\sqrt{x^{2}+1}$ & \lstinline!x => math.sqrt(x * x + 1)!\tabularnewline \hline $\left[1,~2,~...,~n\right]$ & \lstinline!(1 to n)!\tabularnewline \hline $\left[f(1),~...,~f(n)\right]$ & \lstinline!(1 to n).map(k => f(k))!\tabularnewline \hline -$\sum_{k=1}^{n}k^{2}$ & \lstinline!(1 to n).map(k => k*k).sum!\tabularnewline +$\sum_{k=1}^{n}k^{2}$ & \lstinline!(1 to n).map(k => k * k).sum!\tabularnewline \hline $\prod_{k=1}^{n}f(k)$ & \lstinline!(1 to n).map(f).product!\tabularnewline \hline @@ -872,7 +864,8 @@ \section{Summary} \end{itemize} These computations require a general case of \emph{mathematical induction}\index{mathematical induction}. Chapter\ \ref{chap:2-Mathematical-induction} will explain how to -implement these tasks using recursion. +implement these tasks using recursion as well as using library methods +such as \lstinline!foldLeft!. Library functions we have seen so far, such as \texttt{}\lstinline!map! and \lstinline!filter!, implement a restricted class of iterative @@ -887,7 +880,7 @@ \section{Summary} containing \lstinline!map!, \lstinline!filter!, \lstinline!takeWhile!, etc., that solves Example\ 1. We could write the solution of Example\ 1 as a formula by using mathematical induction, but we have not yet -seen how to implement that in Scala code. +seen how to translate that into Scala code. An implementation of Example\ 2 is shown in Section~\ref{sec:Transforming-a-sequence}. This cannot be implemented with operations such as \texttt{}\lstinline!map! @@ -920,9 +913,8 @@ \subsubsection{Exercise \label{subsec:ch1-aggr-Exercise-1}\ref{subsec:ch1-aggr-E \end{align*} Implement a function that computes the series for $\arctan\frac{1}{n}$ up to a given number of terms, and compute an approximation of $\pi$ -using this formula. Show that $12$ terms of the series are already -sufficient for a full-precision \lstinline!Double! approximation -of $\pi$. +using this formula. Show that $12$ terms of the series are sufficient +for a full-precision \lstinline!Double! approximation of $\pi$. \subsubsection{Exercise \label{subsec:ch1-aggr-Example-6}\ref{subsec:ch1-aggr-Example-6}} @@ -935,11 +927,11 @@ \subsubsection{Exercise \label{subsec:ch1-aggr-Exercise-2}\ref{subsec:ch1-aggr-E Using the function \lstinline!isPrime!, check numerically the Euler product\index{Euler product} formula\footnote{\texttt{\href{http://tinyurl.com/4rjj2rvc}{http://tinyurl.com/4rjj2rvc}}} -for the Riemann\textsf{'}s zeta function\index{Riemann\textsf{'}s zeta function} $\zeta\left(4\right)$. +for the Riemann\textsf{'}s zeta function\index{Riemann\textsf{'}s zeta function} $\zeta(4)$. It is known\footnote{\texttt{\href{https://ocw.mit.edu/courses/mathematics/18-104-seminar-in-analysis-applications-to-number-theory-fall-2006/projects/chan.pdf}{https://tinyurl.com/yxey4tsd}}} -that $\zeta\left(4\right)=\frac{\pi^{4}}{90}$: +that $\zeta(4)=\frac{\pi^{4}}{90}$: \[ -\zeta\left(4\right)=\prod_{k\geq2;~k\text{ is prime}}\frac{1}{1-\frac{1}{k^{4}}}=\frac{\pi^{4}}{90}\quad. +\zeta(4)=\prod_{k\geq2;~k\text{ is prime}}\frac{1}{1-\frac{1}{k^{4}}}=\frac{\pi^{4}}{90}\quad. \] @@ -958,7 +950,7 @@ \subsubsection{Exercise \label{subsec:ch1-transf-Exercise-1}\ref{subsec:ch1-tran \subsubsection{Exercise \label{subsec:ch1-transf-Exercise-2}\ref{subsec:ch1-transf-Exercise-2}} An integer $n$ is called a \textsf{``}$3$-factor\textsf{''} if it is divisible by -only three different integers $i$, $j$, $k$ such that $1 Boolean!, an integer $n$ is called a \textsf{``}$3$-$f$\textsf{''} if there are only three different integers -$1 x * x).sum + math.sqrt(x2sum / (n - 1) - xsum * xsum / n / (n - 1)) +} + +scala> sigma(Seq(10, 20, 30)) +res0: Double = 10.0 +\end{lstlisting} + +The programmer can avoid writing loops because all iterative computations +are delegated to functions such as \lstinline!map!, \lstinline!filter!, +\lstinline!sum!, and others. It is the job of the library and the +compiler to translate those high-level functions into low-level machine +code. The machine code \emph{will} likely contain loops, but the programmer +does not need to see that machine code or to reason about it. + \subsection{The mathematical meaning of \textquotedblleft variables\textquotedblright} The usage of variables in functional programming is similar to how @@ -1127,8 +1165,8 @@ \subsection{The mathematical meaning of \textquotedblleft variables\textquotedbl \begin{lstlisting} val x: Int = 123 \end{lstlisting} -or we could omit the type annotation \lstinline!:Int! and write more -concisely: +We could also omit the type annotation \textsf{``}\lstinline!:Int!\textsf{''} and +write more concisely: \begin{lstlisting} val x = 123 \end{lstlisting} @@ -1147,61 +1185,12 @@ \subsection{The mathematical meaning of \textquotedblleft variables\textquotedbl \end{lstlisting} -\subsection{Iteration without loops} - -A distinctive feature of the FP paradigm is handling of iteration -\emph{without} writing loops, just as iterative computations are written -in mathematical notation. - -As an example, consider the formula for the standard deviation ($\sigma$) -estimated from a data sample $\left[x_{1},...,x_{n}\right]$: -\[ -\sigma=\sqrt{\frac{1}{n-1}\sum_{i=1}^{n}x_{i}^{2}-\frac{1}{n\left(n-1\right)}\left(\sum_{i=1}^{n}x_{i}\right)^{2}}\quad. -\] -Here the index $i$ goes over the integer range $\left[1,...,n\right]$. -And yet no mathematics textbook would define this formula via loops -or by saying \textsf{``}now repeat equation $X$ ten times\textsf{''}. Indeed, it -is unnecessary to evaluate a formula such as $x_{i}^{2}$ ten times: -the value of $x_{i}^{2}$ remains the same every time. It is just -as unnecessary to \textsf{``}repeat\textsf{''} a mathematical equation. - -Instead of loops, mathematicians write \emph{expressions} such as -$\sum_{i=1}^{n}s_{i}$, where symbols such as $\sum_{i=1}^{n}$ denote -the results of entire iterative computations. Such computations are -defined using mathematical induction\index{mathematical induction}. -The FP paradigm has developed rich tools for translating mathematical -induction into code. This chapter focuses on methods such as \lstinline!map!, -\lstinline!filter!, and \lstinline!sum!. The next chapter shows -more general methods for implementing inductive computations. These -methods can be combined in flexible ways, enabling programmers to -write iterative code without loops. For example, the value $\sigma$ -defined by the formula shown above is computed by code that looks -like this: -\begin{lstlisting} -def sigma(xs: Seq[Double]): Double = { - val n = xs.length.toDouble - val xsum = xs.sum - val x2sum = xs.map(x => x * x).sum - math.sqrt(x2sum / (n - 1) - xsum * xsum / n / (n - 1)) -} - -scala> sigma(Seq(10, 20, 30)) -res0: Double = 10.0 -\end{lstlisting} - -The programmer can avoid writing loops because all iterative computations -are delegated to functions such as \lstinline!map!, \lstinline!filter!, -\lstinline!sum!, and others. It is the job of the library and the -compiler to translate those high-level functions into low-level machine -code. The machine code \emph{will} likely contain loops, but the programmer -does not need to see that machine code or to reason about it. - \subsection{Nameless functions in mathematical notation\label{subsec:Nameless-functions-in-mathematical-notation}} Functions in mathematics are mappings from one set to another. A function -does not necessarily \emph{need} a name; the mapping just needs to -be defined. However, nameless functions have not been widely used -in the conventional mathematical notation. It turns out that nameless +does not necessarily \emph{need} a name; we just need to define the +mapping. However, nameless functions have not been widely used in +the conventional mathematical notation. It turns out that nameless functions are important in functional programming because, in particular, they allow programmers to write code with a straightforward and consistent syntax. @@ -1215,9 +1204,9 @@ \subsection{Nameless functions in mathematical notation\label{subsec:Nameless-fu The mathematical convention is that one may rename the integration variable at will, and so these formulas define the same function $f$. -In programming, the only situation when a variable \textsf{``}may be renamed -at will\textsf{''} is when the variable represents an argument of a function. -It follows that the notations $\frac{dx}{1+x}$ and $\frac{dz}{1+z}$ +In programming, one situation when a variable \textsf{``}may be renamed at +will\textsf{''} is when the variable represents an argument of a function. +We can see that the notations $\frac{dx}{1+x}$ and $\frac{dz}{1+z}$ correspond to a nameless function whose argument was renamed from $x$ to $z$. In FP notation, this nameless function would be denoted as $z\rightarrow\frac{1}{1+z}$, and the integral rewritten as code @@ -1242,8 +1231,7 @@ \subsection{Nameless functions in mathematical notation\label{subsec:Nameless-fu and does not use the special symbol \textsf{``}$d$\textsf{''} but takes a function as an argument. Written in this way, the operations of summation and integration become \emph{functions} that take functions as arguments. -The above summation may be written in a consistent and straightforward -manner as a Scala function: +The above summation may be written as a Scala function: \begin{lstlisting} summation(0, x, { y => 1.0 / (1 + y) } ) \end{lstlisting} @@ -1260,7 +1248,7 @@ \subsection{Nameless functions in mathematical notation\label{subsec:Nameless-fu \index{Simpson\textsf{'}s rule}Simpson\textsf{'}s rule\footnote{\texttt{\href{https://en.wikipedia.org/wiki/Simpson\%27s_rule}{https://en.wikipedia.org/wiki/Simpson\%27s\_rule}}} gives the following formulas for numerical integration: \begin{align*} -\text{Simpson}\left(a,b,g,\varepsilon\right) & =\frac{\delta}{3}\big(g(a)+g(b)+4s_{1}+2s_{2}\big)\quad,\\ +\text{simpson}\left(a,b,g,\varepsilon\right) & =\frac{\delta}{3}\big(g(a)+g(b)+4s_{1}+2s_{2}\big)\quad,\\ \text{where }~~~n & =2\left\lfloor \frac{b-a}{\varepsilon}\right\rfloor \quad,\quad\quad\delta_{x}=\frac{b-a}{n}\quad,\\ s_{1}=\sum_{k=1,3,...,n-1}g(a+k\delta_{x}) & \quad,\quad\quad s_{2}=\sum_{k=2,4,...,n-2}g(a+k\delta_{x})\quad. \end{align*} @@ -1406,7 +1394,7 @@ \subsection{Historical perspective on nameless functions} \hline {\footnotesize{}Go} & {\footnotesize{}2012} & \lstinline!func(k int) { return k + 1 }!\tabularnewline \hline -{\footnotesize{}Julia} & {\footnotesize{}2012} & \lstinline!function(k:: Int) k + 1 end!\tabularnewline +{\footnotesize{}Julia} & {\footnotesize{}2012} & \lstinline!function(k :: Int) k + 1 end!\tabularnewline \hline {\footnotesize{}Kotlin} & {\footnotesize{}2012} & \lstinline!{ k: Int -> k + 1 }!\tabularnewline \hline diff --git a/sofp-src/sofp-preface.lyx b/sofp-src/sofp-preface.lyx index 6d9764866..c4f50ca03 100644 --- a/sofp-src/sofp-preface.lyx +++ b/sofp-src/sofp-preface.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -313,7 +313,7 @@ Preface This book is a reference text and a tutorial that teaches functional programmers how to reason mathematically about types and code, in a manner directly relevant to software practice. - The material ranges from introductory to advanced. + The material ranges from introductory (Part I) to advanced (Part III). \begin_inset Note Comment status collapsed @@ -381,8 +381,8 @@ noprefix "false" \end_layout \begin_layout Standard -All concepts and techniques are motivated, illustrated by examples and explained - as simply as possible ( +All concepts and techniques are illustrated by examples and explained as + simply as possible ( \begin_inset Quotes eld \end_inset @@ -396,7 +396,7 @@ but not simpler \begin_layout Standard A software engineer needs to learn only those few fragments of mathematical - theory that answer questions arising in the practice of functional programming. + theory that answer questions arising in the programming practice. So, this book keeps theoretical material at the minimum: \emph on vita brevis, ars longa @@ -708,7 +708,7 @@ noprefix "false" \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch1-aggr-Example-6" +reference "subsec:ch1-aggr-Example-1" plural "false" caps "false" noprefix "false" @@ -747,19 +747,7 @@ noprefix "false" \end_layout \begin_layout Itemize -Scala code is written inline using a small monospaced font, such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -flatMap -\end_layout - -\end_inset - - or +Scala code is written inline using a small monospaced font: \begin_inset listings inline true status open @@ -838,8 +826,8 @@ noprefix "false" \end_inset -, the book introduces and uses a new notation for types: e.g., the Scala type - expression +, the book introduces a mathematical notation for types: for example, the + Scala type expression \begin_inset listings inline true status open @@ -994,11 +982,11 @@ noprefix "false" \end_inset - summarizes this book's chosen notation for types and code. + summarizes this book's notation for types and code. \end_layout \begin_layout Itemize -Frequently used methods of standard typeclasses, named in Scala as +Frequently used methods of standard typeclasses, such as Scala's \begin_inset listings inline true status open @@ -1022,18 +1010,6 @@ flatMap \end_inset -, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -filter -\end_layout - -\end_inset - , etc., are denoted by shorter words and are labeled by the type constructor they belong to. For instance, the methods @@ -1111,8 +1087,8 @@ next \end_inset -When the two-column presentation becomes too wide, the explanations are - placed before the next step's line: +When the two-column presentation becomes too wide to fit the page, the explanati +ons are placed before the next step's line: \begin_inset Formula \begin{align*} & \quad\text{expect to equal }\text{pu}_{M}:\quad\\ @@ -1127,8 +1103,8 @@ When the two-column presentation becomes too wide, the explanations are A green underline is sometimes also used at the last step of a derivation, to indicate the sub-expression that resulted from the most recent rewriting. - Other than providing hints to help remember the steps, the green text - and the green underlines + Other than providing hints to help clarify the steps, the green text and + the green underlines \emph on play no role \emph default diff --git a/sofp-src/sofp-preface.tex b/sofp-src/sofp-preface.tex index 0c12314da..fbd1ffbeb 100644 --- a/sofp-src/sofp-preface.tex +++ b/sofp-src/sofp-preface.tex @@ -7,7 +7,7 @@ This book is a reference text and a tutorial that teaches functional programmers how to reason mathematically about types and code, in a manner directly relevant to software practice. The material ranges -from introductory to advanced. % +from introductory (Part I) to advanced (Part III). % \begin{comment} Readers will need to learn some difficult concepts through prolonged mental concentration and effort. @@ -32,20 +32,19 @@ are in Scala, the material in this book also applies to many other functional programming languages. -All concepts and techniques are motivated, illustrated by examples -and explained as simply as possible (\textsf{``}but not simpler\textsf{''}, as Einstein -said). Exercises should be attempted after absorbing the preceding -material. +All concepts and techniques are illustrated by examples and explained +as simply as possible (\textsf{``}but not simpler\textsf{''}, as Einstein said). Exercises +should be attempted after absorbing the preceding material. A software engineer needs to learn only those few fragments of mathematical -theory that answer questions arising in the practice of functional -programming. So, this book keeps theoretical material at the minimum: -\emph{vita brevis, ars longa}. The scope of the required mathematical -knowledge is limited to first notions of set theory, formal logic, -and category theory. Concepts such as functors or natural transformations -arise organically from the practice of reasoning about code and are -first introduced without reference to category theory. This book does -not use \textsf{``}introduction/elimination rules\textsf{''}, \textsf{``}strong normalization\textsf{''}, +theory that answer questions arising in the programming practice. +So, this book keeps theoretical material at the minimum: \emph{vita +brevis, ars longa}. The scope of the required mathematical knowledge +is limited to first notions of set theory, formal logic, and category +theory. Concepts such as functors or natural transformations arise +organically from the practice of reasoning about code and are first +introduced without reference to category theory. This book does not +use \textsf{``}introduction/elimination rules\textsf{''}, \textsf{``}strong normalization\textsf{''}, \textsf{``}complete partial orders\textsf{''}, \textsf{``}adjoint functors\textsf{''}, \textsf{``}pullbacks\textsf{''}, \textsf{``}co-ends\textsf{''}, or \textsf{``}topoi\textsf{''}, as learning those concepts will neither help programmers write code nor answer any practical questions about @@ -96,13 +95,12 @@ \end{quotation} \begin{itemize} \item Equations are numbered per chapter: Eq.~(\ref{eq:prime-formula-function}). -Statements, examples, and exercises are numbered per subsection: Example~\ref{subsec:ch1-aggr-Example-6} +Statements, examples, and exercises are numbered per subsection: Example~\ref{subsec:ch1-aggr-Example-1} is in subsection~\ref{subsec:Aggregation-solved-examples}, which belongs to Chapter~\ref{chap:1-Values,-types,-expressions,}. -\item Scala code is written inline using a small monospaced font, such as -\lstinline!flatMap! or \lstinline!val a = "xyz"!. Longer code examples -are written in separate code blocks and may also show the Scala interpreter\textsf{'}s -output for certain lines: +\item Scala code is written inline using a small monospaced font: \lstinline!val a = "xyz"!. +Longer code examples are written in separate code blocks and may also +show the Scala interpreter\textsf{'}s output for certain lines: \begin{lstlisting}[mathescape=true] val s = (1 to 10).toList @@ -111,9 +109,9 @@ \end{lstlisting} \item In the introductory chapters, type expressions and code examples are written in the syntax of Scala. Starting from Chapters~\ref{chap:Higher-order-functions}\textendash \ref{chap:5-Curry-Howard}, -the book introduces and uses a new notation for types: e.g., the Scala -type expression \lstinline!((A, B)) => Option[A]! is written as $A\times B\rightarrow\bbnum 1+A$. -Chapters~\ref{chap:Higher-order-functions}\textendash \ref{chap:Reasoning-about-code} +the book introduces a mathematical notation for types: for example, +the Scala type expression \lstinline!((A, B)) => Option[A]! is written +as $A\times B\rightarrow\bbnum 1+A$. Chapters~\ref{chap:Higher-order-functions}\textendash \ref{chap:Reasoning-about-code} also develop a more concise notation for code. For example, the functor composition law (in Scala: \lstinline!_.map(f).map(g) == _.map(f andThen g)!) is written in the code notation as: @@ -126,14 +124,13 @@ Scala\textsf{'}s syntax \lstinline!x.map(f)! where \lstinline!x! is of type \lstinline!L[A]!. The symbol $\bef$ denotes the forward composition of functions (Scala\textsf{'}s method \lstinline!andThen!). Appendix~\ref{chap:Appendix-Notations} -summarizes this book\textsf{'}s chosen notation for types and code. -\item Frequently used methods of standard typeclasses, named in Scala as -\lstinline!flatten!, \lstinline!flatMap!, \lstinline!filter!, etc., -are denoted by shorter words and are labeled by the type constructor -they belong to. For instance, the methods \lstinline!pure!, \lstinline!flatten!, -and \lstinline!flatMap! for a monad $M$ are denoted by $\text{pu}_{M}$, -$\text{ftn}_{M}$, and $\text{flm}_{M}$ when writing code formulas -and proofs of laws. +summarizes this book\textsf{'}s notation for types and code. +\item Frequently used methods of standard typeclasses, such as Scala\textsf{'}s \lstinline!flatten!, +\lstinline!flatMap!, etc., are denoted by shorter words and are labeled +by the type constructor they belong to. For instance, the methods +\lstinline!pure!, \lstinline!flatten!, and \lstinline!flatMap! +for a monad $M$ are denoted by $\text{pu}_{M}$, $\text{ftn}_{M}$, +and $\text{flm}_{M}$ when writing code formulas and proofs of laws. \item Derivations are written in a two-column format. The right column contains formulas in the code notation. The left column gives an explanation or indicates the property or law used to derive the expression at @@ -144,8 +141,8 @@ {\color{greenunder}\text{lifting to the identity functor}:}\quad & =\text{pu}_{M}\bef\gunderline{\text{pu}_{M}\bef\text{ftn}_{M}}\\ {\color{greenunder}\text{left identity law of }M:}\quad & =\text{pu}_{M}\quad. \end{align*} -When the two-column presentation becomes too wide, the explanations -are placed before the next step\textsf{'}s line: +When the two-column presentation becomes too wide to fit the page, +the explanations are placed before the next step\textsf{'}s line: \begin{align*} & \quad{\color{greenunder}\text{expect to equal }\text{pu}_{M}:}\quad\\ & \gunderline{\text{pu}_{M}^{\uparrow\text{Id}}}\bef\text{pu}_{M}\bef\text{ftn}_{M}\\ @@ -156,8 +153,8 @@ \end{align*} A green underline is sometimes also used at the last step of a derivation, to indicate the sub-expression that resulted from the most recent -rewriting. Other than providing hints to help remember the steps, -the green text and the green underlines \emph{play no role} in symbolic +rewriting. Other than providing hints to help clarify the steps, the +green text and the green underlines \emph{play no role} in symbolic derivations. \item The symbol $\square$ is used occasionally to indicate more clearly the end of a definition, a derivation, or a proof. diff --git a/sofp-src/sofp-reasoning.lyx b/sofp-src/sofp-reasoning.lyx index e25302783..77e656f7a 100644 --- a/sofp-src/sofp-reasoning.lyx +++ b/sofp-src/sofp-reasoning.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -2219,7 +2219,11 @@ None \end_inset - is a named unit, this function is written in the code notation as + is a named unit and is denoted by +\begin_inset Formula $1$ +\end_inset + +, this function is written in the code notation as \begin_inset Formula $1\rightarrow\bbnum 0^{:\bbnum 1}+100^{:\text{Int}}$ \end_inset @@ -2252,7 +2256,19 @@ x \end_inset -, so we can denote that function by + and has type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Int +\end_layout + +\end_inset + +, so we denote that function by \begin_inset Formula $x^{:\text{Int}}\rightarrow\bbnum 0^{:\bbnum 1}+(x/2)^{:\text{Int}}$ \end_inset @@ -2261,8 +2277,8 @@ x \end_layout \begin_layout Standard -To obtain the matrix notation, we may simply write the two partial functions - in the two rows: +To obtain the matrix notation, we write the two partial functions in the + two rows: \begin_inset listings inline false status open diff --git a/sofp-src/sofp-reasoning.tex b/sofp-src/sofp-reasoning.tex index 52bfcd631..6a9a8efda 100644 --- a/sofp-src/sofp-reasoning.tex +++ b/sofp-src/sofp-reasoning.tex @@ -267,18 +267,18 @@ \subsection{The nine constructions of fully parametric code} \begin{lstlisting} { case None => Some(100) } \end{lstlisting} -Since \lstinline!None! is a named unit, this function is written -in the code notation as $1\rightarrow\bbnum 0^{:\bbnum 1}+100^{:\text{Int}}$. +Since \lstinline!None! is a named unit and is denoted by $1$, this +function is written in the code notation as $1\rightarrow\bbnum 0^{:\bbnum 1}+100^{:\text{Int}}$. The second line is written in the form of a partial function as: \begin{lstlisting} { case Some(x) => Some(x / 2) } \end{lstlisting} -The pattern variable on the left side is \lstinline!x!, so we can -denote that function by $x^{:\text{Int}}\rightarrow\bbnum 0^{:\bbnum 1}+(x/2)^{:\text{Int}}$. +The pattern variable on the left side is \lstinline!x! and has type +\lstinline!Int!, so we denote that function by $x^{:\text{Int}}\rightarrow\bbnum 0^{:\bbnum 1}+(x/2)^{:\text{Int}}$. -To obtain the matrix notation, we may simply write the two partial -functions in the two rows: +To obtain the matrix notation, we write the two partial functions +in the two rows: \begin{lstlisting} val compute: Option[Int] => Option[Int] = { case None => Some(100) diff --git a/sofp-src/sofp-summary.lyx b/sofp-src/sofp-summary.lyx index 910545c78..6bfd20a11 100644 --- a/sofp-src/sofp-summary.lyx +++ b/sofp-src/sofp-summary.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -4798,7 +4798,8 @@ not \end_inset ? -\end_layout +\begin_inset Note Note +status open \begin_layout Subsubsection Problem @@ -4821,7 +4822,7 @@ noprefix "false" \end_layout -\begin_layout Standard +\begin_layout Plain Layout \series bold (a) @@ -4921,7 +4922,7 @@ State -effects were collected?) \end_layout -\begin_layout Standard +\begin_layout Plain Layout \series bold (b) @@ -4997,7 +4998,7 @@ such that . \end_layout -\begin_layout Standard +\begin_layout Plain Layout It appears that this property \emph on cannot @@ -5098,6 +5099,11 @@ traverse is necessary? \end_layout +\end_inset + + +\end_layout + \begin_layout Subsubsection Problem \begin_inset CommandInset label diff --git a/sofp-src/sofp-summary.tex b/sofp-src/sofp-summary.tex index 134b51c02..9ca1bcaad 100644 --- a/sofp-src/sofp-summary.tex +++ b/sofp-src/sofp-summary.tex @@ -653,38 +653,6 @@ \subsubsection{Problem \label{subsec:Problem-co-pointed-applicative}\ref{subsec: but is \emph{not} of the form $A\times G^{A}$ with some applicative functor $G^{\bullet}$? -\subsubsection{Problem \label{par:Problem-traverse-law}\ref{par:Problem-traverse-law}} - -\textbf{(a)} Show that the applicative naturality law~(\ref{eq:traverse-applicative-naturality-law}), -the identity law~(\ref{eq:traverse-identity-law}), and the composition -law~(\ref{eq:composition-law-of-traverse}) of \lstinline!traverse! -guarantee that \lstinline!traverse! collects each $F$-effect exactly -once, or find another law that is necessary to guarantee that. (Can -we use a composition of an applicative functor $F$ with a \lstinline!State! -monad to count the number of times $F$-effects were collected?) - -\textbf{(b)} For any lawful traversable functor $L$, define the function -\lstinline!zipWithIndex! (denoted for brevity by $\text{zwi}_{L}$) -via Eq.~(\ref{eq:definition-of-zwi}). Show that there exists a \textsf{``}tabulating\textsf{''} -function (denoted by $\text{tab}_{L}^{A}$): -\[ -\text{tab}_{L}^{A}:L^{A\times\text{Int}}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad, -\] -such that $\text{zwi}_{L}\bef\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})=\text{id}^{:L^{A}\rightarrow L^{A}}$. -So, the function $\text{zwi}_{L}\bef\text{tab}_{L}$ is an injective -map of type $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$. - -It appears that this property \emph{cannot} be proved via the three -laws of \lstinline!traverse!. One reason is that the function $\text{tab}_{L}$ -produces an \textsf{``}indexing\textsf{''} function $f:\text{Int}\rightarrow A$, -which can be computed only by traversing the entire data structure -$L^{A}$. In other words, $f$ is a result of a traversal operation. -We want to prove a property of \lstinline!traverse! that combines -$f$ withanother traversal (\lstinline!zipWithIndex!). But there -are no laws of \lstinline!traverse! that involve reusing a result -of another traverse operation. What new law of \lstinline!traverse! -is necessary? - \subsubsection{Problem \label{par:Problem-monads-2}\ref{par:Problem-monads-2}} Monad transformers are defined in different ways for different monads. diff --git a/sofp-src/sofp-transformers.lyx b/sofp-src/sofp-transformers.lyx index cb7ce2a76..89e217ce3 100644 --- a/sofp-src/sofp-transformers.lyx +++ b/sofp-src/sofp-transformers.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -3853,15 +3853,9 @@ noprefix "false" \end_inset lists the types of some known monad transformers. - -\end_layout - -\begin_layout Standard -\begin_inset Wrap table -lines 0 -placement l -overhang 0in -width "59col%" +\begin_inset Float table +wide false +sideways false status open \begin_layout Plain Layout @@ -4349,6 +4343,10 @@ Known monad transformers for some monads. \end_inset +\end_layout + +\begin_layout Plain Layout + \end_layout \end_inset @@ -4357,7 +4355,6 @@ Known monad transformers for some monads. \end_layout \begin_layout Standard -\noindent Depending on the monad, the corresponding transformer is defined by composing inside the foreign monad ( \begin_inset listings @@ -4419,8 +4416,7 @@ List \end_inset -); and by mixing the foreign monad in a special way with the base monad - ( +); or by mixing the foreign monad in a special way with the base monad ( \begin_inset listings inline true status open @@ -4462,7 +4458,7 @@ Cont \end_layout \begin_layout Standard -It is not easy to determine the type of a monad transformer. +It is not always easy to determine the type of a monad transformer. \begin_inset Foot status open @@ -4643,12 +4639,12 @@ final case class ReaderT[M[_]: Monad : Functor, R, A](run: R => M[A]) { \begin_layout Plain Layout - .flatMap(f) // Type is M[ReaderT[M, R, B]]. + .map(f) // Type is M[ReaderT[M, R, B]]. \end_layout \begin_layout Plain Layout - .map(_.run(r)) // Type is M[B]. + .flatMap(_.run(r)) // Type is M[B]. \end_layout \begin_layout Plain Layout @@ -13649,10 +13645,11 @@ literal "false" \end_inset -) that defines typeclasses with sufficiently many operations for each supported - monad, so that any desired monadic program may be expressed through those - operations without using explicit monad types. - The library should also implement instances of those typeclasses for all +) that defines typeclasses for monad operations. + The library must support sufficiently many operations and monads, so that + any desired monadic program may be expressed via those operations without + using explicit monad types. + The library must also implement instances of those typeclasses for all supported monad stacks. \end_layout @@ -13706,14 +13703,86 @@ State As an example, look at \emph on updating +\emph default + the state using a given function of type +\begin_inset Formula $S\rightarrow S$ +\end_inset + +. + In many cases, updating is the same as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +get +\end_layout + +\end_inset + +ting the current state value and immediately +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +set +\end_layout + +\end_inset + +ting a new value. + However, certain kinds of updates need special handling. + Examples are: atomic updates in a concurrent program; updates wrapped in + a database transaction; and updates that must be run on a designated CPU + thread (e.g., the thread that drives the GUI events). + Such special handling of updates cannot be implemented via monadic programs + with just +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +get +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +set +\end_layout + +\end_inset + +. + A new effectful operation ( +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +update +\end_layout + +\end_inset + +) must be provided to the programmer. \end_layout \begin_layout Standard -\begin_inset Wrap table -lines 0 -placement l -overhang 0in -width "60col%" +\begin_inset Float table +wide false +sideways false status open \begin_layout Plain Layout @@ -13721,8 +13790,8 @@ status open \begin_inset Tabular - - + + \begin_inset Text @@ -14045,86 +14114,13 @@ name "tab:effectful-operations-for-some-monads" \end_layout -\end_inset - - -\end_layout - -\begin_layout Standard -\noindent -the state using a given function of type -\begin_inset Formula $S\rightarrow S$ -\end_inset - -. - In many cases, updating is the same as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -get -\end_layout - -\end_inset - -ting the current state value and immediately -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -set -\end_layout - -\end_inset - -ting a new value. - However, certain kinds of updates need special handling. - Examples are: atomic updates in a concurrent program; updates wrapped in - a database transaction; and updates that must be run on a designated CPU - thread (e.g., the thread that drives the GUI events). - Such special handling of updates cannot be implemented via monadic programs - with just -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -get -\end_layout - -\end_inset - - and -\begin_inset listings -inline true -status open - \begin_layout Plain Layout -set \end_layout \end_inset -. - A new effectful operation ( -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -update -\end_layout - -\end_inset -) must be provided to the programmer. \end_layout \begin_layout Standard @@ -14143,15 +14139,11 @@ noprefix "false" \end_inset shows a number of operations for some monads. -\begin_inset Foot -status open - -\begin_layout Plain Layout -Operations were gathered from the + Operations were gathered from the \family typewriter cats-mtl \family default - documentation and the papers + documentation as well as the papers \begin_inset Quotes eld \end_inset @@ -14163,9 +14155,13 @@ Monad transformers and modular interpreters \begin_inset Quotes erd \end_inset - (see -\family typewriter + +\begin_inset Foot +status open +\begin_layout Plain Layout + +\family typewriter \begin_inset CommandInset href LatexCommand href target "http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html" @@ -14174,8 +14170,11 @@ literal "false" \end_inset -\family default -) and +\end_layout + +\end_inset + + and \begin_inset Quotes eld \end_inset @@ -14187,9 +14186,13 @@ Modular monad transformers \begin_inset Quotes erd \end_inset - (see -\family typewriter + +\begin_inset Foot +status open +\begin_layout Plain Layout + +\family typewriter \begin_inset CommandInset href LatexCommand href target "https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.219.5365" @@ -14198,12 +14201,11 @@ literal "false" \end_inset -\family default -). \end_layout \end_inset +. The choice of operations is heuristic and does not follow any principle or system. It is not easy to decide what operations will be necessary in practical @@ -14237,8 +14239,8 @@ Either \begin_layout Standard Different libraries choose different sets of supported operations. - However, adding a new operation to a monad in an MTL-style library means - updating all typeclasses related to that monad. + Adding a new operation to a monad in an MTL-style library means updating + all typeclasses related to that monad. Users who cannot modify the library code will be unable to add new operations. \end_layout @@ -18432,8 +18434,7 @@ It is remarkable that all the laws of monad transformers can be derived is \emph on -just a pointed and optionally co-pointed endofunctor in the category of - monads +just a pointed and (perhaps) co-pointed endofunctor in the category of monads \emph default . \begin_inset Foot diff --git a/sofp-src/sofp-transformers.tex b/sofp-src/sofp-transformers.tex index 080cd323f..d0752810d 100644 --- a/sofp-src/sofp-transformers.tex +++ b/sofp-src/sofp-transformers.tex @@ -452,9 +452,8 @@ \subsection{Monad transformers for standard monads\label{subsec:Monad-transforme are known for every monad defined by fully parametric code. Transformers for some monads are obtained via functor composition; for other monads, transformers need to be defined in special ways. Table~\ref{tab:Known-monad-transformers} -lists the types of some known monad transformers. - -\begin{wraptable}{l}{0.59\columnwidth}% +lists the types of some known monad transformers. +\begin{table} \begin{centering} \begin{tabular}{|c|c|c|} \hline @@ -481,16 +480,17 @@ \subsection{Monad transformers for standard monads\label{subsec:Monad-transforme \par\end{centering} \caption{\label{tab:Known-monad-transformers}Known monad transformers for some monads.} -\end{wraptable}% -\noindent Depending on the monad, the corresponding transformer is -defined by composing inside the foreign monad (\lstinline!Either!, -\lstinline!Writer!); by composing outside the foreign monad (\lstinline!Reader!, -\lstinline!Sel!); by wrapping a recursive definition inside the foreign -monad (\lstinline!List!); and by mixing the foreign monad in a special -way with the base monad (\lstinline!Eval!, \lstinline!State!, \lstinline!Cont!). +\end{table} + +Depending on the monad, the corresponding transformer is defined by +composing inside the foreign monad (\lstinline!Either!, \lstinline!Writer!); +by composing outside the foreign monad (\lstinline!Reader!, \lstinline!Sel!); +by wrapping a recursive definition inside the foreign monad (\lstinline!List!); +or by mixing the foreign monad in a special way with the base monad +(\lstinline!Eval!, \lstinline!State!, \lstinline!Cont!). -It is not easy to determine the type of a monad transformer.\footnote{The difficulty of that task is illustrated by the history of the \lstinline!ListT! +It is not always easy to determine the type of a monad transformer.\footnote{The difficulty of that task is illustrated by the history of the \lstinline!ListT! transformer in the Haskell standard library. The transformer \lstinline!ListT! was implemented incorrectly in 2002; the code violated the monad laws. The faulty transformer remained in the library until 2007. See the @@ -515,8 +515,8 @@ \subsection{Monad transformers for standard monads\label{subsec:Monad-transforme def map[B](f: A => B): ReaderT[M, R, B] = ReaderT(r => run(r).map(f)) def flatMap[B](f: A => ReaderT[M, R, B]): ReaderT[M, R, B] = ReaderT { r => run(r) // Type is M[A]. - .flatMap(f) // Type is M[ReaderT[M, R, B]]. - .map(_.run(r)) // Type is M[B]. + .map(f) // Type is M[ReaderT[M, R, B]]. + .flatMap(_.run(r)) // Type is M[B]. } } def pure[M[_]: Monad, A](a: A): ReaderT[M, A] = ReaderT(_ => Monad[M].pure(a)) @@ -1829,11 +1829,11 @@ \subsection{Constructing lifts via operation typeclasses (\textquotedblleft MTL- To use the MTL-style monad stacks in practice, one needs a library (such as \texttt{cats-mtl}\footnote{See \texttt{\href{https://typelevel.org/blog/2018/10/06/intro-to-mtl.html}{https://typelevel.org/blog/2018/10/06/intro-to-mtl.html}}}) -that defines typeclasses with sufficiently many operations for each -supported monad, so that any desired monadic program may be expressed -through those operations without using explicit monad types. The library -should also implement instances of those typeclasses for all supported -monad stacks. +that defines typeclasses for monad operations. The library must support +sufficiently many operations and monads, so that any desired monadic +program may be expressed via those operations without using explicit +monad types. The library must also implement instances of those typeclasses +for all supported monad stacks. While the MTL style does provide automatic liftings, some problems remain. @@ -1842,11 +1842,21 @@ \subsection{Constructing lifts via operation typeclasses (\textquotedblleft MTL- of effectful operations. We have seen that the operations \lstinline!get! and \lstinline!set! are sufficient to express any \lstinline!State!-monadic programs. However, it may not be adequate to write code just with -those two operations. As an example, look at \emph{updating} +those two operations. As an example, look at \emph{updating} the state +using a given function of type $S\rightarrow S$. In many cases, updating +is the same as \lstinline!get!ting the current state value and immediately +\lstinline!set!ting a new value. However, certain kinds of updates +need special handling. Examples are: atomic updates in a concurrent +program; updates wrapped in a database transaction; and updates that +must be run on a designated CPU thread (e.g., the thread that drives +the GUI events). Such special handling of updates cannot be implemented +via monadic programs with just \lstinline!get! and \lstinline!set!. +A new effectful operation (\lstinline!update!) must be provided to +the programmer. -\begin{wraptable}{l}{0.6\columnwidth}% +\begin{table} \begin{centering} -\begin{tabular}{|>{\centering}m{1.3cm}|>{\centering}m{7cm}|} +\begin{tabular}{|>{\centering}m{1.6cm}|>{\centering}m{8.5cm}|} \hline \textbf{\small{}Monad} & \textbf{\small{}Operations}\tabularnewline \hline @@ -1876,32 +1886,23 @@ \subsection{Constructing lifts via operation typeclasses (\textquotedblleft MTL- \end{tabular} \par\end{centering} \caption{Known operations for some monads.\label{tab:effectful-operations-for-some-monads}} -\end{wraptable}% - -\noindent the state using a given function of type $S\rightarrow S$. -In many cases, updating is the same as \lstinline!get!ting the current -state value and immediately \lstinline!set!ting a new value. However, -certain kinds of updates need special handling. Examples are: atomic -updates in a concurrent program; updates wrapped in a database transaction; -and updates that must be run on a designated CPU thread (e.g., the -thread that drives the GUI events). Such special handling of updates -cannot be implemented via monadic programs with just \lstinline!get! -and \lstinline!set!. A new effectful operation (\lstinline!update!) -must be provided to the programmer. + +\end{table} Table~\ref{tab:effectful-operations-for-some-monads} shows a number -of operations for some monads.\footnote{Operations were gathered from the \texttt{cats-mtl} documentation -and the papers \textsf{``}\emph{Monad transformers and modular interpreters}\textsf{''} -(see \texttt{\href{http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html}{http://web.cecs.pdx.edu/$\sim$mpj/pubs/modinterp.html}}) -and \textsf{``}\emph{Modular monad transformers}\textsf{''} (see \texttt{\href{https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.219.5365}{https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.219.5365}}).} The choice of operations is heuristic and does not follow any principle +of operations for some monads. Operations were gathered from the \texttt{cats-mtl} +documentation as well as the papers \textsf{``}\emph{Monad transformers and +modular interpreters}\textsf{''} \footnote{\texttt{\href{http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html}{http://web.cecs.pdx.edu/$\sim$mpj/pubs/modinterp.html}}} +and \textsf{``}\emph{Modular monad transformers}\textsf{''} \footnote{\texttt{\href{https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.219.5365}{https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.219.5365}}}. +The choice of operations is heuristic and does not follow any principle or system. It is not easy to decide what operations will be necessary in practical tasks involving a given monad. (Do we need a \lstinline!filter! operation for the \lstinline!Either! monad? How can we decide?) Different libraries choose different sets of supported operations. -However, adding a new operation to a monad in an MTL-style library -means updating all typeclasses related to that monad. Users who cannot -modify the library code will be unable to add new operations. +Adding a new operation to a monad in an MTL-style library means updating +all typeclasses related to that monad. Users who cannot modify the +library code will be unable to add new operations. The second problem is the lack of a general method for lifting effectful operations to arbitrary monad transformers.\footnote{Section~\ref{subsec:Monatron} shows a technique that can lift effectful @@ -2582,7 +2583,7 @@ \subsection{Simplifying the laws of lifts and runners via category theory\label{ It is remarkable that all the laws of monad transformers can be derived from a single (but more abstract) definition: a monad transformer -$T$ is \emph{just a pointed and optionally co-pointed endofunctor +$T$ is \emph{just a pointed and (perhaps) co-pointed endofunctor in the category of monads}.\footnote{\textsf{``}\emph{What\textsf{'}s the big deal?}\textsf{''} as one\label{fn:Whats-the-big-deal-monad-transformers} would joke\index{jokes} similarly to the well-known monad joke in footnote~\ref{fn:A-monad-is-a-monoid-in-category-of-endofunctors-big-deal} diff --git a/sofp-src/sofp-traversable.lyx b/sofp-src/sofp-traversable.lyx index 75c9a576f..79d5baa0a 100644 --- a/sofp-src/sofp-traversable.lyx +++ b/sofp-src/sofp-traversable.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -528,7 +528,7 @@ Seq[A] \end_inset - can be written as: + may be written as: \begin_inset listings inline false status open @@ -547,9 +547,10 @@ def foldLeft[A, B](xs: Seq[A])(b0: B)(update: (B, A) => B): B \begin_inset Formula -\[ -\text{reduce}:\text{Seq}^{A}\rightarrow(A\times A\rightarrow A)\rightarrow A\quad,\quad\quad\text{foldLeft}:\text{Seq}^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad. -\] +\begin{align*} + & \text{reduce}:\text{Seq}^{A}\rightarrow(A\times A\rightarrow A)\rightarrow A\quad,\\ + & \text{foldLeft}:\text{Seq}^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad. +\end{align*} \end_inset @@ -2668,13 +2669,14 @@ def trav[A, B, F[_]: Applicative : Functor](f: A => F[B])(t: T2[A]): F[T2[B]] In the code notation, this function looks like this: \begin_inset Formula -\[ -\text{trav}\,(f^{:A\rightarrow F^{B}})\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{trav}\,(f^{:A\rightarrow F^{B}})\\ + & \triangleq\,\begin{array}{|c||c|} & F^{B+\text{T2}^{B}\times\text{T2}^{B}}\\ \hline A & f\bef(b^{:B}\rightarrow b+\bbnum 0^{:\text{T2}^{B}\times\text{T2}^{B}})^{\uparrow F}\\ \text{T2}^{A}\times\text{T2}^{A} & \big(\overline{\text{trav}}\,(f)\boxtimes\overline{\text{trav}}\,(f)\big)\bef\text{zip}_{F}\bef(l^{:\text{T2}^{B}}\times r^{:\text{T2}^{B}}\rightarrow\bbnum 0^{:B}+l\times r)^{\uparrow F} \end{array}\quad. -\] +\end{align*} \end_inset @@ -2802,7 +2804,7 @@ def trav[A, B, F[_]: Applicative : Functor](f: A => F[B])(t: PTree[A]): \begin_layout Plain Layout - case Branch(t) => ??? // Here t has type PTree[(A, A)]. + case Branch(p) => ??? // Here p has type PTree[(A, A)]. \end_layout \begin_layout Plain Layout @@ -2819,7 +2821,7 @@ status open \begin_layout Plain Layout -t +p \end_layout \end_inset @@ -2905,7 +2907,7 @@ status open \begin_layout Plain Layout -t +p \end_layout \end_inset @@ -2995,7 +2997,7 @@ status open \begin_layout Plain Layout - case Branch(t) => trav { case (a1, a2) => f(a1) zip f(a2) }(t); ??? + case Branch(p) => trav { case (a1, a2) => f(a1) zip f(a2) }(p); ??? } // Have F[PTree[(B, B)]]. \end_layout @@ -3053,8 +3055,8 @@ def trav[A, B, F[_]: Applicative : Functor](f: A => F[B])(t: PTree[A]): \begin_layout Plain Layout - case Branch(t) => (trav[(A, A), (B, B), F] { case (a1, a2) => f(a1) - zip f(a2) }(t) + case Branch(p) => (trav[(A, A), (B, B), F] { case (a1, a2) => f(a1) + zip f(a2) }(p) \end_layout \begin_layout Plain Layout @@ -3602,6 +3604,30 @@ List[A] \end_inset +, given a +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Monoid +\end_layout + +\end_inset + + instance for +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +List[A] +\end_layout + +\end_inset + : \begin_inset listings inline false @@ -3609,8 +3635,7 @@ status open \begin_layout Plain Layout -def toList[A]: T2[A] => List[A] = foldMap[A, List[A]](List(_)) // Need a - Monoid instance for List[A]. +def toList[A]: T2[A] => List[A] = foldMap[A, List[A]](List(_)) \end_layout \end_inset @@ -3966,6 +3991,10 @@ status open \end_inset +\begin_inset Newline newline +\end_inset + + \end_layout \begin_layout Standard @@ -4291,8 +4320,8 @@ def listMerge[A](l: List[List[A]], r: List[List[A]]): List[List[A]] = (l, \begin_layout Plain Layout - case (Nil, r) => r // Keep the elements from the - longer list. + case (Nil, r) => r // Keep the elements from the longer + list. \end_layout \begin_layout Plain Layout @@ -5043,14 +5072,12 @@ final case class St[A](run: Int => (A, Int)) // A State monad with internal \begin_layout Plain Layout - // Assume that we have defined Applicative and - Functor instances for St. +// Assume that we have defined Applicative and Functor instances for St. \end_layout \begin_layout Plain Layout -def computeIndex[A]: A => St[(A, Int)] = ??? // Define the - +def computeIndex[A]: A => St[(A, Int)] = ??? // Define the \begin_inset Quotes eld \end_inset @@ -5074,8 +5101,7 @@ def zipWithIndexDF[A](tree: T2[A]): T2[(A, Int)] = { \begin_layout Plain Layout - afterTraverse.run(0)._1 // Run the State monad and - get the result value. + afterTraverse.run(0)._1 // Run the State monad and get the result value. \end_layout \begin_layout Plain Layout @@ -5507,25 +5533,25 @@ List( \begin_layout Plain Layout - List(), // No leaves at - level 0. + List(), // No leaves at level + 0. \end_layout \begin_layout Plain Layout - List( Left(8) ), // One leaf at - level 1. + List( Left(8) ), // One leaf at level + 1. \end_layout \begin_layout Plain Layout - List( Right(Right(4)) ), // One leaf at - level 2. + List( Right(Right(4)) ), // One leaf at level + 2. \end_layout \begin_layout Plain Layout - List( Right(Left(Left(3))), Right(Left(Right(5))) ), // Two leaves at + List( Right(Left(Left(3))), Right(Left(Right(5))) ), // Two leaves at level 3. \end_layout @@ -5685,20 +5711,17 @@ status open \begin_layout Plain Layout -val td2: TD[Int] = More(List(), More( // No leaves - at level 0. +val td2: TD[Int] = More(List(), More( // No leaves at level 0. \end_layout \begin_layout Plain Layout - List( Left(8) ), More( // The leaf - at level 1. + List( Left(8) ), More( // One leaf at level 1. \end_layout \begin_layout Plain Layout - List( Right(Right(4)) ), Last( // The leaf - at level 2. + List( Right(Right(4)) ), Last( // One leaf at level 2. \end_layout \begin_layout Plain Layout @@ -5830,8 +5853,7 @@ def t2ToTD[A]: T2[A] => TD[A] = { \begin_layout Plain Layout - case Leaf(a) => Last(List(a)) // A leaf at - level 0. + case Leaf(a) => Last(List(a)) // One leaf at level 0. \end_layout \begin_layout Plain Layout @@ -7519,8 +7541,7 @@ ee) \begin_layout Plain Layout - afterTraverse.run(0)._1 // Run the State monad and - get the result value. + afterTraverse.run(0)._1 // Run the State monad and get the result value. \end_layout \begin_layout Plain Layout @@ -8613,7 +8634,8 @@ Tree[ 8 [ [ 3 5 ] 4 ] ] \end_inset . - We may write the following code for converting trees to this format: + The following code converts trees into the \SpecialChar LaTeX + format: \begin_inset listings inline false status open @@ -12614,7 +12636,7 @@ evenOdd lines 0 placement l overhang 0in -width "74col%" +width "84col%" status open \begin_layout Plain Layout @@ -12655,10 +12677,10 @@ res0: T2[Int] = Branch(Leaf(3), Branch(Branch(Leaf(1), Leaf(0)), Leaf(2))) \begin_layout Standard \noindent -\begin_inset space ~ +\begin_inset VSpace 30baselineskip% \end_inset - + \begin_inset Preview \begin_layout Standard @@ -12682,6 +12704,10 @@ Tree[ 3 [ [ 1 0 ] 2 ] ] \end_inset +\begin_inset Newline newline +\end_inset + + \end_layout \begin_layout Standard @@ -12717,7 +12743,7 @@ noprefix "false" \end_inset - is called + is known as reasoning by \series bold co-induction \series default @@ -12958,6 +12984,10 @@ Tree[ 1 [ 2 [3 ... \end_inset with unbounded size: +\begin_inset VSpace 60baselineskip% +\end_inset + + \begin_inset listings inline false status open @@ -13212,7 +13242,7 @@ status open lines 0 placement l overhang 0in -width "65col%" +width "82col%" status open \begin_layout Plain Layout @@ -13664,8 +13694,8 @@ final case class St[A](run: Int => (A, Int)) { // A State monad with internal \begin_layout Plain Layout - import io.chymyst.ch.implement // Implement the monad methods - automatically. + import io.chymyst.ch.implement // Derive these methods automatical +ly from types. \end_layout \begin_layout Plain Layout @@ -13903,7 +13933,7 @@ noprefix "false" lines 0 placement l overhang 0in -width "70col%" +width "78col%" status open \begin_layout Plain Layout @@ -14965,7 +14995,8 @@ def toList[A]: L[A] => List[A] \begin_inset Formula \begin{align*} - & \text{foldLeft}_{L}:L^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad,\quad\quad\text{foldMap}_{L}:(A\rightarrow M)\rightarrow L^{A}\rightarrow M\quad,\\ + & \text{foldLeft}_{L}:L^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad,\\ + & \text{foldMap}_{L}:(A\rightarrow M)\rightarrow L^{A}\rightarrow M\quad,\\ & \text{reduceE}_{L}:L^{M}\rightarrow M\quad,\quad\quad\text{toList}_{L}:L^{A}\rightarrow\text{List}^{A}\quad. \end{align*} @@ -15605,7 +15636,7 @@ foldLeft \end_inset - satisfies the naturality law with respect to its type parameter + obeys the naturality law with respect to its type parameter \begin_inset Formula $A$ \end_inset @@ -15815,7 +15846,7 @@ reduceE \end_inset - follows from Statement + can be derived from Statement \begin_inset space ~ \end_inset @@ -15955,7 +15986,8 @@ fldl : \begin_inset Formula \begin{align*} - & \text{fldl}:(A\rightarrow B\rightarrow B)\rightarrow L^{A}\rightarrow B\rightarrow B\quad,\quad\quad\text{fldl}\,(u^{:A\rightarrow B\rightarrow B})(p^{:L^{A}})(z^{:B})\triangleq\text{foldLeft}\,(p)(z)(\tilde{u})\quad,\\ + & \text{fldl}:(A\rightarrow B\rightarrow B)\rightarrow L^{A}\rightarrow B\rightarrow B\quad,\\ + & \text{fldl}\,(u^{:A\rightarrow B\rightarrow B})(p^{:L^{A}})(z^{:B})\triangleq\text{foldLeft}\,(p)(z)(\tilde{u})\quad,\\ & \text{where we defined}:\quad\tilde{u}^{:B\times A\rightarrow B}\triangleq b^{:B}\times a^{:A}\rightarrow u\left(a\right)(b)\quad. \end{align*} @@ -16234,10 +16266,6 @@ In particular, for any value \end_inset - -\end_layout - -\begin_layout Standard The function \begin_inset listings inline true @@ -16250,7 +16278,7 @@ inMF \end_inset - is a monoid morphism because the two laws of Definition + is a monoid morphism since the two laws of Definition \begin_inset space ~ \end_inset @@ -16757,9 +16785,11 @@ reduceE : \begin_inset Formula \begin{align*} -\text{expect to equal }\text{reduceE}\left(p\right):\quad & \text{reduceE}^{\prime}(p^{:L^{M}})=\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})=\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ +\text{expect to equal }\text{reduceE}\left(p\right):\quad & \text{reduceE}^{\prime}(p^{:L^{M}})=\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ + & =\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ \text{rewrite using }\triangleright\text{-notation}:\quad & =e_{M}\triangleright\big(p\triangleright\gunderline{\text{inMF}^{\uparrow L}\bef\text{reduceE}}\big)\\ -\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:\quad & =e_{M}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)=\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{M})}\\ +\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:\quad & =e_{M}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)\\ + & =\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{M})}\\ \text{use Eq.~(\ref{eq:identity-law-of-inMF})}:\quad & =p\triangleright\text{reduceE}=\text{reduceE}\,(p)\quad. \end{align*} @@ -16841,9 +16871,11 @@ noprefix "false" ) holds: \begin_inset Formula \begin{align*} -\text{expect to equal }\text{foldFn}^{B}(p):\quad & \text{foldFn}^{B\rightarrow B}(p^{:L^{B\rightarrow B}}\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})=\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ +\text{expect to equal }\text{foldFn}^{B}(p):\quad & \text{foldFn}^{B\rightarrow B}(p^{:L^{B\rightarrow B}}\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ + & =\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ & =e_{\text{MF}}\triangleright(p\triangleright\gunderline{\text{inMF}^{\uparrow L}\bef\text{reduceE}})\\ -\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:\quad & =e_{\text{MF}}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)=\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{\text{MF}})}\\ +\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:\quad & =e_{\text{MF}}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)\\ + & =\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{\text{MF}})}\\ \text{use Eq.~(\ref{eq:identity-law-of-inMF})}:\quad & =p\triangleright\text{reduceE}=\text{reduceE}^{B\rightarrow B}(p)=\text{foldFn}^{B}(p)\quad. \end{align*} @@ -17120,7 +17152,7 @@ noprefix "false" \begin_inset Formula \begin{align} & \phi\,(p^{:L^{E^{A}}})=\phi\,(p\triangleright\text{inF}^{\uparrow L})(\text{id}^{:A\rightarrow A})\quad,\label{eq:first-special-law-of-phi}\\ -\text{where we defined}:\quad & \quad\text{inF}:E^{A}\rightarrow E^{A}\rightarrow E^{A}\quad,\quad\quad\text{inF}\triangleq h^{:A\rightarrow A}\rightarrow k^{:A\rightarrow A}\rightarrow k\bef h\quad.\nonumber +\text{where we defined}:\quad & \quad\text{inF}:E^{A}\rightarrow E^{A}\rightarrow E^{A}\quad,\quad\text{inF}\triangleq h^{:A\rightarrow A}\rightarrow k^{:A\rightarrow A}\rightarrow k\bef h\quad.\nonumber \end{align} \end_inset @@ -17715,8 +17747,10 @@ We simplify separately each side of this equation and find that they are equal: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & h^{:A\rightarrow A}\rightarrow f\bef h=h\rightarrow(k\rightarrow\gunderline{k(a_{0}))\bef h}=h\rightarrow k\rightarrow h(k(a_{0}))\quad,\\ -\text{right-hand side}:\quad & \gunderline{\text{inF}}\bef(g^{:B\rightarrow B}\rightarrow g\bef\gunderline f)=(h\rightarrow k\rightarrow k\bef h)\bef(g\rightarrow g\bef(k\rightarrow k(a_{0}))\\ +\text{left-hand side}:\quad & h^{:A\rightarrow A}\rightarrow f\bef h=h\rightarrow(k\rightarrow\gunderline{k(a_{0}))\bef h}\\ + & \quad=h\rightarrow k\rightarrow h(k(a_{0}))\quad,\\ +\text{right-hand side}:\quad & \gunderline{\text{inF}}\bef(g^{:B\rightarrow B}\rightarrow g\bef\gunderline f)\\ + & \quad=(h\rightarrow k\rightarrow k\bef h)\bef(g\rightarrow g\bef(k\rightarrow k(a_{0}))\\ \text{compute composition}:\quad & \quad=h\rightarrow(k\rightarrow k\bef h)\bef(k\rightarrow k(a_{0}))=h\rightarrow k\rightarrow\gunderline{(k\bef h)(a_{0})}\\ & \quad=h\rightarrow k\rightarrow h(k(a_{0})\quad. \end{align*} @@ -17919,7 +17953,7 @@ A\triangleq N\quad,\quad\quad B\triangleq M\quad,\quad\quad x^{:L^{N\rightarrow \end_inset -Before we can use Eq. +In order to use Eq. \begin_inset space ~ \end_inset @@ -17935,9 +17969,10 @@ noprefix "false" ), we need to verify that its precondition is satisfied: \begin_inset Formula -\[ -x\triangleright(h\rightarrow f\bef h)^{\uparrow L}=p\triangleright\big(f\bef\text{inMF}\bef(h\rightarrow f\bef h)\big)^{\uparrow L}\overset{?}{=}y\triangleright(g\rightarrow g\bef f)^{\uparrow L}=p\triangleright\big(\text{inMF}\bef(g\rightarrow g\bef f)\big)^{\uparrow L}\quad. -\] +\begin{align*} + & x\triangleright(h\rightarrow f\bef h)^{\uparrow L}=p\triangleright\big(f\bef\text{inMF}\bef(h\rightarrow f\bef h)\big)^{\uparrow L}\\ + & \quad\overset{?}{=}y\triangleright(g\rightarrow g\bef f)^{\uparrow L}=p\triangleright\big(\text{inMF}\bef(g\rightarrow g\bef f)\big)^{\uparrow L}\quad. +\end{align*} \end_inset @@ -17949,8 +17984,10 @@ To show that this equation holds, we compare separately the lifted functions : \begin_inset Formula \begin{align*} - & f\bef\text{inMF}\bef(h\rightarrow f\bef h)=\big(m^{:M}\rightarrow n^{:N}\rightarrow n\oplus_{N}f(m)\big)\bef(h\rightarrow f\bef h)=m^{:M}\rightarrow l^{:M}\rightarrow f(l)\oplus_{N}f(m)\quad,\\ - & \text{inMF}\bef(g\rightarrow g\bef f)=(m^{:M}\rightarrow l^{:M}\rightarrow l\oplus_{M}m)\bef(g\rightarrow g\bef f)=m^{:M}\rightarrow l^{:M}\rightarrow f(l\oplus_{M}m)\quad. + & f\bef\text{inMF}\bef(h\rightarrow f\bef h)=\big(m^{:M}\rightarrow n^{:N}\rightarrow n\oplus_{N}f(m)\big)\bef(h\rightarrow f\bef h)\\ + & \quad=m^{:M}\rightarrow l^{:M}\rightarrow f(l)\oplus_{N}f(m)\quad,\\ + & \text{inMF}\bef(g\rightarrow g\bef f)=(m^{:M}\rightarrow l^{:M}\rightarrow l\oplus_{M}m)\bef(g\rightarrow g\bef f)\\ + & \quad=m^{:M}\rightarrow l^{:M}\rightarrow f(l\oplus_{M}m)\quad. \end{align*} \end_inset @@ -17977,9 +18014,10 @@ noprefix "false" ) holds, and we may use its conclusion: \begin_inset Formula -\[ -f\bef\text{foldFn}\,(x)\overset{!}{=}\text{foldFn}(y)\bef f\quad\text{or equivalently:}\quad\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})\bef f=f\bef\text{foldFn}(p\triangleright f^{\uparrow L}\bef\text{inMF}^{\uparrow L}). -\] +\begin{align*} + & f\bef\text{foldFn}\,(x)\overset{!}{=}\text{foldFn}(y)\bef f\\ +\text{or equivalently}:\quad & \text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})\bef f=f\bef\text{foldFn}(p\triangleright f^{\uparrow L}\bef\text{inMF}^{\uparrow L}). +\end{align*} \end_inset @@ -18176,13 +18214,14 @@ def reduceList[M: Monoid]: List[M] => M = { \begin_inset Formula -\[ -\text{reduceList}^{M}:\text{List}^{M}\rightarrow M\quad,\quad\quad\text{reduceList}\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{reduceList}^{M}:\text{List}^{M}\rightarrow M\quad,\\ + & \text{reduceList}\triangleq\,\begin{array}{|c||c|} & M\\ \hline \bbnum 1 & \_\rightarrow e_{M}\\ M\times\text{List}^{M} & h^{:M}\times t^{:\text{List}^{M}}\rightarrow h\oplus_{M}\overline{\text{reduceList}}\left(t\right) \end{array}\quad. -\] +\end{align*} \end_inset @@ -18218,7 +18257,7 @@ This law assumes that \begin_inset Formula $f^{:M\rightarrow N}$ \end_inset - is a monoid morphism between two monoids + is a monoid morphism between monoids \begin_inset Formula $M$ \end_inset @@ -18234,7 +18273,8 @@ This law assumes that Simplify the left-hand side of the law: \begin_inset Formula \begin{align*} - & f^{\uparrow\text{List}}\bef\text{reduceList}=\,\begin{array}{|c||cc|} + & f^{\uparrow\text{List}}\bef\text{reduceList}\\ + & =\,\begin{array}{|c||cc|} & \bbnum 1 & N\times\text{List}^{N}\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ M\times\text{List}^{M} & \bbnum 0 & f\boxtimes f^{\uparrow\text{List}} @@ -18243,7 +18283,7 @@ M\times\text{List}^{M} & \bbnum 0 & f\boxtimes f^{\uparrow\text{List}} \hline \bbnum 1 & \_\rightarrow e_{N}\\ N\times\text{List}^{N} & h\times t\rightarrow h\oplus_{N}(t\triangleright\overline{\text{reduceList}}) \end{array}\\ - & =\,\begin{array}{|c||c|} + & =\,\,\begin{array}{|c||c|} & N\\ \hline \bbnum 1 & \_\rightarrow e_{N}\\ M\times\text{List}^{M} & h\times t\rightarrow f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}}) @@ -18276,7 +18316,8 @@ t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}}=t\triang The bottom-row expression in the last matrix is then rewritten to: \begin_inset Formula \begin{align*} - & f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}})=f(h)\oplus_{N}f(\overline{\text{reduceList}}\left(t\right))\\ + & f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}})\\ + & =f(h)\oplus_{N}f(\overline{\text{reduceList}}\left(t\right))\\ \text{monad morphism law}:\quad & =f\big(h\oplus_{M}\overline{\text{reduceList}}\left(t\right)\big)\quad. \end{align*} @@ -18453,7 +18494,8 @@ reduceE , we write: \begin_inset Formula \begin{align*} - & \text{reduceE}^{\prime}=\text{toList}\bef\text{reduceList}=\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{M}}}\bef\text{reduceList}\\ + & \text{reduceE}^{\prime}=\text{toList}\bef\text{reduceList}\\ + & =\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{M}}}\bef\text{reduceList}\\ \text{Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE}) with }N\triangleq\text{List}^{A}:\quad & =\text{reduceE}^{M}\bef\text{pu}_{\text{List}}\bef\text{reduceList}\quad. \end{align*} @@ -18627,7 +18669,8 @@ toList , we write: \begin_inset Formula \begin{align*} - & \text{toList}^{\prime}=\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{A}}=\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{toList}}\bef\text{reduceList}^{\text{List}^{A}}\\ + & \text{toList}^{\prime}=\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{A}}\\ + & =\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{toList}}\bef\text{reduceList}^{\text{List}^{A}}\\ \text{naturality of }\text{toList}:\quad & =\text{toList}\bef\text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}\quad. \end{align*} @@ -18684,12 +18727,12 @@ List[A] : \begin_inset Formula \begin{align*} - & \text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}\\ - & =\,\begin{array}{|c||cc|} + & \text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}=\,\begin{array}{|c||cc|} & \bbnum 1 & \text{List}^{M}\times\text{List}^{\text{List}^{M}}\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ M\times\text{List}^{M} & \bbnum 0 & h\times t\rightarrow\text{pu}_{\text{List}}(h)\times(t\triangleright\text{pu}_{\text{List}}^{\uparrow\text{List}}) -\end{array}\,\bef\,\begin{array}{|c||c|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||c|} & \text{List}^{M}\\ \hline \bbnum 1 & \_\rightarrow1+\bbnum 0\\ \text{List}^{M}\times\text{List}^{\text{List}^{M}} & h\times t\rightarrow h\pplus\overline{\text{reduceList}}\left(t\right) @@ -18715,7 +18758,7 @@ reduceList \end_inset - already satisfies Eq. + already obeys Eq. \begin_inset space ~ \end_inset @@ -19135,7 +19178,7 @@ toList(x) \end_inset - always ignores its argument + always ignores \begin_inset listings inline true status open @@ -20191,21 +20234,6 @@ If \end_inset as: -\end_layout - -\begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "60col%" -status open - -\begin_layout Plain Layout -\begin_inset VSpace -25baselineskip% -\end_inset - - \begin_inset listings inline false status open @@ -20233,30 +20261,6 @@ def toList_M[A]: Either[K[A], L[A]] => List[A] = { \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset VSpace -100baselineskip% -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\noindent -\begin_inset space ~ -\end_inset - - -\begin_inset VSpace -200baselineskip% -\end_inset - - \begin_inset Formula \[ \text{toList}_{M}\triangleq\,\begin{array}{|c||c|} @@ -20269,10 +20273,6 @@ L^{A} & \text{toList}_{L} \end_inset -\begin_inset VSpace -60baselineskip% -\end_inset - - \end_layout \begin_layout Paragraph @@ -20533,7 +20533,7 @@ sequence \end_layout \begin_layout Standard -The standard Scala library contains the method +The Scala library contains the methods \begin_inset listings inline true status open @@ -20545,7 +20545,7 @@ Future.sequence \end_inset - in addition to + and \begin_inset listings inline true status open @@ -21486,7 +21486,7 @@ traverse \end_inset , we write an equation similar to the second naturality law, except that - the arbitrary function + the function \begin_inset Formula $f$ \end_inset @@ -21503,6 +21503,11 @@ arbitrary \end_inset : +\end_layout + +\begin_layout Standard +\noindent +\align center \begin_inset Formula $\xymatrix{\xyScaleY{1.7pc}\xyScaleX{5.0pc}L^{A}\ar[rd]\sb(0.4){\text{trav}_{L}^{G,A,B}(g\bef f)~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(g)} & F^{L^{B}}\ar[d]\sp(0.45){f}\\ & G^{L^{B}} } @@ -21517,6 +21522,11 @@ $ \end_inset + +\end_layout + +\begin_layout Standard +\align left Here \begin_inset Formula $f$ \end_inset @@ -21690,8 +21700,8 @@ composition law!of applicative morphisms \begin_inset Formula \begin{align} -\text{identity law of applicative morphism }f:\quad & f^{:F^{\bbnum 1}\rightarrow G^{\bbnum 1}}(\text{wu}_{F})=\text{wu}_{G}\quad,\label{eq:identity-law-of-applicative-morphism}\\ -\text{composition law of applicative morphism }f:\quad & \text{zip}_{G}\big(f(p^{:F^{A}})\times f(q^{:F^{B}})\big)=f(\text{zip}_{F}(p\times q))\quad.\label{eq:composition-law-of-applicative-morphism} +\text{identity law }:\quad & f^{:F^{\bbnum 1}\rightarrow G^{\bbnum 1}}(\text{wu}_{F})=\text{wu}_{G}\quad,\label{eq:identity-law-of-applicative-morphism}\\ +\text{composition law}:\quad & \text{zip}_{G}\big(f(p^{:F^{A}})\times f(q^{:F^{B}})\big)=f(\text{zip}_{F}(p\times q))\quad.\label{eq:composition-law-of-applicative-morphism} \end{align} \end_inset @@ -21943,21 +21953,22 @@ zip are: \begin_inset Formula -\[ -\text{zip}_{G}\triangleq\,\begin{array}{|c||cc|} +\begin{align*} + & \text{zip}_{G}\triangleq\,\begin{array}{|c||cc|} & \bbnum 1 & A\times B\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ A\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ \bbnum 1\times B & \_\rightarrow1 & \bbnum 0\\ A\times B & \bbnum 0 & \text{id} -\end{array}\quad,\quad\quad\text{zip}_{H}\triangleq\,\begin{array}{|c||cc|} +\end{array}\quad,\\ + & \text{zip}_{H}\triangleq\,\,\begin{array}{|c||cc|} & \bbnum 1 & (A\times B)\times(A\times B)\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ (A\times A)\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ \bbnum 1\times(B\times B) & \_\rightarrow1 & \bbnum 0\\ (A\times A)\times(B\times B) & \bbnum 0 & \text{zip}_{L} \end{array}\quad. -\] +\end{align*} \end_inset @@ -22098,8 +22109,8 @@ The pair product ( ) can be written in matrix form like this: \begin_inset Formula -\[ -g\boxtimes g=\,\begin{array}{|c||cc|} +\begin{align*} +g\boxtimes g & =\,\begin{array}{|c||cc|} & \bbnum 1 & A\times A\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ A & \bbnum 0 & \Delta @@ -22107,14 +22118,15 @@ A & \bbnum 0 & \Delta & \bbnum 1 & B\times B\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ B & \bbnum 0 & \Delta -\end{array}\,=\,\begin{array}{|c||cccc|} +\end{array}\\ + & =\,\,\begin{array}{|c||cccc|} & \bbnum 1 & A\times A\times\bbnum 1 & \bbnum 1\times B\times B & A\times A\times B\times B\\ \hline \bbnum 1\times\bbnum 1 & \text{id} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ A\times\bbnum 1 & \bbnum 0 & \Delta\boxtimes\text{id} & \bbnum 0 & \bbnum 0\\ \bbnum 1\times B & \bbnum 0 & \bbnum 0 & \text{id}\boxtimes\Delta & \bbnum 0\\ A\times B & \bbnum 0 & \bbnum 0 & \bbnum 0 & \Delta\boxtimes\Delta \end{array}\quad. -\] +\end{align*} \end_inset @@ -22135,7 +22147,7 @@ noprefix "false" ) are then simplified to: \begin_inset Formula \begin{align*} - & (g\boxtimes g)\bef\text{zip}_{H}=\,\begin{array}{||cccc|} +(g\boxtimes g)\bef\text{zip}_{H} & =\,\begin{array}{||cccc|} \text{id} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ \bbnum 0 & \Delta\boxtimes\text{id} & \bbnum 0 & \bbnum 0\\ \bbnum 0 & \bbnum 0 & \text{id}\boxtimes\Delta & \bbnum 0\\ @@ -22145,13 +22157,14 @@ noprefix "false" \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \bbnum 0 & \text{zip}_{L} -\end{array}\,=\,\begin{array}{||cc|} +\end{array}\\ + & =\,\,\begin{array}{||cc|} \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \bbnum 0 & (\Delta\boxtimes\Delta)\bef\text{zip}_{L} \end{array}\quad,\\ - & \text{zip}_{G}\bef g=\,\begin{array}{|c||cc|} +\text{zip}_{G}\bef g & =\,\begin{array}{|c||cc|} & \bbnum 1 & A\times B\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ A\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ @@ -22161,7 +22174,8 @@ A\times B & \bbnum 0 & \text{id} & \bbnum 1 & (A\times B)\times(A\times B)\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ A\times B & \bbnum 0 & \Delta -\end{array}\,=\,\begin{array}{||cc|} +\end{array}\\ + & =\,\,\begin{array}{||cc|} \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ @@ -22438,7 +22452,8 @@ noprefix "false" To verify the composition law: \begin_inset Formula \begin{align*} - & \text{zip}_{F}\big(\text{pu}_{F}(p^{:A})\times\text{pu}_{F}(q^{:B})\big)\overset{?}{=}\text{pu}_{F}(\text{zip}_{\text{Id}}(p\times q))=\text{pu}_{F}(p\times q)\\ + & \text{zip}_{F}\big(\text{pu}_{F}(p^{:A})\times\text{pu}_{F}(q^{:B})\big)\overset{?}{=}\text{pu}_{F}(\text{zip}_{\text{Id}}(p\times q))\\ + & =\text{pu}_{F}(p\times q)\\ \text{use Exercise~\ref{subsec:Exercise-zip-pure-pure}}:\quad & =\text{zip}_{F}(\text{pu}_{F}(p)\times\text{pu}_{F}(q))\quad. \end{align*} @@ -23342,6 +23357,18 @@ traverse \end_inset operation using that functor and obtain: +\end_layout + +\begin_layout Standard +\noindent +\align center +\begin_inset Formula $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{3.4pc}L^{A}\ar[dr]\sb(0.35){\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(f)} & F^{L^{B}}\ar[d]\sp(0.4){\big(\text{trav}_{L}^{G,B,C}(g)\big)^{\uparrow F}}\\ + & F^{G^{L^{C}}} +} +$ +\end_inset + + \begin_inset Formula \[ p\triangleright\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F}):F^{G^{L^{C}}}\quad. @@ -23350,12 +23377,10 @@ p\triangleright\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F}):F^{G^{L^{C}} \end_inset -\begin_inset Formula $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{3.4pc}L^{A}\ar[dr]\sb(0.35){\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(f)} & F^{L^{B}}\ar[d]\sp(0.4){\big(\text{trav}_{L}^{G,B,C}(g)\big)^{\uparrow F}}\\ - & F^{G^{L^{C}}} -} -$ -\end_inset +\end_layout +\begin_layout Standard +\noindent The \series bold composition law @@ -23626,7 +23651,7 @@ Int \end_inset that add their arguments to the internal state. - The complete code (using the + The complete law-violating code (using the \begin_inset listings inline true status open @@ -23652,31 +23677,10 @@ noprefix "false" \end_inset -) is shown in Fig. -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "fig:Full-code-implementing-traverse-law-counterexample" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -. +) is shown below: \end_layout \begin_layout Standard -\begin_inset Float figure -wide false -sideways false -status collapsed - -\begin_layout Plain Layout -\align center \begin_inset listings lstparams "frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm" inline false @@ -23809,8 +23813,7 @@ implicit val ZippableS: Zippable[S] = new Zippable[S] { \begin_layout Plain Layout - // Define F[A] as the composition S[S[A]] and implement WuZip and Functor - instances. + // Define F[A] as S[S[A]] and implement WuZip and Functor instances. \end_layout \begin_layout Plain Layout @@ -23994,46 +23997,10 @@ res1: ((Int, Int), Int, Int) = ((4, 6), 2, 6) \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset Caption Standard - -\begin_layout Plain Layout -A counterexample violating the composition law of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -traverse -\end_layout - -\end_inset - -. -\begin_inset CommandInset label -LatexCommand label -name "fig:Full-code-implementing-traverse-law-counterexample" - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - \end_layout \begin_layout Standard -We have shown that +We have found that \emph on some \emph default @@ -24049,9 +24016,8 @@ traverse \end_inset - are excluded by the composition law. - But it remains unknown whether the mentioned laws guarantee that any lawful - + are prohibited by its laws. + But this is not a proof that all lawful \begin_inset listings inline true status open @@ -24063,38 +24029,26 @@ traverse \end_inset - function collects each + functions will collect each \begin_inset Formula $F$ \end_inset -effect exactly once. - Perhaps another law of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -traverse -\end_layout - -\end_inset - - is required (see Problem + We will revisit this question below in Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "par:Problem-traverse-law" +reference "subsec:Laws-of-traverse-and-zipWithIndex" plural "false" caps "false" noprefix "false" \end_inset -).***Mention the paper about the rewinding law. +. \end_layout \begin_layout Subsection @@ -24178,6 +24132,7 @@ sequence \end_layout \begin_layout Standard +\align center \begin_inset Formula $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{2.0pc}L^{F^{A}}\ar[d]\sb(0.45){\text{seq}_{L}^{F,A}}\ar[r]\sb(0.5){f^{\uparrow F\uparrow L}} & L^{F^{B}}\ar[d]\sp(0.45){\text{seq}_{L}^{F,B}}\\ F^{L^{A}}\ar[r]\sp(0.5){f^{\uparrow L\uparrow F}} & F^{L^{B}} } @@ -24192,6 +24147,10 @@ $ \end_inset + +\end_layout + +\begin_layout Standard It will be shown in Exercise \begin_inset space ~ \end_inset @@ -24327,16 +24286,7 @@ noprefix "false" \end_inset for a similar property). -\end_layout - -\begin_layout Standard -\begin_inset Formula $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{2.0pc}L^{F^{A}}\ar[d]\sb(0.45){\text{seq}_{L}^{F,A}}\ar[r]\sb(0.5){(f^{A})^{\uparrow L}} & L^{G^{A}}\ar[d]\sp(0.45){\text{seq}_{L}^{G,A}}\\ -F^{L^{A}}\ar[r]\sp(0.5){f^{L^{A}}} & G^{L^{A}} -} -$ -\end_inset - -Renaming + Renaming \begin_inset Formula $B$ \end_inset @@ -24344,7 +24294,7 @@ Renaming \begin_inset Formula $A$ \end_inset -, we rewrite the applicative naturality law +, we write the applicative naturality law \begin_inset Index idx status open @@ -24368,7 +24318,18 @@ sequence \end_inset - as: +: +\end_layout + +\begin_layout Standard +\align center +\begin_inset Formula $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{2.0pc}L^{F^{A}}\ar[d]\sb(0.45){\text{seq}_{L}^{F,A}}\ar[r]\sb(0.5){(f^{A})^{\uparrow L}} & L^{G^{A}}\ar[d]\sp(0.45){\text{seq}_{L}^{G,A}}\\ +F^{L^{A}}\ar[r]\sp(0.5){f^{L^{A}}} & G^{L^{A}} +} +$ +\end_inset + + \begin_inset Formula \[ (f^{A})^{\uparrow L}\bef\text{seq}_{L}^{G,A}=\text{seq}_{L}^{F,A}\bef f^{L^{A}}\quad. @@ -24532,7 +24493,8 @@ sequence : \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{trav}_{L}^{F,A,B}(f^{:A\rightarrow F^{B}})\bef\big(\text{trav}_{L}^{G,B,C}(g^{:B\rightarrow G^{C}})\big)^{\uparrow F}=f^{\uparrow L}\bef\text{seq}_{L}^{F,B}\bef\big(g^{\uparrow L}\bef\text{seq}_{L}^{G,C}\big)^{\uparrow F}\\ +\text{left-hand side}:\quad & \text{trav}_{L}^{F,A,B}(f^{:A\rightarrow F^{B}})\bef\big(\text{trav}_{L}^{G,B,C}(g^{:B\rightarrow G^{C}})\big)^{\uparrow F}\\ + & \quad=f^{\uparrow L}\bef\text{seq}_{L}^{F,B}\bef\big(g^{\uparrow L}\bef\text{seq}_{L}^{G,C}\big)^{\uparrow F}\\ & \quad=f^{\uparrow L}\bef\gunderline{\text{seq}_{L}^{F,B}\bef g^{\uparrow L\uparrow F}}\bef(\text{seq}_{L}^{G,C})^{\uparrow F}\\ \text{naturality law~(\ref{eq:sequence-naturality-law})}:\quad & \quad=f^{\uparrow L}\bef g^{\uparrow F\uparrow L}\bef\text{seq}_{L}^{F,G^{C}}\bef(\text{seq}_{L}^{G,C})^{\uparrow F}\quad,\\ \text{right-hand side}:\quad & \text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})=(f\bef g^{\uparrow F})^{\uparrow L}\bef\text{seq}_{L}^{F\circ G,C}\quad. @@ -24541,12 +24503,20 @@ sequence \end_inset +\end_layout + +\begin_layout Standard +\align center \begin_inset Formula $\xymatrix{\xyScaleY{1.4pc}\xyScaleX{3.0pc}L^{F^{G^{A}}}\ar[r]\sp(0.55){\text{seq}_{L}^{F,G^{A}}}\ar[rd]\sb(0.4){\text{seq}_{L}^{F\circ G,A}} & F^{L^{G^{A}}}\ar[d]\sp(0.4){(\text{seq}_{L}^{G,A})^{\uparrow F}}\\ & F^{G^{L^{A}}} } $ \end_inset + +\end_layout + +\begin_layout Standard Omitting the common function \begin_inset Formula $(f\bef g^{\uparrow F})^{\uparrow L}$ \end_inset @@ -24880,9 +24850,10 @@ Here as: \begin_inset Formula -\[ -\text{seq}_{L}^{F,A}:M^{F^{A}}\times N^{F^{A}}\rightarrow F^{M^{A}\times N^{A}}\quad,\quad\quad\text{seq}_{L}^{F,A}\triangleq m^{:M^{F^{A}}}\times n^{:N^{F^{A}}}\rightarrow\text{zip}_{F}\big((m\triangleright\text{seq}_{M}^{F,A})\times(n\triangleright\text{seq}_{N}^{F,A})\big)\quad. -\] +\begin{align*} + & \text{seq}_{L}^{F,A}:M^{F^{A}}\times N^{F^{A}}\rightarrow F^{M^{A}\times N^{A}}\quad,\\ + & \text{seq}_{L}^{F,A}\triangleq m^{:M^{F^{A}}}\times n^{:N^{F^{A}}}\rightarrow\text{zip}_{F}\big((m\triangleright\text{seq}_{M}^{F,A})\times(n\triangleright\text{seq}_{N}^{F,A})\big)\quad. +\end{align*} \end_inset @@ -24946,9 +24917,11 @@ noprefix "false" ), begin with its left-hand side: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq}_{M}^{G,A}\boxtimes\text{seq}_{N}^{G,A})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ -\text{naturality law of }\text{zip}_{F}:\quad & =\gunderline{(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\big((\text{seq}_{M}^{G,A})^{\uparrow F}\boxtimes(\text{seq}_{N}^{G,A})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ -\text{composition law~(\ref{eq:pair-product-composition-law})}:\quad & =\big((\text{seq}_{M}^{F,G^{A}}\bef(\text{seq}_{M}^{G,A})^{\uparrow F})\boxtimes(\text{seq}_{N}^{F,G^{A}}\bef(\text{seq}_{N}^{G,A})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq}_{M}^{G,A}\boxtimes\text{seq}_{N}^{G,A})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad\text{naturality law of }\text{zip}_{F}:\quad\\ + & =\gunderline{(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\big((\text{seq}_{M}^{G,A})^{\uparrow F}\boxtimes(\text{seq}_{N}^{G,A})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad\text{composition law~(\ref{eq:pair-product-composition-law})}:\quad\\ + & =\big((\text{seq}_{M}^{F,G^{A}}\bef(\text{seq}_{M}^{G,A})^{\uparrow F})\boxtimes(\text{seq}_{N}^{F,G^{A}}\bef(\text{seq}_{N}^{G,A})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. \end{align*} \end_inset @@ -25075,7 +25048,7 @@ Here as: \begin_inset Formula \[ -\text{seq}_{L}:M^{F^{A}}+N^{F^{A}}\rightarrow F^{M^{A}+N^{A}}\quad,\quad\quad\text{seq}_{L}\triangleq\,\begin{array}{|c||c|} +\text{seq}_{L}:M^{F^{A}}+N^{F^{A}}\rightarrow F^{M^{A}+N^{A}}\quad,\quad\text{seq}_{L}\triangleq\,\begin{array}{|c||c|} & F^{M^{A}+N^{A}}\\ \hline M^{F^{A}} & \text{seq}_{M}^{F,A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow F}\\ N^{F^{A}} & \text{seq}_{N}^{F,A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow F} @@ -25089,7 +25062,7 @@ N^{F^{A}} & \text{seq}_{N}^{F,A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{ \begin_layout Standard \begin_inset Note Comment -status open +status collapsed \begin_layout Plain Layout *** do we need this? @@ -25156,7 +25129,8 @@ noprefix "false" \hline M^{\text{Id}^{A}} & \text{seq}_{M}^{\text{Id},A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow\text{Id}}\\ N^{\text{Id}^{A}} & \text{seq}_{N}^{\text{Id},A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow\text{Id}} \end{array}\\ -\text{identity laws of }\text{seq}_{M}\text{ and }\text{seq}_{N}:\quad & =\,\begin{array}{|c||c|} + & \quad\text{identity laws of }\text{seq}_{M}\text{ and }\text{seq}_{N}:\quad\\ + & =\,\begin{array}{|c||c|} & M^{A}+N^{A}\\ \hline M^{A} & m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}}\\ N^{A} & n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n @@ -25190,7 +25164,8 @@ noprefix "false" ), write its two sides separately: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\,\begin{array}{||c|} +\text{left-hand side}:\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ + & \quad=\,\begin{array}{||c|} \text{seq}_{M}^{F,G^{A}}\bef(m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})^{\uparrow F}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ \text{seq}_{N}^{F,G^{A}}\bef(n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)^{\uparrow F}\bef(\text{seq}_{L}^{G,A})^{\uparrow F} \end{array}\quad,\\ @@ -25236,7 +25211,8 @@ The Write them separately: \begin_inset Formula \begin{align*} - & (m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})\bef\text{seq}_{L}^{G,A}=\,\begin{array}{|c||cc|} + & (m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})\bef\text{seq}_{L}^{G,A}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A}} & N^{G^{A}}\\ \hline M^{G^{A}} & \text{id} & \bbnum 0 \end{array}\,\bef\,\begin{array}{|c||c|} @@ -25245,7 +25221,8 @@ The N^{G^{A}} & \text{seq}_{N}^{G,A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow G} \end{array}\\ & \quad=\text{seq}_{M}^{G,A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow G}\quad,\\ - & (n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)\bef\text{seq}_{L}^{G,A}=\,\begin{array}{|c||cc|} + & (n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)\bef\text{seq}_{L}^{G,A}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A}} & N^{G^{A}}\\ \hline N^{G^{A}} & \bbnum 0 & \text{id} \end{array}\,\bef\,\begin{array}{|c||c|} @@ -25560,7 +25537,8 @@ noprefix "false" ), write its two sides separately: \begin_inset Formula \begin{align*} - & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F,G^{A},L^{G^{A}}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow S^{G^{A},\bullet}\uparrow F}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\quad,\\ + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ + & \quad=\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F,G^{A},L^{G^{A}}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow S^{G^{A},\bullet}\uparrow F}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\quad,\\ & \text{seq}_{L}^{F\circ G,A}=\big(\overline{\text{seq}}_{L}^{F\circ G,A}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F\circ G,A,L^{A}}\quad. \end{align*} @@ -25601,8 +25579,10 @@ noprefix "false" \begin{align*} & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ & =\gunderline{\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow F\uparrow S^{F^{G^{A}},\bullet}}}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\\ -\text{composition law~(\ref{eq:composition-law-of-sequence})}:\quad & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}}\\ -\text{composition law~(\ref{eq:composition-law-of-bisequence})}:\quad & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F\circ G,A,L^{A}}}\quad. + & \quad\text{composition law~(\ref{eq:composition-law-of-sequence})}:\quad\\ + & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}}\\ + & \quad\text{composition law~(\ref{eq:composition-law-of-bisequence})}:\quad\\ + & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F\circ G,A,L^{A}}}\quad. \end{align*} \end_inset @@ -25923,8 +25903,8 @@ Bitraversable bifunctors are used in the recursive-type construction for The properties of bitraversable bifunctors are similar to the properties of traversable functors. We will now prove that all polynomial bifunctors are bitraversable. - The proof verifies that each of the five type constructions of polynomial - bifunctors will produce a bitraversable bifunctor satisfying the laws + This verifies that each of the five type constructions of polynomial bifunctors + produces a bitraversable bifunctor satisfying the laws \begin_inset space ~ \end_inset @@ -26116,9 +26096,10 @@ Here as: \begin_inset Formula -\[ -\text{seq2}_{S}^{F,A,B}:M^{F^{A},F^{B}}\times N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}\times N^{A,B}}\quad,\quad\quad\text{seq2}_{S}^{F,A,B}\triangleq(\text{seq2}_{M}^{F,A,B}\boxtimes\text{seq2}_{N}^{F,A,B})\bef\text{zip}_{F}\quad. -\] +\begin{align*} + & \text{seq2}_{S}^{F,A,B}:M^{F^{A},F^{B}}\times N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}\times N^{A,B}}\quad,\\ + & \text{seq2}_{S}^{F,A,B}\triangleq(\text{seq2}_{M}^{F,A,B}\boxtimes\text{seq2}_{N}^{F,A,B})\bef\text{zip}_{F}\quad. +\end{align*} \end_inset @@ -26174,10 +26155,12 @@ noprefix "false" ), begin with its left-hand side: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ + & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ & =(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq2}_{M}^{G,A,B}\boxtimes\text{seq2}_{N}^{G,A,B})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ -\text{naturality of }\text{zip}_{F}:\quad & =\gunderline{(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\big((\text{seq2}_{M}^{G,A,B})^{\uparrow F}\boxtimes(\text{seq2}_{N}^{G,A,B})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ -\text{the law~(\ref{eq:pair-product-composition-law})}:\quad & =\big((\text{seq2}_{M}^{F,G^{A},G^{B}}\bef(\text{seq2}_{M}^{G,A,B})^{\uparrow F})\boxtimes(\text{seq2}_{N}^{F,G^{A},G^{B}}\bef(\text{seq2}_{N}^{G,A,B})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. + & \quad\text{naturality of }\text{zip}_{F}:\quad\\ + & =\gunderline{(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\big((\text{seq2}_{M}^{G,A,B})^{\uparrow F}\boxtimes(\text{seq2}_{N}^{G,A,B})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad\text{the law~(\ref{eq:pair-product-composition-law})}:\quad\\ + & =\big((\text{seq2}_{M}^{F,G^{A},G^{B}}\bef(\text{seq2}_{M}^{G,A,B})^{\uparrow F})\boxtimes(\text{seq2}_{N}^{F,G^{A},G^{B}}\bef(\text{seq2}_{N}^{G,A,B})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. \end{align*} \end_inset @@ -26243,13 +26226,14 @@ Here as: \begin_inset Formula -\[ -\text{seq2}_{S}:M^{F^{A},F^{B}}+N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}+N^{A,B}}\quad,\quad\text{seq2}_{S}\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{seq2}_{S}:M^{F^{A},F^{B}}+N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}+N^{A,B}}\quad,\\ + & \text{seq2}_{S}\triangleq\,\begin{array}{|c||c|} & F^{M^{A,B}+N^{A,B}}\\ \hline M^{F^{A},F^{B}} & \text{seq2}_{M}^{F,A,B}\bef(m^{:M^{A,B}}\rightarrow m+\bbnum 0)^{\uparrow F}\\ N^{F^{A},F^{B}} & \text{seq2}_{N}^{F,A,B}\bef(n^{:N^{A,B}}\rightarrow\bbnum 0+n)^{\uparrow F} \end{array}\quad. -\] +\end{align*} \end_inset @@ -26279,7 +26263,8 @@ noprefix "false" \hline M^{\text{Id}^{A},\text{Id}^{B}} & \text{seq2}_{M}^{\text{Id},A,B}\bef(m\rightarrow m+\bbnum 0)^{\uparrow\text{Id}}\\ N^{\text{Id}^{A}} & \text{seq2}_{N}^{\text{Id},A,B}\bef(n\rightarrow\bbnum 0+n)^{\uparrow\text{Id}} \end{array}\\ -\text{identity laws of }\text{seq2}_{M}\text{ and }\text{seq2}_{N}:\quad & =\,\begin{array}{|c||c|} + & \quad\text{identity laws of }\text{seq2}_{M}\text{ and }\text{seq2}_{N}:\quad\\ + & =\,\begin{array}{|c||c|} & M^{A,B}+N^{A,B}\\ \hline M^{A,B} & m\rightarrow m+\bbnum 0\\ N^{A,B} & n\rightarrow\bbnum 0+n @@ -26313,7 +26298,8 @@ noprefix "false" ), write its two sides separately: \begin_inset Formula \begin{align*} -\text{left-hand side}:\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\,\begin{array}{||c|} +\text{left-hand side}:\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ + & \quad=\,\begin{array}{||c|} \text{seq2}_{M}^{F,G^{A},G^{B}}\bef(m\rightarrow m+\bbnum 0)^{\uparrow F}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ \text{seq2}_{N}^{F,G^{A},G^{B}}\bef(n\rightarrow\bbnum 0+n)^{\uparrow F}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F} \end{array}\quad,\\ @@ -26359,7 +26345,8 @@ The Write them separately: \begin_inset Formula \begin{align*} - & (m\rightarrow m+\bbnum 0)\bef\text{seq2}_{S}^{G,A,B}=\,\begin{array}{|c||cc|} + & (m\rightarrow m+\bbnum 0)\bef\text{seq2}_{S}^{G,A,B}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A},G^{B}} & N^{G^{A},G^{B}}\\ \hline M^{G^{A},G^{B}} & \text{id} & \bbnum 0 \end{array}\,\bef\,\begin{array}{|c||c|} @@ -26368,7 +26355,8 @@ The N^{G^{A},G^{B}} & \text{seq2}_{N}^{G,A,B}\bef(n\rightarrow\bbnum 0+n)^{\uparrow G} \end{array}\\ & \quad=\text{seq2}_{M}^{G,A,B}\bef(m^{:M^{A,B}}\rightarrow m+\bbnum 0^{:N^{A,B}})^{\uparrow G}\quad,\\ - & (n\rightarrow\bbnum 0+n)\bef\text{seq2}_{S}^{G,A,B}=\,\begin{array}{|c||cc|} + & (n\rightarrow\bbnum 0+n)\bef\text{seq2}_{S}^{G,A,B}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A},G^{B}} & N^{G^{A},G^{B}}\\ \hline N^{G^{A},G^{B}} & \bbnum 0 & \text{id} \end{array}\,\bef\,\begin{array}{|c||c|} @@ -26606,15 +26594,16 @@ Assume that a lawful \begin_inset Formula $\text{seq3}_{T}$ \end_inset - is available and define + is available, and define \begin_inset Formula $\text{seq2}_{S}$ \end_inset as: \begin_inset Formula -\[ -\text{seq2}_{S}^{F,A,B}:T^{F^{A},F^{B},S^{F^{A},F^{B}}}\rightarrow F^{T^{A,B,S^{A,B}}}\quad,\quad\quad\text{seq2}_{S}^{F,A,B}\triangleq\big(\overline{\text{seq2}}_{S}^{F,A,B}\big)^{\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,S^{A,B}}\quad. -\] +\begin{align*} + & \text{seq2}_{S}^{F,A,B}:T^{F^{A},F^{B},S^{F^{A},F^{B}}}\rightarrow F^{T^{A,B,S^{A,B}}}\quad,\\ + & \text{seq2}_{S}^{F,A,B}\triangleq\big(\overline{\text{seq2}}_{S}^{F,A,B}\big)^{\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,S^{A,B}}\quad. +\end{align*} \end_inset @@ -26657,7 +26646,7 @@ noprefix "false" ): \begin_inset Formula \[ -\text{seq2}_{S}^{\text{Id},A,B}=\big(\overline{\text{seq2}}_{S}^{\text{Id},A,B}\big)^{\uparrow T^{\text{Id}^{A},\text{Id}^{B},\bullet}}\bef\text{seq3}_{T}^{\text{Id},A,B,S^{A,B}}=\text{id}^{\uparrow T^{A,B,\bullet}}\bef\text{id}=\text{id}\quad. +\text{seq2}_{S}^{\text{Id},A,B}=\big(\overline{\text{seq2}}_{S}^{\text{Id},A,B}\big)^{\uparrow T^{\text{Id}^{A},\text{Id}^{B},\,\bullet}}\bef\text{seq3}_{T}^{\text{Id},A,B,S^{A,B}}=\text{id}^{\uparrow T^{A,B,\bullet}}\bef\text{id}=\text{id}\quad. \] \end_inset @@ -26683,9 +26672,9 @@ noprefix "false" ): \begin_inset Formula \begin{align*} - & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ - & \quad=\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},S^{G^{A},G^{B}}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow T^{G^{A},G^{B},\bullet}\uparrow F}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\quad,\\ - & \text{seq2}_{S}^{F\circ G,A,B}=\big(\overline{\text{seq2}}_{S}^{F\circ G,A,B}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}\quad. + & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},S^{G^{A},G^{B}}}\\ + & \quad\quad\quad\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow T^{G^{A},G^{B},\bullet}\uparrow F}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\quad,\\ + & \text{seq2}_{S}^{F\circ G,A,B}=\big(\overline{\text{seq2}}_{S}^{F\circ G,A,B}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}\quad. \end{align*} \end_inset @@ -26701,7 +26690,7 @@ We use the naturality law of : \begin_inset Formula \[ -\text{seq3}_{T}^{F,A,B,C}\bef(f^{:C\rightarrow D})^{\uparrow T^{A,B,\bullet}\uparrow F}=f^{\uparrow F\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,D}\quad. +\text{seq3}_{T}^{F,A,B,C}\bef(f^{:C\rightarrow D})^{\uparrow T^{A,B,\bullet}\uparrow F}=f^{\uparrow F\uparrow T^{F^{A},F^{B},\,\bullet}}\bef\text{seq3}_{T}^{F,A,B,D}\quad. \] \end_inset @@ -26723,10 +26712,10 @@ noprefix "false" ) becomes: \begin_inset Formula \begin{align*} -\text{seq2}_{S}^{F,G^{A},G^{B}}\bef & (\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ - & =\gunderline{\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow F\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\\ -\text{Eq.~(\ref{eq:identity-law-of-bisequence})}:\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\gunderline{\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}}\\ -\text{Eq.~(\ref{eq:composition-law-of-trisequence})}:\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\gunderline{\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}}\quad. +\text{seq2}_{S}^{F,G^{A},G^{B}}\bef & (\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\gunderline{\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow F\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}}\\ + & \quad\quad\quad\bef\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\\ +\text{Eq.~(\ref{eq:identity-law-of-bisequence})}:\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\gunderline{\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}}\\ +\text{Eq.~(\ref{eq:composition-law-of-trisequence})}:\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\gunderline{\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}}\quad. \end{align*} \end_inset @@ -27892,27 +27881,6 @@ noprefix "false" not \emph default necessarily a monad morphism. - One example is where -\begin_inset Formula $M$ -\end_inset - - and -\begin_inset Formula $N$ -\end_inset - - are -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -State -\end_layout - -\end_inset - - monads ***??? \end_layout \begin_layout Subsubsection @@ -28237,89 +28205,52 @@ not . \end_layout -\begin_layout Section -Discussion and further developments -\end_layout - -\begin_layout Subsection -Laws of -\family typewriter -traverse -\family default - and properties of -\family typewriter -zipWithIndex -\family default - +\begin_layout Subsubsection +Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:Laws-of-traverse-and-zipWithIndex" - -\end_inset - - -\end_layout +name "subsec:Exercise-traversables-10-1-1-2" -\begin_layout Standard -Sections -\begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Decorating-a-tree1" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -– -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Decorating-a-tree-breadth-first-traversal" +reference "subsec:Exercise-traversables-10-1-1-2" plural "false" caps "false" noprefix "false" \end_inset - defined the method -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -zipWithIndex \end_layout +\begin_layout Standard +For any applicative functor +\begin_inset Formula $F$ \end_inset - for different orders of tree traversal. - In a similar way, we may define + with a known \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +zip \end_layout \end_inset - (denoted -\begin_inset Formula $\text{zwi}_{L}$ + method, define the +\begin_inset Quotes eld \end_inset - for brevity) for any traversable functor -\begin_inset Formula $L$ +reversed +\begin_inset Quotes erd \end_inset -. - In this section, we will prove some intuitively reasonable properties of \begin_inset listings inline true @@ -28327,114 +28258,153 @@ status open \begin_layout Plain Layout -zipWithIndex +zip \end_layout \end_inset - by assuming only that the laws of -\begin_inset listings -inline true -status open + method as: +\begin_inset Formula +\[ +\text{zip}_{\text{rev}F}:F^{A}\times F^{B}\rightarrow F^{A\times B}\quad,\quad\quad\text{zip}_{\text{rev}F}\triangleq\text{swap}\bef\text{zip}_{F}\bef\text{swap}^{\uparrow F}\quad. +\] + +\end_inset -\begin_layout Plain Layout -traverse \end_layout +\begin_layout Standard + +\series bold +(a) +\series default + Show that +\begin_inset Formula $\text{zip}_{\text{rev}F}$ +\end_inset + + also provides a lawful applicative instance for +\begin_inset Formula $F$ +\end_inset + + (where +\begin_inset Formula $F$ \end_inset - hold. - This will serve as an additional evidence that the laws of +'s \begin_inset listings inline true status open \begin_layout Plain Layout -traverse +pure \end_layout \end_inset - correspond to a programmer's intuitions about code. + method remains unchanged). + Show that +\begin_inset Formula $\text{zip}_{\text{rev}F}=\text{zip}_{F}$ +\end_inset + + whenever +\begin_inset Formula $F$ +\end_inset + + is commutative. \end_layout \begin_layout Standard -To implement -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\series bold +(b) +\series default + Show that the +\begin_inset Quotes eld +\end_inset -zipWithIndex -\end_layout +applicative reversal +\begin_inset Quotes erd +\end_inset + obeys an applicative naturality law: for any applicative functors +\begin_inset Formula $F$ \end_inset - for -\begin_inset Formula $L$ +, +\begin_inset Formula $G$ \end_inset -, we use -\begin_inset Formula $L$ + and an applicative morphism +\begin_inset Formula $\phi:F^{A}\rightarrow G^{A}$ \end_inset -'s -\begin_inset listings -inline true -status open +, the following equation holds: +\begin_inset Formula +\[ +(p^{:F^{A}}\times q^{:F^{B}})\triangleright\text{zip}_{\text{rev}F}\triangleright\phi=(\phi(p)\times\phi(q))\triangleright\text{zip}_{\text{rev}G}\quad. +\] + +\end_inset -\begin_layout Plain Layout -traverse \end_layout -\end_inset +\begin_layout Section +Discussion and further developments +\end_layout - method ( -\begin_inset Formula $\text{trav}_{L}^{F,A,B}$ -\end_inset +\begin_layout Subsection +The missing laws of +\family typewriter +traverse +\family default + and +\family typewriter +zipWithIndex +\family default + +\begin_inset CommandInset label +LatexCommand label +name "subsec:Laws-of-traverse-and-zipWithIndex" -) and chose the applicative functor -\begin_inset Formula $F$ \end_inset - as the + +\end_layout + +\begin_layout Standard +The two laws of \begin_inset listings inline true status open \begin_layout Plain Layout -State +traverse \end_layout \end_inset - monad with internal state of type + shown in this chapter do +\emph on +not +\emph default + in fact guarantee that \begin_inset listings inline true status open \begin_layout Plain Layout -Int +traverse \end_layout \end_inset -: -\begin_inset Formula -\[ -F^{A}\triangleq\text{State}^{\text{Int},A}\triangleq\text{Int}\rightarrow A\times\text{Int}\quad. -\] - -\end_inset - -The internal state represents a current value of the index. - The code of + behaves as programmers expect. + To see that, we generalize \begin_inset listings inline true status open @@ -28446,77 +28416,93 @@ zipWithIndex \end_inset - applies + to arbitrary traversable functors and then try proving two intuitively + reasonable properties of \begin_inset listings inline true status open \begin_layout Plain Layout -traverse +zipWithIndex \end_layout \end_inset - to a function of type -\begin_inset Formula $A\rightarrow\text{State}^{S,A\times\text{Int}}$ -\end_inset + starting from the two laws of +\begin_inset listings +inline true +status open - that increments the index: -\begin_inset Formula -\begin{equation} -\text{zwi}_{L}^{A}:L^{A}\rightarrow L^{A\times\text{Int}}\quad,\quad\text{zwi}_{L}^{A}\triangleq\text{trav}_{L}^{F,A,A\times\text{Int}}(a^{:A}\rightarrow s^{:\text{Int}}\rightarrow(a\times s)\times(s+1))\bef\text{run}_{\text{State}}(0^{:\text{Int}})\quad,\label{eq:definition-of-zwi} -\end{equation} +\begin_layout Plain Layout -\end_inset +traverse +\end_layout -Here -\begin_inset Formula $\text{run}_{\text{State}}(0^{:\text{Int}})$ \end_inset - is the +. + We will find that we +\emph on +cannot +\emph default + prove one of these properties without assuming some new laws of \begin_inset listings inline true status open \begin_layout Plain Layout -State +traverse \end_layout \end_inset - monad's runner defined by Eq. +. + However, another approach based on more advanced techniques makes it possible + to prove all necessary properties. + +\end_layout + +\begin_layout Standard +Sections \begin_inset space ~ \end_inset -( + \begin_inset CommandInset ref LatexCommand ref -reference "eq:definition-of-runState" +reference "subsec:Decorating-a-tree1" plural "false" caps "false" noprefix "false" \end_inset -) and applied to the zero integer value -\begin_inset Formula $0^{:\text{Int}}$ +– +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Decorating-a-tree-breadth-first-traversal" +plural "false" +caps "false" +noprefix "false" + \end_inset -: -\begin_inset Formula -\[ -\text{run}_{\text{State}}:S\rightarrow\text{State}^{S,A}\rightarrow A\quad,\quad\quad\text{run}_{\text{State}}(s_{0})\triangleq k^{:S\rightarrow A\times S}\rightarrow s_{0}\triangleright k\triangleright\pi_{1}\quad. -\] - -\end_inset + defined the method +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +zipWithIndex \end_layout -\begin_layout Standard -What are a programmer's intuitive expectations about +\end_inset + + for certain choices of traversals over binary trees. + How can we define \begin_inset listings inline true status open @@ -28528,70 +28514,81 @@ zipWithIndex \end_inset - when applied to arbitrary traversable functors + (denoted +\begin_inset Formula $\text{zwi}_{L}$ +\end_inset + + for brevity) for any traversable functor \begin_inset Formula $L$ \end_inset -? First, +? We use +\begin_inset Formula $L$ +\end_inset + +'s \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +traverse \end_layout \end_inset - applied to a value -\begin_inset Formula $p:L^{A}$ + method ( +\begin_inset Formula $\text{trav}_{L}^{F,A,B}$ \end_inset - should produce a value of type -\begin_inset Formula $L^{A\times\text{Int}}$ +) and chose the applicative functor +\begin_inset Formula $F$ \end_inset - that preserves the structure of -\begin_inset Formula $p$ -\end_inset + as the +\begin_inset listings +inline true +status open - and just adds indices at places where some data of type -\begin_inset Formula $A$ -\end_inset +\begin_layout Plain Layout + +State +\end_layout - is stored within -\begin_inset Formula $p$ \end_inset -. - Second, + monad with the internal state of type \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +Int \end_layout \end_inset - should produce a -\emph on -different -\emph default - index for every value of type +: +\begin_inset Formula +\[ +F^{A}\triangleq\text{State}^{\text{Int},A}\triangleq\text{Int}\rightarrow A\times\text{Int}\quad. +\] + +\end_inset + +The internal state represents the current value of the index while we iterate + over values of type \begin_inset Formula $A$ \end_inset stored within -\begin_inset Formula $p$ +\begin_inset Formula $L^{A}$ \end_inset . - Let us now formulate those intuitions as equations that rigorously express - the expected properties of + The code of \begin_inset listings inline true status open @@ -28603,65 +28600,175 @@ zipWithIndex \end_inset -. + applies +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse \end_layout -\begin_layout Standard -The first property is that the value -\begin_inset Formula $p:L^{A}$ \end_inset - must be restored if we remove the index values: + to a function of type +\begin_inset Formula $A\rightarrow\text{State}^{S,A\times\text{Int}}$ +\end_inset + + that increments the index: +\begin_inset Formula +\begin{align} + & \text{zwi}_{L}^{A}:L^{A}\rightarrow L^{A\times\text{Int}}\quad,\nonumber \\ + & \text{zwi}_{L}^{A}\triangleq\text{trav}_{L}^{F,A,A\times\text{Int}}(a^{:A}\rightarrow s^{:\text{Int}}\rightarrow(a\times s)\times(s+1))\bef\text{run}_{\text{State}}(0^{:\text{Int}})\quad.\label{eq:definition-of-zwi} +\end{align} + +\end_inset + +Here, +\begin_inset Formula $\text{run}_{\text{State}}(0^{:\text{Int}})$ +\end_inset + + is the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +State +\end_layout + +\end_inset + + monad's runner defined by Eq. +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:definition-of-runState" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) and applied to the zero integer value +\begin_inset Formula $0^{:\text{Int}}$ +\end_inset + +: +\begin_inset Formula +\[ +\text{run}_{\text{State}}:S\rightarrow\text{State}^{S,A}\rightarrow A\quad,\quad\quad\text{run}_{\text{State}}(s_{0})\triangleq k^{:S\rightarrow A\times S}\rightarrow s_{0}\triangleright k\triangleright\pi_{1}\quad. +\] + +\end_inset + + \end_layout \begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "50col%" +What are a programmer's intuitive expectations about +\begin_inset listings +inline true status open \begin_layout Plain Layout -\begin_inset VSpace -100baselineskip% + +zipWithIndex +\end_layout + \end_inset + when applied to arbitrary traversable functors +\begin_inset Formula $L$ +\end_inset +? First, \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -p.zipWithIndex.map(_._1) == p +zipWithIndex \end_layout \end_inset + applied to a value +\begin_inset Formula $p:L^{A}$ +\end_inset -\begin_inset VSpace -50baselineskip% + should produce a value of type +\begin_inset Formula $L^{A\times\text{Int}}$ \end_inset + that preserves the structure of +\begin_inset Formula $p$ +\end_inset + + and just adds indices at places where data of type +\begin_inset Formula $A$ +\end_inset + + is stored within +\begin_inset Formula $p$ +\end_inset + +. + Second, +\begin_inset listings +inline true +status open +\begin_layout Plain Layout + +zipWithIndex \end_layout \end_inset + should produce a +\emph on +different +\emph default + index for every value of type +\begin_inset Formula $A$ +\end_inset + + stored within +\begin_inset Formula $p$ +\end_inset +. + To express these properties rigorously, let us formulate them as equations. \end_layout \begin_layout Standard -\begin_inset space ~ +The first property is that the value +\begin_inset Formula $p:L^{A}$ \end_inset + must be recovered if we drop the index values: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +p.zipWithIndex.map(_._1) == p +\end_layout -\begin_inset VSpace -50baselineskip% \end_inset \begin_inset Formula \[ -p\triangleright\text{zwi}_{L}\triangleright\pi_{1}^{\uparrow L}=p\quad. +p\triangleright\text{zwi}_{L}\triangleright\pi_{1}^{\uparrow L}=p\quad,\quad\text{or equivalently}:\quad\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}\quad. \] \end_inset @@ -28670,8 +28777,7 @@ p\triangleright\text{zwi}_{L}\triangleright\pi_{1}^{\uparrow L}=p\quad. \end_layout \begin_layout Standard -The second property means that each index can be mapped to a distinct value - of type +The second property says that each distinct value of type \begin_inset Formula $A$ \end_inset @@ -28679,8 +28785,17 @@ The second property means that each index can be mapped to a distinct value \begin_inset Formula $p$ \end_inset -. - Begin by computing a value + should get a different index. + To express this property via an equation, begin by computing +\begin_inset Formula $\text{zwi}_{L}(p)$ +\end_inset + + and then discard the values of type +\begin_inset Formula $A$ +\end_inset + +, leaving only the indices. + The result is a value \begin_inset Formula $q\triangleq p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}$ \end_inset @@ -28689,24 +28804,28 @@ The second property means that each index can be mapped to a distinct value \end_inset . - Then + We expect \begin_inset Formula $q$ \end_inset - has the same structure as + to have the same shape and structure as \begin_inset Formula $p$ \end_inset - but carries integer index values instead of values of type + except that +\begin_inset Formula $q$ +\end_inset + + carries integer index values instead of values of type \begin_inset Formula $A$ \end_inset . - We expect that the original data ( + The original value ( \begin_inset Formula $p$ \end_inset -) can be restored if we replace the index values in +) can be restored if we replace all index values in \begin_inset Formula $q$ \end_inset @@ -28715,16 +28834,20 @@ The second property means that each index can be mapped to a distinct value \end_inset . - In other words, there should exist a function -\begin_inset Formula $f:\text{Int}\rightarrow A$ + So, for any given +\begin_inset Formula $p$ +\end_inset + + there should exist a function +\begin_inset Formula $f_{p}:\text{Int}\rightarrow A$ \end_inset such that \begin_inset Formula $p$ \end_inset - can be restored from -\begin_inset Formula $f$ + can be recovered from +\begin_inset Formula $f_{p}$ \end_inset and @@ -28732,19 +28855,19 @@ The second property means that each index can be mapped to a distinct value \end_inset as -\begin_inset Formula $p=q\triangleright f^{\uparrow L}$ +\begin_inset Formula $p=q\triangleright f_{p}^{\uparrow L}$ \end_inset . - This also means that there should be an injective map from the type -\begin_inset Formula $L^{A}$ -\end_inset + In other words: +\begin_inset Formula +\[ +\forall p^{:L^{A}}:\quad p=p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright f_{p}^{\uparrow L}\quad. +\] - to the type -\begin_inset Formula $(\text{Int}\rightarrow A)\times L^{\text{Int}}$ \end_inset -. + \end_layout \begin_layout Standard @@ -28765,7 +28888,7 @@ zipWithIndex \end_inset is a lawful traversable functor. - In that proof, we will need a special subtype of the + In that proof, we will use a special subtype of the \begin_inset listings inline true status open @@ -28777,7 +28900,7 @@ State \end_inset - monad: + monad. \end_layout \begin_layout Subsubsection @@ -28802,7 +28925,11 @@ noprefix "false" \end_layout \begin_layout Standard -We define a +Assume that the type +\begin_inset Formula $S$ +\end_inset + + is not void and define a \begin_inset Quotes eld \end_inset @@ -28822,11 +28949,11 @@ State \begin_inset Quotes erd \end_inset -, denoted by +, which we denote by \begin_inset Formula $\text{CFState}^{S,A}$ \end_inset -, like this: Write the type of a +, like this: Rewrite the type of a \begin_inset listings inline true status open @@ -28838,7 +28965,7 @@ State \end_inset - monad equivalently as + monad as \begin_inset Formula $\text{State}^{S,A}\triangleq S\rightarrow A\times S\cong(S\rightarrow A)\times(S\rightarrow S)$ \end_inset @@ -28903,9 +29030,10 @@ fromCF that is an identity function that merely reassigns types: \begin_inset Formula -\[ -\text{fromCF}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\quad\quad\text{fromCF}\triangleq p^{:\_\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p^{:S\rightarrow A}\times q^{:S\rightarrow S}\quad. -\] +\begin{align*} + & \text{fromCF}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\\ + & \text{fromCF}\triangleq p^{:\_\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p^{:S\rightarrow A}\times q^{:S\rightarrow S}\quad. +\end{align*} \end_inset @@ -28925,7 +29053,7 @@ Assuming that \begin_inset Formula $\text{CFState}^{S,A}$ \end_inset - is a monad with the same implementation code as + is a monad with the same implementation as \begin_inset Formula $\text{State}^{S,A}$ \end_inset @@ -28957,7 +29085,7 @@ fromCF \series bold (c) \series default - The monad + Define a runner for the monad \begin_inset listings inline true status open @@ -28969,14 +29097,10 @@ CFState \end_inset - has a runner, -\begin_inset Formula $\text{run}_{\text{CFState}}:\text{CFState}^{S,A}\rightarrow A$ -\end_inset - -, defined by: + by: \begin_inset Formula \[ -\text{run}_{\text{CFState}}\triangleq\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})\quad, +\text{run}_{\text{CFState}}:\text{CFState}^{S,A}\rightarrow A\quad,\quad\quad\text{run}_{\text{CFState}}\triangleq\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})\quad, \] \end_inset @@ -28986,7 +29110,7 @@ where \end_inset is a fixed value. - The function + Then the function \begin_inset Formula $\text{run}_{\text{CFState}}$ \end_inset @@ -28994,7 +29118,11 @@ where \begin_inset Formula $s_{0}$ \end_inset - and is both a monad morphism and an applicative morphism. + and is an applicative morphism between +\begin_inset Formula $\text{CFState}^{S,A}$ +\end_inset + + and the identity functor. (Note that \begin_inset Formula $\text{run}_{\text{State}}(s_{0})$ \end_inset @@ -29003,10 +29131,18 @@ where \begin_inset Formula $\text{State}^{S,A}\rightarrow A$ \end_inset -.) +.) +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout + +\series bold +The item (d) is, most likely, false. + \end_layout -\begin_layout Standard +\begin_layout Plain Layout \series bold (d) @@ -29037,11 +29173,11 @@ Writer monad. There exists a one-to-one (bijective) monad morphism -\begin_inset Formula $\text{CFState}^{S,A}\rightarrow\text{Writer}^{W,A}$ +\begin_inset Formula $\text{CFState}^{S,A}\rightarrow\text{Writer}^{A,W}$ \end_inset where -\begin_inset Formula $\text{Writer}^{W,A}\triangleq A\times W$ +\begin_inset Formula $\text{Writer}^{A,W}\triangleq A\times W$ \end_inset and the type @@ -29069,9 +29205,14 @@ noprefix "false" ). \end_layout -\begin_layout Subparagraph -Proof -\end_layout +\end_inset + + +\end_layout + +\begin_layout Subparagraph +Proof +\end_layout \begin_layout Standard @@ -29107,7 +29248,8 @@ State \begin{align*} & \text{pu}_{\text{State}}:A\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\quad\quad\text{pu}_{\text{State}}=a^{:A}\rightarrow(\_^{:S}\rightarrow a)\times\text{id}^{:S\rightarrow S}\quad,\\ & \text{ftn}_{\text{State}}:(S\rightarrow(S\rightarrow A)\times(S\rightarrow S))\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\\ - & \text{ftn}_{\text{State}}=p^{:S\rightarrow(S\rightarrow A)\times(S\rightarrow S)}\times q^{:S\rightarrow S}\rightarrow(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{1}))\times(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{2}))\quad. + & \text{ftn}_{\text{State}}=p^{:S\rightarrow(S\rightarrow A)\times(S\rightarrow S)}\times q^{:S\rightarrow S}\\ + & \quad\quad\quad\quad\quad\rightarrow(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{1}))\times(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{2}))\quad. \end{align*} \end_inset @@ -29259,7 +29401,15 @@ State \end_inset - (in the sense of subtyping explained in Section + (in the sense of +\begin_inset Quotes eld +\end_inset + +subtyping +\begin_inset Quotes erd +\end_inset + + explained in Section \begin_inset space ~ \end_inset @@ -29394,7 +29544,7 @@ Here \end_layout \begin_layout Standard -It remains to verify that +Now we will show that \begin_inset Formula $\text{fromCF}\bef\text{toCF}=\text{id}$ \end_inset @@ -29403,15 +29553,16 @@ It remains to verify that \begin_inset Formula $p\triangleq\_^{:S}\rightarrow a_{0}$ \end_inset - we will have +, we have \begin_inset Formula $p(s_{0})=a_{0}$ \end_inset - and so we can write: + and then: \begin_inset Formula -\[ -\text{fromCF}\bef\text{toCF}=p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow p(s_{0}))\times q=p\times q\rightarrow(\_\rightarrow a_{0})\times q=p\times q\rightarrow p\times q=\text{id}\quad. -\] +\begin{align*} +\text{fromCF}\bef\text{toCF} & =p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow p(s_{0}))\times q\\ + & =p\times q\rightarrow(\_\rightarrow a_{0})\times q=p\times q\rightarrow p\times q=\text{id}\quad. +\end{align*} \end_inset @@ -29423,347 +29574,1293 @@ It remains to verify that \series bold (c) \series default - The code *** + To see that the code of +\begin_inset Formula $\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})$ +\end_inset + + does not depend on +\begin_inset Formula $s_{0}$ +\end_inset + +, we first adapt the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +State \end_layout -\begin_layout Standard +\end_inset -\series bold -(d) -\series default - A value of type -\begin_inset Formula $\text{CFState}^{S,A}=(\_^{:S}\rightarrow A)\times(S\rightarrow S)$ + monad's runner ( +\begin_inset Formula $\text{run}_{\text{State}}$ \end_inset - is a pair of a constant function and a value of type -\begin_inset Formula $W$ +) to the type +\begin_inset Formula $(S\rightarrow A)\times(S\rightarrow S)$ \end_inset -. - When -\begin_inset Formula $S$ +, which is equivalent to the type +\begin_inset Formula $\text{State}^{S,A}$ \end_inset - is not void, the type of constant functions -\begin_inset Formula $(\_^{:S}\rightarrow A)$ +: +\begin_inset Formula +\[ +\text{run}_{\text{State}}(s_{0})=(p^{:S\rightarrow A}\times q^{:S\rightarrow S})\rightarrow\big(p(s_{0})\times q(s_{0})\big)\triangleright\pi_{1}=p^{:S\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p(s_{0})\quad. +\] + \end_inset - is equivalent to the type -\begin_inset Formula $A$ +Now we take any value +\begin_inset Formula $c$ \end_inset -: we can substitute an arbitrary value -\begin_inset Formula $s_{0}:S$ + of type +\begin_inset Formula $\text{CFState}^{S,A}$ \end_inset - into a constant function and obtain the corresponding value of type -\begin_inset Formula $A$ + and write: +\begin_inset Formula +\begin{align*} + & c\triangleright\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})=(p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S})\triangleright\text{fromCF}\triangleright\text{run}_{\text{State}}(s_{0})\\ + & =(p\times q)\triangleright\text{run}_{\text{State}}(s_{0})=p(s_{0})\quad. +\end{align*} + \end_inset -. - So, we have the type equivalence -\begin_inset Formula $\text{CFState}^{S,A}\cong A\times(S\rightarrow S)\triangleq A\times W$ +The last value does not depend on +\begin_inset Formula $s_{0}$ \end_inset -. - The isomorphism is given by a function + because +\begin_inset Formula $p$ +\end_inset + + is a constant function. + +\end_layout + +\begin_layout Standard +To show that +\begin_inset Formula $\text{run}_{\text{CFState}}$ +\end_inset + + is an applicative morphism between the applicative functors +\begin_inset Formula $\text{CFState}^{S,A}$ +\end_inset + + and +\begin_inset Formula $\text{Id}$ +\end_inset + +, first note that the \begin_inset listings inline true status open \begin_layout Plain Layout -inCF +pure \end_layout \end_inset - defined by: -\begin_inset Formula -\[ -\text{inCF}:\text{Writer}^{W,A}\rightarrow\text{CFState}^{S,A}\quad,\quad\quad\text{inCF}\triangleq a^{:A}\times w^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow a)\times w\quad. -\] - -\end_inset + method of +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +CFState \end_layout -\begin_layout Standard -It remains to verify that +\end_inset + + is the same as that of the \begin_inset listings inline true status open \begin_layout Plain Layout -inCF +State \end_layout \end_inset - is a monad morphism. - To verify the identity law: -\begin_inset Formula -\begin{align*} - & \text{pu}_{\text{Writer}}\bef\text{inCF}=(a^{:A}\rightarrow a\times\text{id})\bef(a\times w\rightarrow(\_\rightarrow a)\times w)\\ - & =a\rightarrow(\_\rightarrow a)\times\text{id}=\text{pu}_{\text{State}}=\text{pu}_{\text{CFState}}\quad. -\end{align*} + monad. + A +\begin_inset Quotes eld +\end_inset +pure +\begin_inset Quotes erd +\end_inset + + value +\begin_inset Formula $\text{pu}_{\text{CFState}}(a^{:A})$ \end_inset + equals the function +\begin_inset Formula $s\rightarrow a\times s$ +\end_inset -\begin_inset Formula $\square$ +. + Applying +\begin_inset Formula $\text{run}_{\text{State}}(s_{0})$ \end_inset + to the function +\begin_inset Formula $s\rightarrow a\times s$ +\end_inset -\end_layout + will always return just the value +\begin_inset Formula $a$ +\end_inset -\begin_layout Standard -We are now ready to prove the first property of +. + This is the same as the identity functor's \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +pure \end_layout \end_inset -. -\end_layout - -\begin_layout Subsubsection -Statement -\begin_inset CommandInset label -LatexCommand label -name "subsec:Statement-properties-of-zipWithIndex" + method (which is an identity function) applied to the value +\begin_inset listings +inline true +status open -\end_inset +\begin_layout Plain Layout +a +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Statement-properties-of-zipWithIndex" -plural "false" -caps "false" -noprefix "false" +\end_inset +. + So, +\begin_inset Formula $\text{run}_{\text{CFState}}$ \end_inset + will map +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +CFState \end_layout -\begin_layout Standard -For any lawful traversable functor -\begin_inset Formula $L$ \end_inset -, define the function +'s \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +pure \end_layout \end_inset - (denoted for brevity by -\begin_inset Formula $\text{zwi}_{L}$ -\end_inset + into the identity functor's +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +pure +\end_layout -) via Eq. -\begin_inset space ~ \end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:definition-of-zwi" -plural "false" -caps "false" -noprefix "false" +. +\end_layout +\begin_layout Standard +It remains to show that +\begin_inset Formula $\text{run}_{\text{CFState}}$ \end_inset -). - Then + maps \begin_inset listings inline true status open \begin_layout Plain Layout -zipWithIndex +CFState \end_layout \end_inset - satisfies the equation: -\begin_inset Formula $\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}^{:L^{A}\rightarrow L^{A}}$ -\end_inset +'s +\begin_inset listings +inline true +status open -. -\end_layout +\begin_layout Plain Layout -\begin_layout Standard +zip +\end_layout -\series bold -(b) -\series default - There exists a -\begin_inset Quotes eld \end_inset -tabulating -\begin_inset Quotes erd -\end_inset + method into the identity functor's +\begin_inset listings +inline true +status open - function (denoted by -\begin_inset Formula $\text{tab}_{L}^{A}$ -\end_inset +\begin_layout Plain Layout -): -\begin_inset Formula -\[ -\text{tab}_{L}^{A}:L^{A\times\text{Int}}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad, -\] +zip +\end_layout \end_inset -such that -\begin_inset Formula $\text{zwi}_{L}\bef\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})=\text{id}^{:L^{A}\rightarrow L^{A}}$ + method (which is again an identity function, +\begin_inset Formula $a\times b\rightarrow a\times b$ \end_inset -. - So, the function -\begin_inset Formula $\text{zwi}_{L}\bef\text{tab}_{L}$ -\end_inset +). + The code of +\begin_inset listings +inline true +status open - is an injective map of type -\begin_inset Formula $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$ -\end_inset +\begin_layout Plain Layout -. +CFState \end_layout -\begin_layout Subparagraph -Proof -\end_layout +\end_inset + +'s +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zip +\end_layout + +\end_inset + + is: +\begin_inset Formula +\begin{align*} + & \text{zip}_{\text{CFState}}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\times(\_^{:S}\rightarrow B)\times(S\rightarrow S)\rightarrow(\_^{:S}\rightarrow A\times B)\times(S\rightarrow S)\quad,\\ + & \text{zip}_{\text{CFState}}:p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\times p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S}\rightarrow(s^{:S}\rightarrow p_{1}(s)\times p_{2}(s))\times(q_{1}\bef q_{2})\quad. +\end{align*} + +\end_inset + +The function +\begin_inset Formula $s^{:S}\rightarrow p(s)\times q(s)$ +\end_inset + + is a constant function because +\begin_inset Formula $p$ +\end_inset + + and +\begin_inset Formula $q$ +\end_inset + + are. +\end_layout + +\begin_layout Standard +Applying +\begin_inset Formula $\text{zip}_{\text{CFState}}$ +\end_inset + + to arbitrary values: +\begin_inset Formula +\begin{align*} + & c_{1}:\text{CFState}^{S,A}\quad,\quad\quad c_{1}=p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\quad,\\ + & c_{2}:\text{CFState}^{S,B}\quad,\quad\quad c_{2}=p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S}\quad, +\end{align*} + +\end_inset + + and then applying +\begin_inset Formula $\text{run}_{\text{CFState}}$ +\end_inset + +, we get: +\begin_inset Formula +\begin{align*} + & (p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\times p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S})\triangleright\text{zip}_{\text{CFState}}\triangleright\text{run}_{\text{CFState}}\\ + & =(s^{:S}\rightarrow p_{1}(s)\times p_{2}(s))\times(q_{1}\bef q_{2})\triangleright\text{run}_{\text{CFState}}\\ + & =p_{1}(s_{0})\times p_{2}(s_{0})\quad. +\end{align*} + +\end_inset + +Applying +\begin_inset Formula $\text{run}_{\text{CFState}}$ +\end_inset + + to the initial values, we find: +\begin_inset Formula +\[ +(p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S})\triangleright\text{run}_{\text{CFState}}=p_{1}(s_{0})\quad,\quad\quad(p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S})\triangleright\text{run}_{\text{CFState}}=p_{2}(s_{0})\quad. +\] + +\end_inset + +So, the composition law of applicative morphisms holds: +\begin_inset Formula +\[ +(c_{1}\times c_{2})\triangleright\text{zip}_{\text{CFState}}\triangleright\text{run}_{\text{CFState}}=(c_{1}\triangleright\text{run}_{\text{CFState}})\times(c_{2}\triangleright\text{run}_{\text{CFState}})\quad. +\] + +\end_inset + + +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout + +\series bold +The item (d) is, most likely, false. + +\end_layout + +\begin_layout Plain Layout + +\series bold +(d) +\series default + A value of type +\begin_inset Formula $\text{CFState}^{S,A}=(\_^{:S}\rightarrow A)\times(S\rightarrow S)$ +\end_inset + + is a pair of a constant function and a value of type +\begin_inset Formula $W$ +\end_inset + +. + When +\begin_inset Formula $S$ +\end_inset + + is not void, the type of constant functions +\begin_inset Formula $(\_^{:S}\rightarrow A)$ +\end_inset + + is equivalent to the type +\begin_inset Formula $A$ +\end_inset + +: we can substitute an arbitrary value +\begin_inset Formula $s_{0}:S$ +\end_inset + + into a constant function and obtain the corresponding value of type +\begin_inset Formula $A$ +\end_inset + +. + So, we have the type equivalence +\begin_inset Formula $\text{CFState}^{S,A}\cong A\times(S\rightarrow S)\triangleq A\times W$ +\end_inset + +. + The isomorphism is given by a function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +inCF +\end_layout + +\end_inset + + defined by: +\begin_inset Formula +\[ +\text{inCF}:\text{Writer}^{W,A}\rightarrow\text{CFState}^{S,A}\quad,\quad\quad\text{inCF}\triangleq a^{:A}\times w^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow a)\times w\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +It remains to verify that +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +inCF +\end_layout + +\end_inset + + is a monad morphism. + To verify the identity law: +\begin_inset Formula +\begin{align*} + & \text{pu}_{\text{Writer}}\bef\text{inCF}=(a^{:A}\rightarrow a\times\text{id})\bef(a\times w\rightarrow(\_\rightarrow a)\times w)\\ + & =a\rightarrow(\_\rightarrow a)\times\text{id}=\text{pu}_{\text{State}}=\text{pu}_{\text{CFState}}\quad. +\end{align*} + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Formula $\square$ +\end_inset + + +\end_layout + +\begin_layout Standard +We are now ready to prove the first property of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Subsubsection +Statement +\begin_inset CommandInset label +LatexCommand label +name "subsec:Statement-properties-of-zipWithIndex" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Statement-properties-of-zipWithIndex" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +For any traversable functor +\begin_inset Formula $L$ +\end_inset + +, define +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + + (denoted for brevity by +\begin_inset Formula $\text{zwi}_{L}$ +\end_inset + +) via Eq. +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:definition-of-zwi" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +). + Then +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + + satisfies the equation: +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout + +\series bold +(b) +\series default + There exists a +\begin_inset Quotes eld +\end_inset + +tabulating +\begin_inset Quotes erd +\end_inset + + function (denoted by +\begin_inset Formula $\text{tab}_{L}^{A}$ +\end_inset + +): +\begin_inset Formula +\[ +\text{tab}_{L}^{A}:L^{A\times\text{Int}}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad, +\] + +\end_inset + +such that +\begin_inset Formula $\text{zwi}_{L}\bef\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})=\text{id}^{:L^{A}\rightarrow L^{A}}$ +\end_inset + +. + So, the function +\begin_inset Formula $\text{zwi}_{L}\bef\text{tab}_{L}$ +\end_inset + + is an injective map of type +\begin_inset Formula $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$ +\end_inset + +. +\end_layout + +\end_inset + + +\begin_inset Formula +\[ +\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}^{:L^{A}\rightarrow L^{A}}\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Subparagraph +Proof +\end_layout + +\begin_layout Standard +To make the definition +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:definition-of-zwi" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) easier to work with, we denote: +\begin_inset Formula +\begin{align*} + & F^{A}\triangleq\text{State}^{\text{Int},A}=(\text{Int}\rightarrow A)\times(\text{Int}\rightarrow\text{Int})\quad,\\ + & g:A\rightarrow\text{State}^{\text{Int},A\times\text{Int}}\quad,\quad\quad g\triangleq a^{:A}\rightarrow(s^{:\text{Int}}\rightarrow a\times s)\times(s^{:\text{Int}}\rightarrow s+1)\quad,\\ + & r:\forall B.\,\text{State}^{\text{Int},B}\rightarrow B\quad,\quad\quad r\triangleq p^{:\text{Int}\rightarrow B}\times q^{:\text{Int}\rightarrow\text{Int}}\rightarrow p(0^{:\text{Int}})\quad. +\end{align*} + +\end_inset + +and get +\begin_inset Formula $\text{zwi}_{L}=\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef r$ +\end_inset + +. + Then we write: +\begin_inset Formula +\begin{align*} + & \text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef\gunderline{r\bef\pi_{1}^{\uparrow L}}\\ +\text{naturality of }r:\quad & =\gunderline{\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef\pi_{1}^{\uparrow L\uparrow\text{State}}}\bef r\\ +\text{naturality of }\text{trav}_{L}:\quad & =\text{trav}_{L}^{F,A,A}(g\bef\pi_{1}^{\uparrow\text{State}})\bef r\quad. +\end{align*} + +\end_inset + +To compute +\begin_inset Formula $g\bef\pi_{1}^{\uparrow\text{State}}$ +\end_inset + +, we first express the lifting to +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +State +\end_layout + +\end_inset + + as: +\begin_inset Formula +\[ +(f^{:A\rightarrow B})^{\uparrow\text{State}^{S,\bullet}}(p^{:S\rightarrow A}\times q^{:S\rightarrow S})=(p\bef f)\times q\quad. +\] + +\end_inset + +Then we get: +\begin_inset Formula +\begin{align*} + & g\bef\pi_{1}^{\uparrow\text{State}}:A\rightarrow\text{State}^{\text{Int},A}\quad,\\ + & g\bef\pi_{1}^{\uparrow\text{State}}=a^{:A}\rightarrow(s^{:\text{Int}}\rightarrow\pi_{1}(a\times s))\times(s^{:\text{Int}}\rightarrow s+1)\\ + & =a\rightarrow(s^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)=a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\quad. +\end{align*} + +\end_inset + +Now we note that the sub-expression ( +\begin_inset Formula $\_^{:\text{Int}}\rightarrow a$ +\end_inset + +) is a constant function. + So, +\begin_inset Formula $g\bef\pi_{1}^{\uparrow\text{State}}$ +\end_inset + + can be expressed as a function +\begin_inset Formula $h$ +\end_inset + + of type +\begin_inset Formula $A\rightarrow\text{CFState}^{\text{Int},A}$ +\end_inset + + followed by +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +fromCF +\end_layout + +\end_inset + +: +\begin_inset Formula +\begin{align*} + & h:A\rightarrow\text{CFState}^{\text{Int},A}=A\rightarrow(\_^{:\text{Int}}\rightarrow A)\times(\text{Int}\rightarrow\text{Int})\quad,\\ + & h\triangleq a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\quad,\quad\quad g\bef\pi_{1}^{\uparrow\text{State}}=h\bef\text{fromCF}\quad. +\end{align*} + +\end_inset + + +\end_layout + +\begin_layout Standard +In this way, we have found that: +\begin_inset Formula +\[ +\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}^{\text{State}^{\text{Int},\bullet},A,A}(h\bef\text{fromCF})\bef r\quad. +\] + +\end_inset + +Since +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +fromCF +\end_layout + +\end_inset + + is an applicative morphism, we can use the applicative naturality law +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:traverse-applicative-naturality-law" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) with +\begin_inset Formula $B\triangleq A$ +\end_inset + +, +\begin_inset Formula $F^{A}\triangleq\text{CFState}^{\text{Int},A}$ +\end_inset + +, +\begin_inset Formula $G^{A}\triangleq\text{State}^{\text{Int},A}$ +\end_inset + +, +\begin_inset Formula $f^{:F^{B}\rightarrow G^{B}}=$ +\end_inset + + +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +fromCF +\end_layout + +\end_inset + +, and +\begin_inset Formula $g^{:A\rightarrow F^{B}}=h$ +\end_inset + +: +\begin_inset Formula +\begin{align*} + & \text{trav}_{L}^{G,A,B}(g\bef f)=\text{trav}_{L}^{F,A,B}(g)\bef f\\ +\text{or equivalently}:\quad & \text{trav}_{L}(h\bef\text{fromCF})=\text{trav}_{L}(h)\bef\text{fromCF}\quad. +\end{align*} + +\end_inset + +Statement +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Statement-constant-value-state-monad" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +(c) gives the formula +\begin_inset Formula $\text{run}_{\text{CFState}}=\text{fromCF}\bef r$ +\end_inset + +, so we write: +\begin_inset Formula +\[ +\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h)\bef\gunderline{\text{fromCF}\bef r}=\text{trav}_{L}(h)\bef\text{run}_{\text{CFState}}\quad. +\] + +\end_inset + +As +\begin_inset Formula $\text{run}_{\text{CFState}}$ +\end_inset + + is an applicative morphism, we may again use the applicative naturality + law: +\begin_inset Formula +\[ +\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h)\bef\text{run}_{\text{CFState}}=\text{trav}_{L}(h\bef\text{run}_{\text{CFState}})\quad. +\] + +\end_inset + +Now we recall the identity law +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:traverse-identity-law" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) and compute: +\begin_inset Formula +\begin{align*} + & h\bef\text{run}_{\text{CFState}}=a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\bef\text{run}_{\text{CFState}}=a\rightarrow a=\text{id}^{:A\rightarrow A}\quad,\\ + & \text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h\bef\text{run}_{\text{CFState}})=\text{trav}_{L}(\text{id})=\text{id}\quad. +\end{align*} + +\end_inset + + +\begin_inset Formula $\square$ +\end_inset + + +\end_layout + +\begin_layout Standard +The second property of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + + says that +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + + assigns different indices to each value of type +\begin_inset Formula $A$ +\end_inset + + stored inside a data structure of type +\begin_inset Formula $L^{A}$ +\end_inset + +. + This property does +\emph on +not +\emph default + seem to be provable using the two laws of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + +. + One reason is that an +\begin_inset Quotes eld +\end_inset + +indexing +\begin_inset Quotes erd +\end_inset + + function +\begin_inset Formula $f_{p}:\text{Int}\rightarrow A$ +\end_inset + + can be computed only by traversing the entire data structure +\begin_inset Formula $p$ +\end_inset + +. + In other words, +\begin_inset Formula $f$ +\end_inset + + is itself a result of a traversal operation. + We want to prove a property of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + that combines +\begin_inset Formula $f$ +\end_inset + + with another traversal ( +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + +) of the same initial data ( +\begin_inset Formula $p$ +\end_inset + +). + But there are no laws of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + that involve composition of traversals of the same initial container. + A new law of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + is necessary. + +\end_layout \begin_layout Standard -To make the definition +Such a law (involving inverse-order traversals) was first proposed in 2012. +\begin_inset Foot +status open + +\begin_layout Plain Layout +See +\family typewriter + +\begin_inset CommandInset href +LatexCommand href +target "https://www.cs.ox.ac.uk/jeremy.gibbons/publications/backwards.pdf" +literal "false" + +\end_inset + + +\end_layout + +\end_inset + + One year later, R. +\begin_inset space ~ +\end_inset + +Bird +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Richard Bird +\end_layout + +\end_inset + + et al. \begin_inset space ~ \end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:definition-of-zwi" -plural "false" -caps "false" -noprefix "false" +showed that the second property of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + +\end_inset + + can be derived for arbitrary polynomial functors +\begin_inset Formula $L$ +\end_inset + + without assuming any new laws of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + by using techniques motivated by dependent type theory. +\begin_inset Foot +status open + +\begin_layout Plain Layout +\begin_inset CommandInset label +LatexCommand label +name "fn:uitbaf" + +\end_inset + +See +\family typewriter + +\begin_inset CommandInset href +LatexCommand href +target "https://www.cs.ox.ac.uk/jeremy.gibbons/publications/uitbaf.pdf" +literal "false" + +\end_inset + + +\end_layout + +\end_inset + + Those techniques are beyond the scope of this book, as the required theory + is complicated but has limited practical use. + Because all polynomial functors are traversable (and no other functors + are), it is not as important to be able to characterize +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + solely via laws. + In practice, there is no uncertainty about how to implement a law-abiding + +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +traverse +\end_layout + +\end_inset + + correctly, for any given polynomial functor and any traversal order. + +\end_layout + +\begin_layout Standard +It will suffice for our purposes to use the following statement from Bird + et al.: +\end_layout + +\begin_layout Subsubsection +Statement +\begin_inset CommandInset label +LatexCommand label +name "subsec:Statement-Bird-representation-theorem-for-traversal" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Statement-Bird-representation-theorem-for-traversal" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Given a traversable functor +\begin_inset Formula $L$ +\end_inset + + and a value +\begin_inset Formula $p:L^{A}$ +\end_inset + +, there exists an integer +\begin_inset Formula $n\ge0$ +\end_inset + + and a function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +make[A] +\end_layout + +\end_inset + + with type signature: +\begin_inset Formula +\[ +\text{make}:\forall A.\,\underbrace{A\times A\times...\times A}_{n\text{ times}}\rightarrow L^{A}\quad, +\] \end_inset -) easier to work with, we denote: -\begin_inset Formula -\begin{align*} - & F^{A}\triangleq\text{State}^{\text{Int},A}=(\text{Int}\rightarrow A)\times(\text{Int}\rightarrow\text{Int})\quad,\\ - & g:A\rightarrow\text{State}^{\text{Int},A\times\text{Int}}\quad,\quad\quad g\triangleq a^{:A}\rightarrow(s^{:\text{Int}}\rightarrow a\times s)\times(s^{:\text{Int}}\rightarrow s+1)\quad,\\ - & r:\forall B.\,\text{State}^{\text{Int},B}\rightarrow B\quad,\quad\quad r\triangleq p^{:\text{Int}\rightarrow B}\times q^{:\text{Int}\rightarrow\text{Int}}\rightarrow p(0^{:\text{Int}})\quad. -\end{align*} +such that +\begin_inset Formula $p=\text{make}^{A}(a_{1}\times...\times a_{n})$ +\end_inset + with suitable values +\begin_inset Formula $a_{1}$ \end_inset -and get -\begin_inset Formula $\text{zwi}_{L}=\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef r$ +, ..., +\begin_inset Formula $a_{n}$ +\end_inset + + of type +\begin_inset Formula $A$ \end_inset . - Then we write: -\begin_inset Formula -\begin{align*} - & \text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef\gunderline{r\bef\pi_{1}^{\uparrow L}}\\ -\text{naturality of }r:\quad & =\gunderline{\text{trav}_{L}^{F,A,A\times\text{Int}}(g)\bef\pi_{1}^{\uparrow L\uparrow\text{State}}}\bef r\\ -\text{naturality of }\text{trav}_{L}:\quad & =\text{trav}_{L}^{F,A,A}(g\bef\pi_{1}^{\uparrow\text{State}})\bef r\quad. -\end{align*} + The function +\begin_inset listings +inline true +status open -\end_inset +\begin_layout Plain Layout + +make[A] +\end_layout -To compute -\begin_inset Formula $g\bef\pi_{1}^{\uparrow\text{State}}$ \end_inset -, we first express the lifting to + is natural in the type parameter \begin_inset listings inline true status open \begin_layout Plain Layout -State +A \end_layout \end_inset - as: +: \begin_inset Formula \[ -(f^{:A\rightarrow B})^{\uparrow\text{State}^{S,\bullet}}(p^{:S\rightarrow A}\times q^{:S\rightarrow S})=(p\bef f)\times q\quad. +\text{for any }f^{:A\rightarrow B}:\quad(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}\triangleright f^{\uparrow L}=(f(a_{1})\times...\times f(a_{n}))\triangleright\text{make}^{B}\quad. \] \end_inset -Then we get: -\begin_inset Formula -\begin{align*} - & g\bef\pi_{1}^{\uparrow\text{State}}:A\rightarrow\text{State}^{\text{Int},A}\quad,\\ - & g\bef\pi_{1}^{\uparrow\text{State}}=a^{:A}\rightarrow(s^{:\text{Int}}\rightarrow\pi_{1}(a\times s))\times(s^{:\text{Int}}\rightarrow s+1)\\ - & =a\rightarrow(s^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)=a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\quad. -\end{align*} - -\end_inset +The +\begin_inset listings +inline true +status open -Now we note that the sub-expression ( -\begin_inset Formula $\_^{:\text{Int}}\rightarrow a$ -\end_inset +\begin_layout Plain Layout -) is a constant function. - So, -\begin_inset Formula $g\bef\pi_{1}^{\uparrow\text{State}}$ -\end_inset +traverse +\end_layout - can be expressed as a function -\begin_inset Formula $h$ \end_inset - of type -\begin_inset Formula $A\rightarrow\text{CFState}^{\text{Int},A}$ + method of +\begin_inset Formula $L$ \end_inset - followed by + is expressed via \begin_inset listings inline true status open \begin_layout Plain Layout -fromCF +make \end_layout \end_inset -: + and the values +\begin_inset Formula $a_{1}$ +\end_inset + +, ..., +\begin_inset Formula $a_{n}$ +\end_inset + + as: \begin_inset Formula \begin{align*} - & h:A\rightarrow\text{CFState}^{\text{Int},A}=A\rightarrow(\_^{:\text{Int}}\rightarrow A)\times(\text{Int}\rightarrow\text{Int})\quad,\\ - & h\triangleq a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\quad,\quad\quad g\bef\pi_{1}^{\uparrow\text{State}}=h\bef\text{fromCF}\quad. + & \quad\text{for any }g^{:A\rightarrow F^{B}}:\quad\\ + & p\triangleright\text{trav}_{L}(g)=\big(\text{zip}_{L}(g(a_{1})\times\text{zip}_{L}(g(a_{2})\times...\times\text{zip}_{L}(g(a_{n-1})\times g(a_{n}))...)\big)\triangleright\text{restore}^{\uparrow F}\quad,\\ + & \quad\text{where we defined}:\quad\\ + & \text{restore}\triangleq b_{1}\times(b_{2}\times(...\times(b_{n-1}\times b_{n})...)\rightarrow\text{make}^{B}(b_{1}\times...\times b_{n})\quad. \end{align*} \end_inset @@ -29771,216 +30868,342 @@ fromCF \end_layout +\begin_layout Subparagraph +Proof +\end_layout + \begin_layout Standard -In this way, we have found that: -\begin_inset Formula -\[ -\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}^{\text{State}^{\text{Int},\bullet},A,A}(h\bef\text{fromCF})\bef r\quad. -\] +This is proved by Bird et al. +\begin_inset Foot +status open +\begin_layout Plain Layout +See Footnote +\begin_inset space ~ \end_inset -Since -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "fn:uitbaf" +plural "false" +caps "false" +noprefix "false" -fromCF +\end_inset + + on page +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand pageref +reference "fn:uitbaf" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. \end_layout \end_inset - is an applicative morphism, we can use the applicative naturality law + \begin_inset space ~ \end_inset -( +as the +\begin_inset Quotes eld +\end_inset + +representation theorem +\begin_inset Quotes erd +\end_inset + +. + +\begin_inset Formula $\square$ +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Statement +\begin_inset CommandInset label +LatexCommand label +name "subsec:Statement-polynomial-functors-Int-A" + +\end_inset + + \begin_inset CommandInset ref LatexCommand ref -reference "eq:traverse-applicative-naturality-law" +reference "subsec:Statement-polynomial-functors-Int-A" plural "false" caps "false" noprefix "false" \end_inset -) with -\begin_inset Formula $B\triangleq A$ + +\end_layout + +\begin_layout Standard +For any traversable functor +\begin_inset Formula $L$ \end_inset -, -\begin_inset Formula $F^{A}\triangleq\text{CFState}^{\text{Int},A}$ +, any type +\begin_inset Formula $A$ \end_inset -, -\begin_inset Formula $G^{A}\triangleq\text{State}^{\text{Int},A}$ +, and any value +\begin_inset Formula $p^{:L^{A}}$ \end_inset -, -\begin_inset Formula $f^{:F^{B}\rightarrow G^{B}}=$ +: +\end_layout + +\begin_layout Standard + +\series bold +(a) +\series default + There is a function +\begin_inset Formula $t_{p}:\text{Int}\rightarrow A$ \end_inset - + such that \begin_inset listings inline true status open \begin_layout Plain Layout -fromCF +zipWithIndex \end_layout \end_inset -, and -\begin_inset Formula $g^{:A\rightarrow F^{B}}=h$ -\end_inset - -: + satisfies: \begin_inset Formula \[ -\text{trav}_{L}^{G,A,B}(g\bef f)=\text{trav}_{L}^{F,A,B}(g)\bef f\quad\quad\text{or equivalently:}\quad\quad\text{trav}_{L}(h\bef\text{fromCF})=\text{trav}_{L}(h)\bef\text{fromCF}\quad. +p=p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright t_{p}^{\uparrow L}\quad. \] \end_inset -Statement + +\end_layout + +\begin_layout Standard + +\series bold +(b) +\series default + There exists an injective function of type +\begin_inset Formula $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$ +\end_inset + +. +\end_layout + +\begin_layout Subparagraph +Proof +\end_layout + +\begin_layout Standard + +\series bold +(a) +\series default + By Statement \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Statement-constant-value-state-monad" +reference "subsec:Statement-Bird-representation-theorem-for-traversal" plural "false" caps "false" noprefix "false" \end_inset -(c) gives the formula -\begin_inset Formula $\text{run}_{\text{CFState}}=\text{fromCF}\bef r$ +, there exist +\begin_inset Formula $a_{1}$ \end_inset -, so we write: +, ..., +\begin_inset Formula $a_{n}$ +\end_inset + + of type +\begin_inset Formula $A$ +\end_inset + + such that: \begin_inset Formula \[ -\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h)\bef\gunderline{\text{fromCF}\bef r}=\text{trav}_{L}(h)\bef\text{run}_{\text{CFState}}\quad. +p=(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}\quad. \] \end_inset -As -\begin_inset Formula $\text{run}_{\text{CFState}}$ +Then the definition of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +zipWithIndex +\end_layout + \end_inset - is an applicative morphism, we may again use the applicative naturality - law: + is evaluated to: +\begin_inset Formula +\[ +p\triangleright\text{zwi}_{L}=\big((a_{1}\times1^{:\text{Int}})\times(a_{2}\times2^{:\text{Int}})\times...\times(a_{n}\times n^{:\text{Int}})\big)\triangleright\text{make}^{A\times\text{Int}}\quad. +\] + +\end_inset + +By the naturality law of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +make +\end_layout + +\end_inset + +, we get: +\begin_inset Formula +\[ +p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}=\big(1^{:\text{Int}}\times2^{:\text{Int}}\times...\times n^{:\text{Int}}\big)\triangleright\text{make}^{\text{Int}}\quad. +\] + +\end_inset + +Now we define +\begin_inset Formula $t_{p}$ +\end_inset + + as a (partial) function of type +\begin_inset Formula $\text{Int}\rightarrow A$ +\end_inset + + such that \begin_inset Formula \[ -\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h)\bef\text{run}_{\text{CFState}}=\text{trav}_{L}(h\bef\text{run}_{\text{CFState}})\quad. +t_{p}(i)\triangleq a_{i}\quad,\quad i=1,2,...,n\quad. \] \end_inset -Now we recall the identity law -\begin_inset space ~ -\end_inset +We again use the naturality law of +\begin_inset listings +inline true +status open -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:traverse-identity-law" -plural "false" -caps "false" -noprefix "false" +\begin_layout Plain Layout + +make +\end_layout \end_inset -) and compute: + and prove the required property: \begin_inset Formula \begin{align*} - & h\bef\text{run}_{\text{CFState}}=a\rightarrow(\_^{:\text{Int}}\rightarrow a)\times(s^{:\text{Int}}\rightarrow s+1)\bef\text{run}_{\text{CFState}}=a\rightarrow a=\text{id}^{:A\rightarrow A}\quad,\\ - & \text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{trav}_{L}(h\bef\text{run}_{\text{CFState}})=\text{trav}_{L}(\text{id})=\text{id}\quad. + & p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright t_{p}^{\uparrow L}=\big(t_{p}(1)\times...\times t_{p}(n)\big)\triangleright\text{make}^{\text{Int}}\\ + & \quad=(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}=p\quad. \end{align*} \end_inset - -\begin_inset Formula $\square$ -\end_inset - \end_layout \begin_layout Standard -The second property of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -zipWithIndex -\end_layout +\series bold +(b) +\series default + Note that +\begin_inset Formula $p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}$ +\end_inset + is a value of type +\begin_inset Formula $L^{\text{Int}}$ \end_inset - does -\emph on -not -\emph default - seem to be provable using the laws of traverse; see Problem -\begin_inset space ~ +. + We can combine that function with +\begin_inset Formula $t_{p}$ \end_inset + and define a +\begin_inset Quotes eld +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "par:Problem-traverse-law" -plural "false" -caps "false" -noprefix "false" +tabulating +\begin_inset Quotes erd +\end_inset + function (denoted by +\begin_inset Formula $\text{tab}_{L}$ \end_inset -(b). - However, it appears to be natural to expect that -\begin_inset listings -inline true -status open +): +\begin_inset Formula +\begin{align*} + & \text{tab}_{L}^{A}:L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad,\\ + & \text{tab}_{L}^{A}\triangleq p^{:L^{A}}\rightarrow t_{p}\times(p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L})\quad. +\end{align*} -\begin_layout Plain Layout +\end_inset -zipWithIndex -\end_layout +Then the property of +\begin_inset Formula $\text{zwi}_{L}$ +\end_inset + + from +\series bold +(a) +\series default + is rewritten as: +\begin_inset Formula +\[ +\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})\overset{!}{=}\text{id}^{:L^{A}\rightarrow L^{A}}\quad. +\] \end_inset - assigns different indices to each value of type -\begin_inset Formula $A$ +So, the function +\begin_inset Formula $\text{tab}_{L}$ \end_inset - stored inside a data structure of type -\begin_inset Formula $L^{A}$ + is an injective function of type +\begin_inset Formula $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$ \end_inset . - Perhaps another law of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -traverse -\end_layout - + +\begin_inset Formula $\square$ \end_inset - is needed? + \end_layout \begin_layout Subsection @@ -30574,9 +31797,10 @@ sequence function defined as: \begin_inset Formula -\[ -\text{seq}_{L}^{F,A}:S^{F^{A},L^{P^{F^{A}}}}\rightarrow F^{S^{A,L^{P^{A}}}}\quad,\quad\quad\text{seq}_{L}^{F,A}\triangleq\big(\text{seq}_{P}^{F,A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{F,P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}\bef\text{seq2}_{S}^{F,A,L^{P^{A}}}\quad. -\] +\begin{align*} + & \text{seq}_{L}^{F,A}:S^{F^{A},L^{P^{F^{A}}}}\rightarrow F^{S^{A,L^{P^{A}}}}\quad,\\ + & \text{seq}_{L}^{F,A}\triangleq\big(\text{seq}_{P}^{F,A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{F,P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}\bef\text{seq2}_{S}^{F,A,L^{P^{A}}}\quad. +\end{align*} \end_inset @@ -30645,13 +31869,14 @@ noprefix "false" \end_inset -), write its two sides, omitting some type parameters for brevity: +), write its two sides: \begin_inset Formula \begin{align*} - & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ - & \quad=\big(\text{seq}_{P}^{F,G^{A}}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad,\\ + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\big(\text{seq}_{P}^{F,G^{A}}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\\ + & \quad\quad\quad\quad\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad,\\ & \text{seq}_{L}^{F\circ G,A}=\big(\text{seq}_{P}^{F\circ G,A}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F\circ G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F\circ G,A,L^{P^{A}}}\\ - & \quad=\big(\text{seq}_{P}^{F,G^{A}}\bef(\text{seq}_{P}^{G,A})^{\uparrow F}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,G^{P^{A}}}\bef(\overline{\text{seq}}_{L}^{G,P^{A}})^{\uparrow F}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\bef\big(\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad. + & \quad=\big(\text{seq}_{P}^{F,G^{A}}\bef(\text{seq}_{P}^{G,A})^{\uparrow F}\big)^{\uparrow L\uparrow S}\\ + & \quad\quad\quad\quad\bef\big(\overline{\text{seq}}_{L}^{F,G^{P^{A}}}\bef(\overline{\text{seq}}_{L}^{G,P^{A}})^{\uparrow F}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\bef\big(\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad. \end{align*} \end_inset @@ -30704,8 +31929,7 @@ sequence \begin{align*} \text{left-hand side}:\quad & \big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L}\bef\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S\uparrow F}}\\ \text{naturality law of }\text{seq2}_{S}:\quad & =\gunderline{\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L}\bef\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\\ -\text{composition under }^{\uparrow S}:\quad & =\big(\gunderline{\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\quad.\\ -\text{naturality law of }\overline{\text{seq}}_{L}:\quad & =\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}} +\text{composition under }^{\uparrow S}:\quad & =\big(\gunderline{\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\quad. \end{align*} \end_inset @@ -31411,330 +32635,347 @@ zip \begin_inset Formula $N$ \end_inset -. -\end_layout - -\begin_layout Standard -\begin_inset Float figure -wide false -sideways false -status open - -\begin_layout Plain Layout -\align center +.Note that the type \begin_inset listings -lstparams "frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm" -inline false +inline true status open \begin_layout Plain Layout -type Finite[N] = List[N] // A list of all possible values of type N. -\end_layout - -\begin_layout Plain Layout - -\end_layout - -\begin_layout Plain Layout - -object Finite { def apply[N: Finite]: Finite[N] = implicitly[Finite[N]] - } -\end_layout - -\begin_layout Plain Layout - +Sq \end_layout -\begin_layout Plain Layout +\end_inset -sealed abstract class SqSize[N: Finite, A] -\end_layout + sets the type parameter +\begin_inset listings +inline true +status open \begin_layout Plain Layout +N \end_layout -\begin_layout Plain Layout +\end_inset -final case class Matrix[N: Finite, A](byIndex: ((N, N)) => A) extends SqSize[N, - A] -\end_layout + in +\begin_inset listings +inline true +status open \begin_layout Plain Layout +SqSize[N, A] \end_layout -\begin_layout Plain Layout +\end_inset -final case class Next[N: Finite, A](next: SqSize[Option[N], A]) extends - SqSize[N, A] -\end_layout + as +\begin_inset listings +inline true +status open \begin_layout Plain Layout +N = Unit \end_layout -\begin_layout Plain Layout +\end_inset -type Sq[A] = SqSize[Unit, A] -\end_layout +. + This forces the type parameters +\begin_inset listings +inline true +status open \begin_layout Plain Layout +N \end_layout -\begin_layout Plain Layout +\end_inset -implicit val finiteUnit: Finite[Unit] = List(()) -\end_layout + in all of the +\begin_inset listings +inline true +status open \begin_layout Plain Layout +Next() \end_layout -\begin_layout Plain Layout +\end_inset -implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map( -Some(_)) -\end_layout + constructors to be +\begin_inset listings +inline true +status open \begin_layout Plain Layout +Unit \end_layout -\begin_layout Plain Layout +\end_inset -// Access the matrix element at zero-based index (i, j). -\end_layout + wrapped in a number of +\begin_inset listings +inline true +status open \begin_layout Plain Layout -def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { +Option \end_layout -\begin_layout Plain Layout +\end_inset - case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) -\end_layout + constructors. + All values of a type of this form can be enumerated explicitly. + However, the type +\begin_inset listings +inline true +status open \begin_layout Plain Layout - case Next(next) => access[Option[N], A](next, i, j) +SqSize[N, A] \end_layout -\begin_layout Plain Layout +\end_inset -} -\end_layout + does not ensure that +\begin_inset listings +inline true +status open \begin_layout Plain Layout +N \end_layout -\begin_layout Plain Layout +\end_inset -def size[N: Finite, A](s: SqSize[N, A]): Int = s match { -\end_layout + will be a type with a known finite number of values. + This problem prevents us from implementing the +\begin_inset listings +inline true +status open \begin_layout Plain Layout - case Matrix(_) => Finite[N].length +sequence \end_layout -\begin_layout Plain Layout +\end_inset - case Next(next) => size[Option[N], A](next) -\end_layout + method for our current definition of +\begin_inset listings +inline true +status open \begin_layout Plain Layout -} +Sq \end_layout -\begin_layout Plain Layout +\end_inset +. \end_layout -\begin_layout Plain Layout - -def toSeqSeq[N: Finite, A](s: SqSize[N, A]): Seq[Seq[A]] = { -\end_layout +\begin_layout Standard +A solution is to add a typeclass constraint (with a typeclass called +\begin_inset Quotes eld +\end_inset -\begin_layout Plain Layout - val length = size(s) -\end_layout +\begin_inset listings +inline true +status open \begin_layout Plain Layout - (0 until length).map(i => (0 until length).map(j => access(s, i, j))) +Finite \end_layout -\begin_layout Plain Layout +\end_inset -} -\end_layout -\begin_layout Plain Layout +\begin_inset Quotes erd +\end_inset -\end_layout +) on the type parameter +\begin_inset listings +inline true +status open \begin_layout Plain Layout -// Test: visualize the matrix defined previously by converting it to nested - lists. +N \end_layout -\begin_layout Plain Layout +\end_inset -scala> toSeqSeq(matrix2x2) -\end_layout +. + A suitable typeclass instance of +\begin_inset listings +inline true +status open \begin_layout Plain Layout -res1: List[List[Int]] = List(List(11, 12), List(21, 22)) +Finite[N] \end_layout -\begin_layout Plain Layout +\end_inset -\end_layout + contains a list of all values of type +\begin_inset listings +inline true +status open \begin_layout Plain Layout -def sequenceList[F[_]: Applicative : Functor, A](l: List[F[A]]): F[List[A]] - = l match { +N \end_layout -\begin_layout Plain Layout +\end_inset - case Nil => Applicative[F].pure(Nil) -\end_layout +: +\begin_inset listings +inline false +status open \begin_layout Plain Layout - case head :: tail => (head zip sequenceList(tail)).map { case (x, y) => - x +: y } +type Finite[N] = List[N] // A list of all possible values of type N. \end_layout -\begin_layout Plain Layout +\end_inset -} -\end_layout +We can implement functions that create typeclass instances automatically + for all the types we will actually use instead of the type parameter +\begin_inset listings +inline true +status open \begin_layout Plain Layout +N \end_layout -\begin_layout Plain Layout +\end_inset -def sequence[N: Finite, F[_]: Applicative : Functor, A](sq: SqSize[N, F[A]]): - F[SqSize[N, A]] = -\end_layout +, namely, the types +\begin_inset listings +inline true +status open \begin_layout Plain Layout - sq match { +Unit \end_layout -\begin_layout Plain Layout +\end_inset - case Matrix(byIndex) => -\end_layout +, +\begin_inset listings +inline true +status open \begin_layout Plain Layout - val allValuesF: List[F[((N, N), A)]] = for { +Option[Unit] \end_layout -\begin_layout Plain Layout +\end_inset - i <- Finite[N] -\end_layout +, +\begin_inset listings +inline true +status open \begin_layout Plain Layout - j <- Finite[N] +Option[Option[Unit]] \end_layout -\begin_layout Plain Layout +\end_inset - } yield byIndex((i, j)).map(a => ((i, j), a)) -\end_layout + and so on. + Suitable typeclass instances are defined inductively: +\begin_inset listings +inline false +status open \begin_layout Plain Layout +implicit val finiteUnit: Finite[Unit] = List(()) \end_layout \begin_layout Plain Layout - val fList: F[List[((N, N), A)]] = sequenceList(allValuesF) +implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map( +Some(_)) \end_layout -\begin_layout Plain Layout +\end_inset + - fList.map { values => \end_layout -\begin_layout Plain Layout +\begin_layout Standard +Using these definitions, we can now extract all values of type +\begin_inset Formula $A$ +\end_inset - val valuesMap: ((N, N)) => A = values.toMap.apply -\end_layout + from a value of type +\begin_inset Formula $N\times N\rightarrow A$ +\end_inset + +: +\begin_inset listings +inline false +status open \begin_layout Plain Layout - Matrix[N, A](valuesMap) +def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { \end_layout \begin_layout Plain Layout - } + case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) \end_layout \begin_layout Plain Layout - case Next(next) => sequence[Option[N], F, A](next).map(Next(_)) + case Next(next) => access[Option[N], A](next, i, j) \end_layout \begin_layout Plain Layout - } +} \end_layout \end_inset - -\end_layout - -\begin_layout Plain Layout -\begin_inset Caption Standard - -\begin_layout Plain Layout -Implementing +Let us test this code: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -sequence -\end_layout - -\end_inset - - for square matrices. -\begin_inset CommandInset label -LatexCommand label -name "fig:Full-code-implementing-traverse-for-square-matrix" - -\end_inset - - +scala> access(matrix2x2, 0, 1) \end_layout -\end_inset - +\begin_layout Plain Layout +res0: Int = 12 \end_layout \end_inset @@ -31743,409 +32984,319 @@ name "fig:Full-code-implementing-traverse-for-square-matrix" \end_layout \begin_layout Standard -Note that the type +Here is the complete code of \begin_inset listings inline true status open \begin_layout Plain Layout -Sq +sequence \end_layout \end_inset - sets the type parameter + for the type constructor \begin_inset listings inline true status open \begin_layout Plain Layout -N +Sq \end_layout \end_inset - in +: +\end_layout + +\begin_layout Standard \begin_inset listings -inline true +lstparams "frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm" +inline false status open \begin_layout Plain Layout -SqSize[N, A] +type Finite[N] = List[N] // A list of all possible values of type N. \end_layout -\end_inset +\begin_layout Plain Layout - as -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -N = Unit +object Finite { def apply[N: Finite]: Finite[N] = implicitly[Finite[N]] + } \end_layout -\end_inset +\begin_layout Plain Layout -. - This forces the type parameters -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -N +sealed abstract class SqSize[N: Finite, A] \end_layout -\end_inset +\begin_layout Plain Layout - in all of the -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -Next() +final case class Matrix[N: Finite, A](byIndex: ((N, N)) => A) extends SqSize[N, + A] \end_layout -\end_inset +\begin_layout Plain Layout - constructors to be -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -Unit +final case class Next[N: Finite, A](next: SqSize[Option[N], A]) extends + SqSize[N, A] \end_layout -\end_inset +\begin_layout Plain Layout - wrapped in a number of -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -Option +type Sq[A] = SqSize[Unit, A] \end_layout -\end_inset +\begin_layout Plain Layout - constructors. - All values of a type of this form can be enumerated explicitly. - However, the type -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -SqSize[N, A] +implicit val finiteUnit: Finite[Unit] = List(()) \end_layout -\end_inset +\begin_layout Plain Layout - does not ensure that -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -N +implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map( +Some(_)) \end_layout -\end_inset +\begin_layout Plain Layout - will be a type with a known finite number of values. - This problem prevents us from implementing the -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -sequence +// Access the matrix element at zero-based index (i, j). \end_layout -\end_inset +\begin_layout Plain Layout - method for our current definition of -\begin_inset listings -inline true -status open +def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { +\end_layout \begin_layout Plain Layout -Sq + case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) \end_layout -\end_inset +\begin_layout Plain Layout -. + case Next(next) => access[Option[N], A](next, i, j) \end_layout -\begin_layout Standard -A solution is to add a typeclass constraint (with a typeclass called -\begin_inset Quotes eld -\end_inset - - -\begin_inset listings -inline true -status open - \begin_layout Plain Layout -Finite +} \end_layout -\end_inset +\begin_layout Plain Layout +\end_layout -\begin_inset Quotes erd -\end_inset +\begin_layout Plain Layout -) on the type parameter -\begin_inset listings -inline true -status open +def size[N: Finite, A](s: SqSize[N, A]): Int = s match { +\end_layout \begin_layout Plain Layout -N + case Matrix(_) => Finite[N].length \end_layout -\end_inset +\begin_layout Plain Layout -. - A suitable typeclass instance of -\begin_inset listings -inline true -status open + case Next(next) => size[Option[N], A](next) +\end_layout \begin_layout Plain Layout -Finite[N] +} \end_layout -\end_inset +\begin_layout Plain Layout - contains a list of all values of type -\begin_inset listings -inline true -status open +\end_layout \begin_layout Plain Layout -N +def toSeqSeq[N: Finite, A](s: SqSize[N, A]): Seq[Seq[A]] = { \end_layout -\end_inset +\begin_layout Plain Layout -: -\begin_inset listings -inline false -status open + val length = size(s) +\end_layout \begin_layout Plain Layout -type Finite[N] = List[N] // A list of all possible values of type N. + (0 until length).map(i => (0 until length).map(j => access(s, i, j))) \end_layout -\end_inset +\begin_layout Plain Layout -We can implement functions that create typeclass instances automatically - for all the types we will actually use instead of the type parameter -\begin_inset listings -inline true -status open +} +\end_layout \begin_layout Plain Layout -N \end_layout -\end_inset +\begin_layout Plain Layout -, namely, the types -\begin_inset listings -inline true -status open +// Test: visualize matrix2x2 by converting it to nested lists. +\end_layout \begin_layout Plain Layout -Unit +scala> toSeqSeq(matrix2x2) \end_layout -\end_inset +\begin_layout Plain Layout -, -\begin_inset listings -inline true -status open +res1: List[List[Int]] = List(List(11, 12), List(21, 22)) +\end_layout \begin_layout Plain Layout -Option[Unit] \end_layout -\end_inset +\begin_layout Plain Layout -, -\begin_inset listings -inline true -status open +def sequenceList[F[_]: Applicative : Functor, A](l: List[F[A]]): F[List[A]] + = l match { +\end_layout \begin_layout Plain Layout -Option[Option[Unit]] + case Nil => Applicative[F].pure(Nil) \end_layout -\end_inset +\begin_layout Plain Layout - and so on. - Suitable typeclass instances are defined inductively: -\begin_inset listings -inline false -status open + case head :: tail => (head zip sequenceList(tail)).map { case (x, y) => + x +: y } +\end_layout \begin_layout Plain Layout -implicit val finiteUnit: Finite[Unit] = List(()) +} \end_layout \begin_layout Plain Layout -implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map( -Some(_)) \end_layout -\end_inset - +\begin_layout Plain Layout +def sequence[N: Finite, F[_]: Applicative : Functor, A](sq: SqSize[N, F[A]]): + F[SqSize[N, A]] = \end_layout -\begin_layout Standard -Using these definitions, we can now extract all values of type -\begin_inset Formula $A$ -\end_inset - - from a value of type -\begin_inset Formula $N\times N\rightarrow A$ -\end_inset +\begin_layout Plain Layout -: -\begin_inset listings -inline false -status open + sq match { +\end_layout \begin_layout Plain Layout -def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { + case Matrix(byIndex) => \end_layout \begin_layout Plain Layout - case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) + val allValuesF: List[F[((N, N), A)]] = for { \end_layout \begin_layout Plain Layout - case Next(next) => access[Option[N], A](next, i, j) + i <- Finite[N] \end_layout \begin_layout Plain Layout -} + j <- Finite[N] \end_layout -\end_inset +\begin_layout Plain Layout -Let us test this code: -\begin_inset listings -inline false -status open + } yield byIndex((i, j)).map(a => ((i, j), a)) +\end_layout \begin_layout Plain Layout -scala> access(matrix2x2, 0, 1) \end_layout \begin_layout Plain Layout -res0: Int = 12 + val fList: F[List[((N, N), A)]] = sequenceList(allValuesF) \end_layout -\end_inset - +\begin_layout Plain Layout + fList.map { values => \end_layout -\begin_layout Standard -Figure -\begin_inset space ~ -\end_inset - +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "fig:Full-code-implementing-traverse-for-square-matrix" -plural "false" -caps "false" -noprefix "false" + val valuesMap: ((N, N)) => A = values.toMap.apply +\end_layout -\end_inset +\begin_layout Plain Layout - shows the complete code of -\begin_inset listings -inline true -status open + Matrix[N, A](valuesMap) +\end_layout \begin_layout Plain Layout -sequence + } \end_layout -\end_inset +\begin_layout Plain Layout - for -\begin_inset listings -inline true -status open + case Next(next) => sequence[Option[N], F, A](next).map(Next(_)) +\end_layout \begin_layout Plain Layout -Sq + } \end_layout \end_inset -. - For testing (Figure -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "fig:Full-code-implementing-traverse-for-square-matrix-tests" -plural "false" -caps "false" -noprefix "false" -\end_inset +\end_layout -), we define a value +\begin_layout Standard +To test this code, we define a value \begin_inset listings inline true status open @@ -32190,10 +33341,10 @@ sequence \text{seq}_{\text{Sq}}\,(\text{matrix2x2List})=\big[\left|\begin{array}{cc} 0 & 1\\ 2 & 3 -\end{array}\right|,\left|\begin{array}{cc} +\end{array}\right|,\,\left|\begin{array}{cc} 10 & 11\\ 12 & 13 -\end{array}\right|,\left|\begin{array}{cc} +\end{array}\right|,\,\left|\begin{array}{cc} 100 & 101\\ 102 & 103 \end{array}\right|\big]\quad. @@ -32207,16 +33358,7 @@ This represents a kind of transposition operation for tensors of dimension \end_inset . -\end_layout - -\begin_layout Standard -\begin_inset Float figure -wide false -sideways false -status open - -\begin_layout Plain Layout -\align center + The test code is: \begin_inset listings lstparams "frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm" inline false @@ -32344,56 +33486,6 @@ res1: List[List[List[Int]]] = List(List(List(0, 1), List(2, 3)), List(List(10, \end_inset -\end_layout - -\begin_layout Plain Layout -\begin_inset Caption Standard - -\begin_layout Plain Layout -Tests for the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -sequence -\end_layout - -\end_inset - - method implemented in Figure -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "fig:Full-code-implementing-traverse-for-square-matrix" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -. -\begin_inset CommandInset label -LatexCommand label -name "fig:Full-code-implementing-traverse-for-square-matrix-tests" - -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\end_inset - - \end_layout \begin_layout Standard @@ -32429,6 +33521,8 @@ See, for example, the NDScala \family default library for Scala 3: +\family typewriter + \begin_inset CommandInset href LatexCommand href target "https://github.com/SciScala/NDScala" diff --git a/sofp-src/sofp-traversable.tex b/sofp-src/sofp-traversable.tex index 37afa267b..2e1efa40e 100644 --- a/sofp-src/sofp-traversable.tex +++ b/sofp-src/sofp-traversable.tex @@ -22,14 +22,15 @@ \subsection{From \texttt{reduce} and \texttt{foldLeft} to \texttt{foldMap} and \texttt{traverse}\label{subsec:From-reduce-and-foldleft-to-foldmap}} The type signatures of \lstinline!reduce! and \lstinline!foldLeft! -for a sequence of type \lstinline!Seq[A]! can be written as: +for a sequence of type \lstinline!Seq[A]! may be written as: \begin{lstlisting} def reduce[A](xs: Seq[A])(update: (A, A) => A): A def foldLeft[A, B](xs: Seq[A])(b0: B)(update: (B, A) => B): B \end{lstlisting} -\[ -\text{reduce}:\text{Seq}^{A}\rightarrow(A\times A\rightarrow A)\rightarrow A\quad,\quad\quad\text{foldLeft}:\text{Seq}^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad. -\] +\begin{align*} + & \text{reduce}:\text{Seq}^{A}\rightarrow(A\times A\rightarrow A)\rightarrow A\quad,\\ + & \text{foldLeft}:\text{Seq}^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad. +\end{align*} In \lstinline!foldLeft!, the accumulated result is of a different type ($B$) than the type of sequence elements ($A$). So, \lstinline!foldLeft! is a more general version of \lstinline!reduce!. We can implement @@ -313,13 +314,14 @@ \subsubsection{Example \label{subsec:Example-traverse-tree}\ref{subsec:Example-t } \end{lstlisting} In the code notation, this function looks like this: -\[ -\text{trav}\,(f^{:A\rightarrow F^{B}})\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{trav}\,(f^{:A\rightarrow F^{B}})\\ + & \triangleq\,\begin{array}{|c||c|} & F^{B+\text{T2}^{B}\times\text{T2}^{B}}\\ \hline A & f\bef(b^{:B}\rightarrow b+\bbnum 0^{:\text{T2}^{B}\times\text{T2}^{B}})^{\uparrow F}\\ \text{T2}^{A}\times\text{T2}^{A} & \big(\overline{\text{trav}}\,(f)\boxtimes\overline{\text{trav}}\,(f)\big)\bef\text{zip}_{F}\bef(l^{:\text{T2}^{B}}\times r^{:\text{T2}^{B}}\rightarrow\bbnum 0^{:B}+l\times r)^{\uparrow F} \end{array}\quad. -\] +\end{align*} The code first traverses the two sub-branches (using recursive calls to \lstinline!trav!) and then combines the resulting values. So, @@ -338,15 +340,15 @@ \subsubsection{Example \label{subsec:Example-traversal-perfect-shaped-tree}\ref{ \begin{lstlisting}[numbers=left] def trav[A, B, F[_]: Applicative : Functor](f: A => F[B])(t: PTree[A]): F[PTree[B]] = t match { case Leaf(a) => f(a).map(b => Leaf(b)) // Reproduce the Leaf structure under F. - case Branch(t) => ??? // Here t has type PTree[(A, A)]. + case Branch(p) => ??? // Here p has type PTree[(A, A)]. } \end{lstlisting} -In line 3, we have a pattern variable \lstinline!t! of type \lstinline!PTree[(A, A)]!, +In line 3, we have a pattern variable \lstinline!p! of type \lstinline!PTree[(A, A)]!, but we need to obtain a value of type \lstinline!F[Branch[B]]! in that scope. Since a \lstinline!Branch! contains a recursive instance of the type \lstinline!PTree!, it seems we need to use a recursive call of \lstinline!trav! here. However, we cannot apply \lstinline!trav(f)! -to \lstinline!t! because the types do not match. We will be able +to \lstinline!p! because the types do not match. We will be able to apply \lstinline!trav! if instead of \lstinline!f: A => F[B]! we had a function of type \lstinline!(A, A) => F[(B, B)]!. We can create such a function out of \lstinline!f! using $F$\textsf{'}s \lstinline!zip! @@ -356,14 +358,14 @@ \subsubsection{Example \label{subsec:Example-traversal-perfect-shaped-tree}\ref{ \end{lstlisting} So, we write: \begin{lstlisting} - case Branch(t) => trav { case (a1, a2) => f(a1) zip f(a2) }(t); ??? } // Have F[PTree[(B, B)]]. + case Branch(p) => trav { case (a1, a2) => f(a1) zip f(a2) }(p); ??? } // Have F[PTree[(B, B)]]. \end{lstlisting} We can now use $F$\textsf{'}s \lstinline!map! method to restore the \lstinline!Branch! structure under $F$. The complete code is: \begin{lstlisting} def trav[A, B, F[_]: Applicative : Functor](f: A => F[B])(t: PTree[A]): F[PTree[B]] = t match { case Leaf(a) => f(a).map(b => Leaf(b)) // Reproduce the Leaf structure under F. - case Branch(t) => (trav[(A, A), (B, B), F] { case (a1, a2) => f(a1) zip f(a2) }(t) + case Branch(p) => (trav[(A, A), (B, B), F] { case (a1, a2) => f(a1) zip f(a2) }(p) ).map(x => Branch(x)) // Reproduce the Branch structure under F. } \end{lstlisting} @@ -422,9 +424,10 @@ \subsection{Aggregating tree-like data by folding. Breadth-first traversal\label operation is the concatenation of lists. If we use \lstinline!foldMap! with the monoid \lstinline!M = List[A]! and the function \lstinline!f: A => List[A]! that creates a single-element list, we obtain a function \lstinline!toList! -that converts a tree \lstinline!T2[A]! into \lstinline!List[A]!: +that converts a tree \lstinline!T2[A]! into \lstinline!List[A]!, +given a \lstinline!Monoid! instance for \lstinline!List[A]!: \begin{lstlisting} -def toList[A]: T2[A] => List[A] = foldMap[A, List[A]](List(_)) // Need a Monoid instance for List[A]. +def toList[A]: T2[A] => List[A] = foldMap[A, List[A]](List(_)) \end{lstlisting} In the same way, we may implement \lstinline!toList: L[A] => List[A]! @@ -466,7 +469,7 @@ \subsection{Aggregating tree-like data by folding. Breadth-first traversal\label }{\footnotesize\par} \noindent ~~\lstinline!toList(!{\tiny{} \Tree[ 8 [ [ 3 5 ] 4 ] ] }\lstinline!)!{\small{}}\\ -{\small{}~~~ $=\left[8,3,5,4\right]$}{\small\par} +{\small{}~~~ $=\left[8,3,5,4\right]$}\\ Let us now implement another version of \lstinline!toList!, called \lstinline!toList2!, that performs the \emph{breadth-first} traversal @@ -505,7 +508,7 @@ \subsection{Aggregating tree-like data by folding. Breadth-first traversal\label nested lists in this way: \begin{lstlisting} def listMerge[A](l: List[List[A]], r: List[List[A]]): List[List[A]] = (l, r) match { - case (Nil, r) => r // Keep the elements from the longer list. + case (Nil, r) => r // Keep the elements from the longer list. case (l, Nil) => l case (lh :: lt, rh :: rt) => (lh ++ rh) :: listMerge(lt, rt) } @@ -599,11 +602,11 @@ \subsection{Decorating a tree. I. Depth-first traversal\label{subsec:Decorating- The code of \lstinline!zipWithIndexDF! will have the form: \begin{lstlisting} final case class St[A](run: Int => (A, Int)) // A State monad with internal state of type Int. - // Assume that we have defined Applicative and Functor instances for St. -def computeIndex[A]: A => St[(A, Int)] = ??? // Define the "decoration" function. +// Assume that we have defined Applicative and Functor instances for St. +def computeIndex[A]: A => St[(A, Int)] = ??? // Define the "decoration" function. def zipWithIndexDF[A](tree: T2[A]): T2[(A, Int)] = { val afterTraverse: St[T2[(A, Int)]] = trav[A, (A, Int), St](computeIndex)(tree) - afterTraverse.run(0)._1 // Run the State monad and get the result value. + afterTraverse.run(0)._1 // Run the State monad and get the result value. } \end{lstlisting} This will be a depth-first traversal if \lstinline!trav! is the function @@ -657,10 +660,10 @@ \subsection{Decorating a tree. II. Breadth-first traversal\label{subsec:Decorati represented by the following nested list: \begin{lstlisting} List( - List(), // No leaves at level 0. - List( Left(8) ), // One leaf at level 1. - List( Right(Right(4)) ), // One leaf at level 2. - List( Right(Left(Left(3))), Right(Left(Right(5))) ), // Two leaves at level 3. + List(), // No leaves at level 0. + List( Left(8) ), // One leaf at level 1. + List( Right(Right(4)) ), // One leaf at level 2. + List( Right(Left(Left(3))), Right(Left(Right(5))) ), // Two leaves at level 3. ) \end{lstlisting} This data structure makes it easy to iterate over the leaf values @@ -686,9 +689,9 @@ \subsection{Decorating a tree. II. Breadth-first traversal\label{subsec:Decorati The tree descriptor for the tree \lstinline!t2! shown above will then look like this: \begin{lstlisting} -val td2: TD[Int] = More(List(), More( // No leaves at level 0. - List( Left(8) ), More( // The leaf at level 1. - List( Right(Right(4)) ), Last( // The leaf at level 2. +val td2: TD[Int] = More(List(), More( // No leaves at level 0. + List( Left(8) ), More( // One leaf at level 1. + List( Right(Right(4)) ), Last( // One leaf at level 2. List( Right(Left(Left(3))), Right(Left(Right(5))) ), // Two leaves at level 3. )))) \end{lstlisting} @@ -713,7 +716,7 @@ \subsection{Decorating a tree. II. Breadth-first traversal\label{subsec:Decorati Begin implementing the first function by pattern matching: \begin{lstlisting}[numbers=left] def t2ToTD[A]: T2[A] => TD[A] = { - case Leaf(a) => Last(List(a)) // A leaf at level 0. + case Leaf(a) => Last(List(a)) // One leaf at level 0. case Branch(l, r) => ( t2ToTD(l), t2ToTD(r) ); ??? // How to combine the subtrees? } \end{lstlisting} @@ -926,7 +929,7 @@ \subsection{Decorating a tree. II. Breadth-first traversal\label{subsec:Decorati \begin{lstlisting} def zipWithIndexBF[A](tree: T2[A]): T2[(A, Int)] = { val afterTraverse: St[T2[(A, Int)]] = travBF[A, (A, Int), St](computeIndex)(tree) - afterTraverse.run(0)._1 // Run the State monad and get the result value. + afterTraverse.run(0)._1 // Run the State monad and get the result value. } scala> zipWithIndexBF(t2) @@ -1061,8 +1064,8 @@ \subsection{Tasks that cannot be performed via \texttt{traverse}\label{subsec:Ta such a computation is \textsf{``}pretty-printing\textsf{''} that converts trees into a text form. In the \LaTeX{} format used to typeset this book, the tree {\tiny{} \Tree[ 8 [ [ 3 5 ] 4 ] ] } is represented by the text -string \lstinline!"\Tree[ 8 [ [ 3 5 ] 4 ] ]"!. We may write the following -code for converting trees to this format: +string \lstinline!"\Tree[ 8 [ [ 3 5 ] 4 ] ]"!. The following code +converts trees into the \LaTeX{} format: \begin{lstlisting} def printLaTeX[A](t: T2[A])(toString: A => String): String = { def printLaTeXSubtree: T2[A] => String = { @@ -1604,7 +1607,7 @@ \subsubsection{Example \label{subsec:Example-unfold-tree-evenodd}\ref{subsec:Exa \end{lstlisting} The implementation of \lstinline!evenOdd! is now complete. To test: -\begin{wrapfigure}{l}{0.74\columnwidth}% +\begin{wrapfigure}{l}{0.84\columnwidth}% \vspace{-0.95\baselineskip} \begin{lstlisting} scala> evenOdd(3) @@ -1614,16 +1617,17 @@ \subsubsection{Example \label{subsec:Example-unfold-tree-evenodd}\ref{subsec:Exa \vspace{0\baselineskip} \end{wrapfigure}% -\noindent ~{\tiny{}\Tree[ 3 [ [ 1 0 ] 2 ] ]} +\noindent \vspace{0.3\baselineskip} + {\tiny{}\Tree[ 3 [ [ 1 0 ] 2 ] ]}\\ \noindent $\square$ The kind of reasoning shown in Examples~\ref{subsec:Example-unfold-list}\textendash \ref{subsec:Example-unfold-tree-evenodd} -is called \textbf{co-induction}\index{co-induction}. It is related -to mathematical induction but is significantly different from the -reasoning required to write the code for a folding operation (which -is directly modeled on induction). In co-induction, the base cases -are not at the beginning of the computation but \textsf{``}in the future\textsf{''}. +is known as reasoning by \textbf{co-induction}\index{co-induction}. +It is related to mathematical induction but is significantly different +from the reasoning required to write the code for a folding operation +(which is directly modeled on induction). In co-induction, the base +cases are not at the beginning of the computation but \textsf{``}in the future\textsf{''}. Note that \lstinline!unfold(f)(z)! will call itself whenever the value $f(z)$ of type $S^{A,Z}$ contains additional values of type $Z$. The programmer must carefully choose a suitable type $Z$ and @@ -1658,7 +1662,7 @@ \subsubsection{Example \label{subsec:Example-unfold-tree-evenodd}\ref{subsec:Exa $f:Z\rightarrow S^{A,Z}$ because the recursive evaluation of $f$ at the branches is always delayed. For instance, \lstinline!unfold! can generate a value of type $L^{A}$ whose tree structure has the -form {\tiny{}\Tree[ 1 [ 2 [3 ... ] ] ]} with unbounded size: +form {\tiny{}\Tree[ 1 [ 2 [3 ... ] ] ]} with unbounded size:\vspace{0.6\baselineskip} \begin{lstlisting} type S[A, R] = Either[A, Unit => (R, R)] @@ -1696,7 +1700,7 @@ \subsubsection{Example \label{subsec:Example-unfold-tree-evenodd}\ref{subsec:Exa at depth $4$. The result is a finite tree of type \lstinline!T2[Int]!, where the unevaluated part of the tree is shown as \textsf{``}\lstinline!-1!\textsf{''}: -\begin{wrapfigure}{l}{0.65\columnwidth}% +\begin{wrapfigure}{l}{0.82\columnwidth}% \vspace{-0.95\baselineskip} \begin{lstlisting} scala> toT2(maxDepth = 3, default = -1)(tree1toInf) @@ -1760,7 +1764,7 @@ \subsection{Recursion schemes. III. Traversing operations} the \lstinline!State! monad as the functor $F$: \begin{lstlisting} final case class St[A](run: Int => (A, Int)) { // A State monad with internal state of type Int. - import io.chymyst.ch.implement // Implement the monad methods automatically. + import io.chymyst.ch.implement // Derive these methods automatically from types. def flatMap[B](f: A => St[B]): St[B] = implement def map[B](f: A => B): St[B] = implement } @@ -1797,7 +1801,7 @@ \subsection{Recursion schemes. III. Traversing operations} \lstinline!t2! used earlier in Sections~\ref{subsec:Decorating-a-tree-breadth-first-traversal} and~\ref{subsec:Tasks-not-implementable-via-traverse}: -\begin{wrapfigure}{l}{0.7\columnwidth}% +\begin{wrapfigure}{l}{0.78\columnwidth}% \vspace{-0.75\baselineskip} \begin{lstlisting} scala> zipWithDepth(t2) @@ -1924,7 +1928,8 @@ \subsection{Equivalence of \texttt{reduce}, \texttt{foldLeft}, \texttt{foldMap}, def toList[A]: L[A] => List[A] \end{lstlisting} \begin{align*} - & \text{foldLeft}_{L}:L^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad,\quad\quad\text{foldMap}_{L}:(A\rightarrow M)\rightarrow L^{A}\rightarrow M\quad,\\ + & \text{foldLeft}_{L}:L^{A}\rightarrow B\rightarrow(B\times A\rightarrow B)\rightarrow B\quad,\\ + & \text{foldMap}_{L}:(A\rightarrow M)\rightarrow L^{A}\rightarrow M\quad,\\ & \text{reduceE}_{L}:L^{M}\rightarrow M\quad,\quad\quad\text{toList}_{L}:L^{A}\rightarrow\text{List}^{A}\quad. \end{align*} We will now show that these four functions are equivalent, assuming @@ -2015,8 +2020,8 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r \[ \text{foldFn}:L^{B\rightarrow B}\rightarrow B\rightarrow B\quad, \] -as long as \lstinline!foldLeft! satisfies the naturality law with -respect to its type parameter $A$. +as long as \lstinline!foldLeft! obeys the naturality law with respect +to its type parameter $A$. \textbf{(c)} The functions \lstinline!foldFn! and \lstinline!reduceE! are equivalent as long as \lstinline!foldFn! obeys the laws~(\ref{eq:foldFn-first-special-law}) @@ -2034,7 +2039,7 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r \subparagraph{Proof} \textbf{(a)} The equivalence of \lstinline!foldMap! and \lstinline!reduceE! -follows from Statement~\ref{subsec:Statement-tr-equivalent-to-ftr} +can be derived from Statement~\ref{subsec:Statement-tr-equivalent-to-ftr} if we assume that \lstinline!foldMap! satisfies the naturality law with respect to the type parameter $A$. To prove that equivalence, we just need to set $F^{A}\triangleq L^{A}$, $G^{B}\triangleq M$, @@ -2048,7 +2053,8 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r to what was done in Section~\ref{subsec:From-reduce-and-foldleft-to-foldmap}). The result is a function we denote by \lstinline!fldl!: \begin{align*} - & \text{fldl}:(A\rightarrow B\rightarrow B)\rightarrow L^{A}\rightarrow B\rightarrow B\quad,\quad\quad\text{fldl}\,(u^{:A\rightarrow B\rightarrow B})(p^{:L^{A}})(z^{:B})\triangleq\text{foldLeft}\,(p)(z)(\tilde{u})\quad,\\ + & \text{fldl}:(A\rightarrow B\rightarrow B)\rightarrow L^{A}\rightarrow B\rightarrow B\quad,\\ + & \text{fldl}\,(u^{:A\rightarrow B\rightarrow B})(p^{:L^{A}})(z^{:B})\triangleq\text{foldLeft}\,(p)(z)(\tilde{u})\quad,\\ & \text{where we defined}:\quad\tilde{u}^{:B\times A\rightarrow B}\triangleq b^{:B}\times a^{:A}\rightarrow u\left(a\right)(b)\quad. \end{align*} The function \lstinline!fldl! is equivalent to \lstinline!foldLeft! @@ -2088,8 +2094,7 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r \begin{equation} \text{inMF}\,(m)(e_{M})=e_{M}\oplus m=m\quad.\label{eq:identity-law-of-inMF} \end{equation} - -The function \lstinline!inMF! is a monoid morphism because the two +The function \lstinline!inMF! is a monoid morphism since the two laws of Definition~\ref{subsec:Definition-monoid-morphism} hold: \begin{align*} & \text{inMF}\,(e_{M})=n^{:M}\rightarrow n\oplus_{M}e_{M}=n^{:M}\rightarrow n=\text{id}^{:M\rightarrow M}=e_{_{\text{MF}^{M}}}\quad,\\ @@ -2154,9 +2159,11 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r and then define a new \lstinline!reduceE!$^{\prime}$ via Eq.~(\ref{eq:reduceE-via-foldFn}). We need to show that \lstinline!reduceE!$^{\prime}=$ \lstinline!reduceE!: \begin{align*} -{\color{greenunder}\text{expect to equal }\text{reduceE}\left(p\right):}\quad & \text{reduceE}^{\prime}(p^{:L^{M}})=\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})=\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ +{\color{greenunder}\text{expect to equal }\text{reduceE}\left(p\right):}\quad & \text{reduceE}^{\prime}(p^{:L^{M}})=\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ + & =\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{M})\\ {\color{greenunder}\text{rewrite using }\triangleright\text{-notation}:}\quad & =e_{M}\triangleright\big(p\triangleright\gunderline{\text{inMF}^{\uparrow L}\bef\text{reduceE}}\big)\\ -{\color{greenunder}\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:}\quad & =e_{M}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)=\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{M})}\\ +{\color{greenunder}\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:}\quad & =e_{M}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)\\ + & =\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{M})}\\ {\color{greenunder}\text{use Eq.~(\ref{eq:identity-law-of-inMF})}:}\quad & =p\triangleright\text{reduceE}=\text{reduceE}\,(p)\quad. \end{align*} @@ -2165,9 +2172,11 @@ \subsubsection{Statement \label{subsec:Statement-foldleft-foldmap-equivalence}\r and~(\ref{eq:foldFn-second-special-law}). To verify that the law~(\ref{eq:foldFn-first-special-law}) holds: \begin{align*} -{\color{greenunder}\text{expect to equal }\text{foldFn}^{B}(p):}\quad & \text{foldFn}^{B\rightarrow B}(p^{:L^{B\rightarrow B}}\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})=\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ +{\color{greenunder}\text{expect to equal }\text{foldFn}^{B}(p):}\quad & \text{foldFn}^{B\rightarrow B}(p^{:L^{B\rightarrow B}}\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ + & =\text{reduceE}\,(p\triangleright\text{inMF}^{\uparrow L})(e_{\text{MF}})\\ & =e_{\text{MF}}\triangleright(p\triangleright\gunderline{\text{inMF}^{\uparrow L}\bef\text{reduceE}})\\ -{\color{greenunder}\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:}\quad & =e_{\text{MF}}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)=\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{\text{MF}})}\\ +{\color{greenunder}\text{use Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE-inMF})}:}\quad & =e_{\text{MF}}\triangleright\big(p\triangleright\text{reduceE}\bef\text{inMF}\big)\\ + & =\gunderline{\text{inMF}}\,(p\triangleright\text{reduceE})\gunderline{(e_{\text{MF}})}\\ {\color{greenunder}\text{use Eq.~(\ref{eq:identity-law-of-inMF})}:}\quad & =p\triangleright\text{reduceE}=\text{reduceE}^{B\rightarrow B}(p)=\text{foldFn}^{B}(p)\quad. \end{align*} @@ -2209,7 +2218,7 @@ \subsubsection{Statement \label{subsec:relational-property-for-foldFn}\ref{subse satisfies the law~(\ref{eq:foldFn-first-special-law}): \begin{align} & \phi\,(p^{:L^{E^{A}}})=\phi\,(p\triangleright\text{inF}^{\uparrow L})(\text{id}^{:A\rightarrow A})\quad,\label{eq:first-special-law-of-phi}\\ -{\color{greenunder}\text{where we defined}:}\quad & \quad\text{inF}:E^{A}\rightarrow E^{A}\rightarrow E^{A}\quad,\quad\quad\text{inF}\triangleq h^{:A\rightarrow A}\rightarrow k^{:A\rightarrow A}\rightarrow k\bef h\quad.\nonumber +{\color{greenunder}\text{where we defined}:}\quad & \quad\text{inF}:E^{A}\rightarrow E^{A}\rightarrow E^{A}\quad,\quad\text{inF}\triangleq h^{:A\rightarrow A}\rightarrow k^{:A\rightarrow A}\rightarrow k\bef h\quad.\nonumber \end{align} \textbf{(b)} Any fully parametric function $\text{foldFn}:\forall A.\,L^{E^{A}}\rightarrow E^{A}$ @@ -2299,8 +2308,10 @@ \subsubsection{Statement \label{subsec:relational-property-for-foldFn}\ref{subse We simplify separately each side of this equation and find that they are equal: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & h^{:A\rightarrow A}\rightarrow f\bef h=h\rightarrow(k\rightarrow\gunderline{k(a_{0}))\bef h}=h\rightarrow k\rightarrow h(k(a_{0}))\quad,\\ -{\color{greenunder}\text{right-hand side}:}\quad & \gunderline{\text{inF}}\bef(g^{:B\rightarrow B}\rightarrow g\bef\gunderline f)=(h\rightarrow k\rightarrow k\bef h)\bef(g\rightarrow g\bef(k\rightarrow k(a_{0}))\\ +{\color{greenunder}\text{left-hand side}:}\quad & h^{:A\rightarrow A}\rightarrow f\bef h=h\rightarrow(k\rightarrow\gunderline{k(a_{0}))\bef h}\\ + & \quad=h\rightarrow k\rightarrow h(k(a_{0}))\quad,\\ +{\color{greenunder}\text{right-hand side}:}\quad & \gunderline{\text{inF}}\bef(g^{:B\rightarrow B}\rightarrow g\bef\gunderline f)\\ + & \quad=(h\rightarrow k\rightarrow k\bef h)\bef(g\rightarrow g\bef(k\rightarrow k(a_{0}))\\ {\color{greenunder}\text{compute composition}:}\quad & \quad=h\rightarrow(k\rightarrow k\bef h)\bef(k\rightarrow k(a_{0}))=h\rightarrow k\rightarrow\gunderline{(k\bef h)(a_{0})}\\ & \quad=h\rightarrow k\rightarrow h(k(a_{0})\quad. \end{align*} @@ -2333,23 +2344,27 @@ \subsubsection{Statement \label{subsec:relational-property-for-foldFn}\ref{subse \[ A\triangleq N\quad,\quad\quad B\triangleq M\quad,\quad\quad x^{:L^{N\rightarrow N}}\triangleq p\triangleright f^{\uparrow L}\triangleright\text{inMF}^{\uparrow L}\quad,\quad\quad y^{:L^{M\rightarrow M}}\triangleq p\triangleright\text{inMF}^{\uparrow L}\quad. \] -Before we can use Eq.~(\ref{eq:strong-dinaturality-law-of-phi-with-f}), +In order to use Eq.~(\ref{eq:strong-dinaturality-law-of-phi-with-f}), we need to verify that its precondition is satisfied: -\[ -x\triangleright(h\rightarrow f\bef h)^{\uparrow L}=p\triangleright\big(f\bef\text{inMF}\bef(h\rightarrow f\bef h)\big)^{\uparrow L}\overset{?}{=}y\triangleright(g\rightarrow g\bef f)^{\uparrow L}=p\triangleright\big(\text{inMF}\bef(g\rightarrow g\bef f)\big)^{\uparrow L}\quad. -\] +\begin{align*} + & x\triangleright(h\rightarrow f\bef h)^{\uparrow L}=p\triangleright\big(f\bef\text{inMF}\bef(h\rightarrow f\bef h)\big)^{\uparrow L}\\ + & \quad\overset{?}{=}y\triangleright(g\rightarrow g\bef f)^{\uparrow L}=p\triangleright\big(\text{inMF}\bef(g\rightarrow g\bef f)\big)^{\uparrow L}\quad. +\end{align*} To show that this equation holds, we compare separately the lifted functions that are applied to $p$: \begin{align*} - & f\bef\text{inMF}\bef(h\rightarrow f\bef h)=\big(m^{:M}\rightarrow n^{:N}\rightarrow n\oplus_{N}f(m)\big)\bef(h\rightarrow f\bef h)=m^{:M}\rightarrow l^{:M}\rightarrow f(l)\oplus_{N}f(m)\quad,\\ - & \text{inMF}\bef(g\rightarrow g\bef f)=(m^{:M}\rightarrow l^{:M}\rightarrow l\oplus_{M}m)\bef(g\rightarrow g\bef f)=m^{:M}\rightarrow l^{:M}\rightarrow f(l\oplus_{M}m)\quad. + & f\bef\text{inMF}\bef(h\rightarrow f\bef h)=\big(m^{:M}\rightarrow n^{:N}\rightarrow n\oplus_{N}f(m)\big)\bef(h\rightarrow f\bef h)\\ + & \quad=m^{:M}\rightarrow l^{:M}\rightarrow f(l)\oplus_{N}f(m)\quad,\\ + & \text{inMF}\bef(g\rightarrow g\bef f)=(m^{:M}\rightarrow l^{:M}\rightarrow l\oplus_{M}m)\bef(g\rightarrow g\bef f)\\ + & \quad=m^{:M}\rightarrow l^{:M}\rightarrow f(l\oplus_{M}m)\quad. \end{align*} The two functions are equal because of the composition law of the monoid morphism $f$. So, the precondition of Eq.~(\ref{eq:strong-dinaturality-law-of-phi-with-f}) holds, and we may use its conclusion: -\[ -f\bef\text{foldFn}\,(x)\overset{!}{=}\text{foldFn}(y)\bef f\quad\text{or equivalently:}\quad\text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})\bef f=f\bef\text{foldFn}(p\triangleright f^{\uparrow L}\bef\text{inMF}^{\uparrow L}). -\] +\begin{align*} + & f\bef\text{foldFn}\,(x)\overset{!}{=}\text{foldFn}(y)\bef f\\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{foldFn}\,(p\triangleright\text{inMF}^{\uparrow L})\bef f=f\bef\text{foldFn}(p\triangleright f^{\uparrow L}\bef\text{inMF}^{\uparrow L}). +\end{align*} This gives the law~(\ref{eq:foldFn-second-special-law}) if we use $f$\textsf{'}s monoid morphism identity law: $e_{M}\triangleright f=e_{N}$. @@ -2373,13 +2388,14 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref case head :: tail => head |+| reduceList(tail) } \end{lstlisting} -\[ -\text{reduceList}^{M}:\text{List}^{M}\rightarrow M\quad,\quad\quad\text{reduceList}\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{reduceList}^{M}:\text{List}^{M}\rightarrow M\quad,\\ + & \text{reduceList}\triangleq\,\begin{array}{|c||c|} & M\\ \hline \bbnum 1 & \_\rightarrow e_{M}\\ M\times\text{List}^{M} & h^{:M}\times t^{:\text{List}^{M}}\rightarrow h\oplus_{M}\overline{\text{reduceList}}\left(t\right) \end{array}\quad. -\] +\end{align*} \subparagraph{Proof} @@ -2390,11 +2406,12 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref f^{\uparrow\text{List}}\bef\text{reduceList}=\text{reduceList}\bef f\quad. \] This law assumes that $f^{:M\rightarrow N}$ is a monoid morphism -between two monoids $M$ and $N$. +between monoids $M$ and $N$. Simplify the left-hand side of the law: \begin{align*} - & f^{\uparrow\text{List}}\bef\text{reduceList}=\,\begin{array}{|c||cc|} + & f^{\uparrow\text{List}}\bef\text{reduceList}\\ + & =\,\begin{array}{|c||cc|} & \bbnum 1 & N\times\text{List}^{N}\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ M\times\text{List}^{M} & \bbnum 0 & f\boxtimes f^{\uparrow\text{List}} @@ -2403,7 +2420,7 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref \hline \bbnum 1 & \_\rightarrow e_{N}\\ N\times\text{List}^{N} & h\times t\rightarrow h\oplus_{N}(t\triangleright\overline{\text{reduceList}}) \end{array}\\ - & =\,\begin{array}{|c||c|} + & =\,\,\begin{array}{|c||c|} & N\\ \hline \bbnum 1 & \_\rightarrow e_{N}\\ M\times\text{List}^{M} & h\times t\rightarrow f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}}) @@ -2416,7 +2433,8 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref \] The bottom-row expression in the last matrix is then rewritten to: \begin{align*} - & f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}})=f(h)\oplus_{N}f(\overline{\text{reduceList}}\left(t\right))\\ + & f(h)\oplus_{N}(t\triangleright f^{\uparrow\text{List}}\bef\overline{\text{reduceList}})\\ + & =f(h)\oplus_{N}f(\overline{\text{reduceList}}\left(t\right))\\ {\color{greenunder}\text{monad morphism law}:}\quad & =f\big(h\oplus_{M}\overline{\text{reduceList}}\left(t\right)\big)\quad. \end{align*} Using the monad morphism identity law ($f(e_{M})=e_{N}$), we find: @@ -2444,7 +2462,8 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref To show that \lstinline!reduceE!$^{\prime}=$ \lstinline!reduceE!, we write: \begin{align*} - & \text{reduceE}^{\prime}=\text{toList}\bef\text{reduceList}=\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{M}}}\bef\text{reduceList}\\ + & \text{reduceE}^{\prime}=\text{toList}\bef\text{reduceList}\\ + & =\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{M}}}\bef\text{reduceList}\\ {\color{greenunder}\text{Eq.~(\ref{eq:monoidal-naturality-law-of-reduceE}) with }N\triangleq\text{List}^{A}:}\quad & =\text{reduceE}^{M}\bef\text{pu}_{\text{List}}\bef\text{reduceList}\quad. \end{align*} It remains to show that the composition $\text{pu}_{\text{List}}\bef\text{reduceList}$ @@ -2478,7 +2497,8 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref To show that \lstinline!toList!$^{\prime}=$ \lstinline!toList!, we write: \begin{align*} - & \text{toList}^{\prime}=\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{A}}=\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{toList}}\bef\text{reduceList}^{\text{List}^{A}}\\ + & \text{toList}^{\prime}=\text{pu}_{\text{List}}^{\uparrow L}\bef\text{reduceE}^{\text{List}^{A}}\\ + & =\gunderline{\text{pu}_{\text{List}}^{\uparrow L}\bef\text{toList}}\bef\text{reduceList}^{\text{List}^{A}}\\ {\color{greenunder}\text{naturality of }\text{toList}:}\quad & =\text{toList}\bef\text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}\quad. \end{align*} It remains to show that the composition $\text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}$ @@ -2489,12 +2509,12 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref We use the definition of \lstinline!reduceList[M]! and set \lstinline!M! to the monoid type \lstinline!List[A]!: \begin{align*} - & \text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}\\ - & =\,\begin{array}{|c||cc|} + & \text{pu}_{\text{List}}^{\uparrow\text{List}}\bef\text{reduceList}^{\text{List}^{A}}=\,\begin{array}{|c||cc|} & \bbnum 1 & \text{List}^{M}\times\text{List}^{\text{List}^{M}}\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ M\times\text{List}^{M} & \bbnum 0 & h\times t\rightarrow\text{pu}_{\text{List}}(h)\times(t\triangleright\text{pu}_{\text{List}}^{\uparrow\text{List}}) -\end{array}\,\bef\,\begin{array}{|c||c|} +\end{array}\\ + & \quad\quad\quad\bef\,\begin{array}{|c||c|} & \text{List}^{M}\\ \hline \bbnum 1 & \_\rightarrow1+\bbnum 0\\ \text{List}^{M}\times\text{List}^{\text{List}^{M}} & h\times t\rightarrow h\pplus\overline{\text{reduceList}}\left(t\right) @@ -2506,7 +2526,7 @@ \subsubsection{Statement \label{subsec:Statement-reduceE-toList-equivalence}\ref \end{array}\quad. \end{align*} By the inductive assumption, a recursive call to \lstinline!reduceList! -already satisfies Eq.~(\ref{eq:identity-for-reduceList-and-pure}): +already obeys Eq.~(\ref{eq:identity-for-reduceList-and-pure}): \[ t\triangleright\gunderline{\text{pu}_{\text{List}}^{\uparrow\text{List}}\triangleright\overline{\text{reduceList}}}=t\triangleright\text{id}=t\quad. \] @@ -2570,7 +2590,7 @@ \subsection{The missing laws of \texttt{foldMap} and \texttt{reduce}} returns an empty list. For \textsf{``}containers\textsf{''} that store some values of type \lstinline!A!, this implementation (although it is fully parametric) would be unacceptable since it loses information: \lstinline!toList(x)! -always ignores its argument \lstinline!x!. +always ignores \lstinline!x!. To prohibit such implementations, we would like to impose a law that holds only when \lstinline!toList! extracts every value of type \lstinline!A! @@ -2708,20 +2728,12 @@ \subsection{All polynomial functors are foldable} If $K$ and $L$ are foldable functors, we define the co-product $M^{A}\triangleq K^{A}+L^{A}$ and the corresponding function $\text{toList}_{M}:K^{A}+L^{A}\rightarrow\text{List}^{A}$ as: - -\begin{wrapfigure}{l}{0.6\columnwidth}% -\vspace{-0.25\baselineskip} \begin{lstlisting} def toList_M[A]: Either[K[A], L[A]] => List[A] = { case Left(p) => toList_K(p) case Right(q) => toList_L(q) } \end{lstlisting} - -\vspace{-1\baselineskip} -\end{wrapfigure}% - -\noindent ~\vspace{-2\baselineskip} \[ \text{toList}_{M}\triangleq\,\begin{array}{|c||c|} & \text{List}^{A}\\ @@ -2729,7 +2741,6 @@ \subsection{All polynomial functors are foldable} L^{A} & \text{toList}_{L} \end{array}\quad. \] -\vspace{-0.6\baselineskip} \paragraph{Recursive types} @@ -2769,8 +2780,8 @@ \subsection{All polynomial functors are foldable} \subsection{Equivalence of \texttt{traverse} and \texttt{sequence}} -The standard Scala library contains the method \lstinline!Future.sequence! -in addition to \lstinline!Future.traverse!. The main use of \lstinline!Future.sequence! +The Scala library contains the methods \lstinline!Future.sequence! +and \lstinline!Future.traverse!. The main use of \lstinline!Future.sequence! is for transforming a sequence of \lstinline!Future! values that may run in parallel. The result is a single \lstinline!Future! value that waits until all parallel computations are finished. Omitting @@ -2866,18 +2877,24 @@ \subsection{Laws of \texttt{traverse}} To formulate this requirement as an \textbf{applicative naturality law}\index{applicative naturality law!of traverse@of \texttt{traverse}}, we write an equation similar to the second naturality law, except -that the arbitrary function $f$ will now map the applicative functor -$F$ to another \emph{arbitrary} applicative functor $G$:$\xymatrix{\xyScaleY{1.7pc}\xyScaleX{5.0pc}L^{A}\ar[rd]\sb(0.4){\text{trav}_{L}^{G,A,B}(g\bef f)~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(g)} & F^{L^{B}}\ar[d]\sp(0.45){f}\\ +that the function $f$ will now map the applicative functor $F$ to +another \emph{arbitrary} applicative functor $G$: +\noindent \begin{center} +$\xymatrix{\xyScaleY{1.7pc}\xyScaleX{5.0pc}L^{A}\ar[rd]\sb(0.4){\text{trav}_{L}^{G,A,B}(g\bef f)~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(g)} & F^{L^{B}}\ar[d]\sp(0.45){f}\\ & G^{L^{B}} } $ \begin{equation} \text{trav}_{L}^{G,A,B}(g^{:A\rightarrow F^{B}}\bef f^{:F^{B}\rightarrow G^{B}})=\text{trav}_{L}^{F,A,B}(g)\bef f^{:F^{L^{B}}\rightarrow G^{L^{B}}}\quad.\label{eq:traverse-applicative-naturality-law} \end{equation} +\par\end{center} + +\begin{flushleft} Here $f$ is a natural transformation with type signature $f:\forall X.\,F^{X}\rightarrow G^{X}$. So, we are allowed to apply the same code of $f$ to different types: $f$ has type $F^{B}\rightarrow G^{B}$ in the left-hand side of the law and $F^{L^{B}}\rightarrow G^{L^{B}}$ in the right-hand side. +\par\end{flushleft} Another requirement for the function $f$ is that $f$ must map $F$\textsf{'}s applicative methods (\lstinline!wu! and \lstinline!zip!) to the @@ -2892,8 +2909,8 @@ \subsection{Laws of \texttt{traverse}} and monad morphisms defined in Section~\ref{subsec:Monads-in-category-theory-monad-morphisms}). The laws of applicative morphisms are:\index{identity laws!of applicative morphisms}\index{composition law!of applicative morphisms} \begin{align} -{\color{greenunder}\text{identity law of applicative morphism }f:}\quad & f^{:F^{\bbnum 1}\rightarrow G^{\bbnum 1}}(\text{wu}_{F})=\text{wu}_{G}\quad,\label{eq:identity-law-of-applicative-morphism}\\ -{\color{greenunder}\text{composition law of applicative morphism }f:}\quad & \text{zip}_{G}\big(f(p^{:F^{A}})\times f(q^{:F^{B}})\big)=f(\text{zip}_{F}(p\times q))\quad.\label{eq:composition-law-of-applicative-morphism} +{\color{greenunder}\text{identity law }:}\quad & f^{:F^{\bbnum 1}\rightarrow G^{\bbnum 1}}(\text{wu}_{F})=\text{wu}_{G}\quad,\label{eq:identity-law-of-applicative-morphism}\\ +{\color{greenunder}\text{composition law}:}\quad & \text{zip}_{G}\big(f(p^{:F^{A}})\times f(q^{:F^{B}})\big)=f(\text{zip}_{F}(p\times q))\quad.\label{eq:composition-law-of-applicative-morphism} \end{align} The applicative naturality law is required to hold only when $f$ is an applicative morphism. @@ -2953,21 +2970,22 @@ \subsubsection{Example \label{subsec:Example-naturality-law-of-traverse}\ref{sub \] The \lstinline!zip! methods of the applicative functors $G$ and $H$ are: -\[ -\text{zip}_{G}\triangleq\,\begin{array}{|c||cc|} +\begin{align*} + & \text{zip}_{G}\triangleq\,\begin{array}{|c||cc|} & \bbnum 1 & A\times B\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ A\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ \bbnum 1\times B & \_\rightarrow1 & \bbnum 0\\ A\times B & \bbnum 0 & \text{id} -\end{array}\quad,\quad\quad\text{zip}_{H}\triangleq\,\begin{array}{|c||cc|} +\end{array}\quad,\\ + & \text{zip}_{H}\triangleq\,\,\begin{array}{|c||cc|} & \bbnum 1 & (A\times B)\times(A\times B)\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ (A\times A)\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ \bbnum 1\times(B\times B) & \_\rightarrow1 & \bbnum 0\\ (A\times A)\times(B\times B) & \bbnum 0 & \text{zip}_{L} \end{array}\quad. -\] +\end{align*} The function $\text{zip}_{L}$ was shown in the solution to Example~\ref{subsec:Example-some-applicative-morphisms}(a). The applicative morphism $g:G^{A}\rightarrow H^{A}$ is implemented @@ -3003,8 +3021,8 @@ \subsubsection{Example \label{subsec:Example-naturality-law-of-traverse}\ref{sub \end{equation} The pair product ($g\boxtimes g$) can be written in matrix form like this: -\[ -g\boxtimes g=\,\begin{array}{|c||cc|} +\begin{align*} +g\boxtimes g & =\,\begin{array}{|c||cc|} & \bbnum 1 & A\times A\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ A & \bbnum 0 & \Delta @@ -3012,18 +3030,19 @@ \subsubsection{Example \label{subsec:Example-naturality-law-of-traverse}\ref{sub & \bbnum 1 & B\times B\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ B & \bbnum 0 & \Delta -\end{array}\,=\,\begin{array}{|c||cccc|} +\end{array}\\ + & =\,\,\begin{array}{|c||cccc|} & \bbnum 1 & A\times A\times\bbnum 1 & \bbnum 1\times B\times B & A\times A\times B\times B\\ \hline \bbnum 1\times\bbnum 1 & \text{id} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ A\times\bbnum 1 & \bbnum 0 & \Delta\boxtimes\text{id} & \bbnum 0 & \bbnum 0\\ \bbnum 1\times B & \bbnum 0 & \bbnum 0 & \text{id}\boxtimes\Delta & \bbnum 0\\ A\times B & \bbnum 0 & \bbnum 0 & \bbnum 0 & \Delta\boxtimes\Delta \end{array}\quad. -\] +\end{align*} The two sides of the composition law~(\ref{eq:composition-law-applicative-morphism-point-free}) are then simplified to: \begin{align*} - & (g\boxtimes g)\bef\text{zip}_{H}=\,\begin{array}{||cccc|} +(g\boxtimes g)\bef\text{zip}_{H} & =\,\begin{array}{||cccc|} \text{id} & \bbnum 0 & \bbnum 0 & \bbnum 0\\ \bbnum 0 & \Delta\boxtimes\text{id} & \bbnum 0 & \bbnum 0\\ \bbnum 0 & \bbnum 0 & \text{id}\boxtimes\Delta & \bbnum 0\\ @@ -3033,13 +3052,14 @@ \subsubsection{Example \label{subsec:Example-naturality-law-of-traverse}\ref{sub \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \bbnum 0 & \text{zip}_{L} -\end{array}\,=\,\begin{array}{||cc|} +\end{array}\\ + & =\,\,\begin{array}{||cc|} \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \bbnum 0 & (\Delta\boxtimes\Delta)\bef\text{zip}_{L} \end{array}\quad,\\ - & \text{zip}_{G}\bef g=\,\begin{array}{|c||cc|} +\text{zip}_{G}\bef g & =\,\begin{array}{|c||cc|} & \bbnum 1 & A\times B\\ \hline \bbnum 1\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ A\times\bbnum 1 & \_\rightarrow1 & \bbnum 0\\ @@ -3049,7 +3069,8 @@ \subsubsection{Example \label{subsec:Example-naturality-law-of-traverse}\ref{sub & \bbnum 1 & (A\times B)\times(A\times B)\\ \hline \bbnum 1 & \text{id} & \bbnum 0\\ A\times B & \bbnum 0 & \Delta -\end{array}\,=\,\begin{array}{||cc|} +\end{array}\\ + & =\,\,\begin{array}{||cc|} \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ \_\rightarrow1 & \bbnum 0\\ @@ -3102,7 +3123,8 @@ \subsubsection{Example \label{subsec:Example-pure-is-applicative-morphism}\ref{s \] To verify the composition law: \begin{align*} - & \text{zip}_{F}\big(\text{pu}_{F}(p^{:A})\times\text{pu}_{F}(q^{:B})\big)\overset{?}{=}\text{pu}_{F}(\text{zip}_{\text{Id}}(p\times q))=\text{pu}_{F}(p\times q)\\ + & \text{zip}_{F}\big(\text{pu}_{F}(p^{:A})\times\text{pu}_{F}(q^{:B})\big)\overset{?}{=}\text{pu}_{F}(\text{zip}_{\text{Id}}(p\times q))\\ + & =\text{pu}_{F}(p\times q)\\ {\color{greenunder}\text{use Exercise~\ref{subsec:Exercise-zip-pure-pure}}:}\quad & =\text{zip}_{F}(\text{pu}_{F}(p)\times\text{pu}_{F}(q))\quad. \end{align*} $\square$ @@ -3202,13 +3224,17 @@ \subsubsection{Statement \label{subsec:Statement-identity-law-traverse-simplifie $F\circ G$. By Statement~\ref{subsec:Statement-applicative-composition}, the functor $F\circ G$ is applicative. So, we may apply a single \lstinline!traverse! operation using that functor and obtain: -\[ -p\triangleright\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F}):F^{G^{L^{C}}}\quad. -\] +\noindent \begin{center} $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{3.4pc}L^{A}\ar[dr]\sb(0.35){\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})~~}\ar[r]\sp(0.5){\text{trav}_{L}^{F,A,B}(f)} & F^{L^{B}}\ar[d]\sp(0.4){\big(\text{trav}_{L}^{G,B,C}(g)\big)^{\uparrow F}}\\ & F^{G^{L^{C}}} } -$The \textbf{composition law}\index{composition law!of traverse@of \texttt{traverse}} +$ +\[ +p\triangleright\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F}):F^{G^{L^{C}}}\quad. +\] +\par\end{center} + +\noindent The \textbf{composition law}\index{composition law!of traverse@of \texttt{traverse}} of \lstinline!traverse! says that the two results should be equal: \begin{equation} \text{trav}_{L}^{F,A,B}(f)\bef\big(\text{trav}_{L}^{G,B,C}(g)\big)^{\uparrow F}=\text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})\quad.\label{eq:composition-law-of-traverse} @@ -3237,12 +3263,10 @@ \subsubsection{Statement \label{subsec:Statement-identity-law-traverse-simplifie $G$ to the \lstinline!State! monad.\footnote{The paper \texttt{\href{https://arxiv.org/abs/1202.2919}{https://arxiv.org/abs/1202.2919}} shows another example using the \lstinline!List! monad.} For simplicity, we set all type parameters to \lstinline!Int! and choose the functions $f$ and $g$ that add their arguments to the -internal state. The complete code (using the \lstinline!Zippable! +internal state. The complete law-violating code (using the \lstinline!Zippable! typeclass defined in Section~\ref{subsec:The-Zippable-and-Applicative-typeclass}) -is shown in Fig.~\ref{fig:Full-code-implementing-traverse-law-counterexample}. +is shown below: -\begin{figure} -\begin{centering} \begin{lstlisting}[frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm] import io.chymyst.ch.implement // Automatic implementation of some methods. @@ -3270,7 +3294,7 @@ \subsubsection{Statement \label{subsec:Statement-identity-law-traverse-simplifie } } - // Define F[A] as the composition S[S[A]] and implement WuZip and Functor instances. + // Define F[A] as S[S[A]] and implement WuZip and Functor instances. final case class F[A](run: S[S[A]]) { // A runner method to help with testing. def eval(i: Int, j: Int): (A, Int, Int) = { @@ -3309,16 +3333,11 @@ \subsubsection{Statement \label{subsec:Statement-identity-law-traverse-simplifie scala> result2.eval(0,0) res1: ((Int, Int), Int, Int) = ((4, 6), 2, 6) \end{lstlisting} -\par\end{centering} -\caption{A counterexample violating the composition law of \lstinline!traverse!.\label{fig:Full-code-implementing-traverse-law-counterexample}} -\end{figure} -We have shown that \emph{some} incorrect implementations of \lstinline!traverse! -are excluded by the composition law. But it remains unknown whether -the mentioned laws guarantee that any lawful \lstinline!traverse! -function collects each $F$-effect exactly once. Perhaps another law -of \lstinline!traverse! is required (see Problem~\ref{par:Problem-traverse-law}).{*}{*}{*}Mention -the paper about the rewinding law. +We have found that \emph{some} incorrect implementations of \lstinline!traverse! +are prohibited by its laws. But this is not a proof that all lawful +\lstinline!traverse! functions will collect each $F$-effect exactly +once. We will revisit this question below in Section~\ref{subsec:Laws-of-traverse-and-zipWithIndex}. \subsection{Laws of \texttt{sequence}} @@ -3328,7 +3347,7 @@ \subsection{Laws of \texttt{sequence}} Begin with the naturality laws. Since the type signature of \lstinline!sequence! ($L^{F^{A}}\rightarrow F^{L^{A}}$) has only one type parameter, \lstinline!sequence! has only one naturality law\index{naturality law!of sequence@of \texttt{sequence}}: - +\begin{center} $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{2.0pc}L^{F^{A}}\ar[d]\sb(0.45){\text{seq}_{L}^{F,A}}\ar[r]\sb(0.5){f^{\uparrow F\uparrow L}} & L^{F^{B}}\ar[d]\sp(0.45){\text{seq}_{L}^{F,B}}\\ F^{L^{A}}\ar[r]\sp(0.5){f^{\uparrow L\uparrow F}} & F^{L^{B}} } @@ -3336,6 +3355,8 @@ \subsection{Laws of \texttt{sequence}} \begin{equation} (f^{:A\rightarrow B})^{\uparrow F\uparrow L}\bef\text{seq}_{L}^{F,B}=\text{seq}_{L}^{F,A}\bef f^{\uparrow L\uparrow F}\quad.\label{eq:sequence-naturality-law} \end{equation} +\par\end{center} + It will be shown in Exercise~\ref{subsec:Exercise-traversables-laws-2} that this naturality law is equivalent to the two naturality laws of \lstinline!traverse!. @@ -3350,16 +3371,18 @@ \subsection{Laws of \texttt{sequence}} \end{align*} The function $g^{\uparrow L}$ can be omitted from both sides (see Exercise~\ref{subsec:Exercise-simplify-law-omit-lifted-function} -for a similar property). - +for a similar property). Renaming $B$ to $A$, we write the applicative +naturality law\index{applicative naturality law!of sequence@of \texttt{sequence}} +of \lstinline!sequence!: +\begin{center} $\xymatrix{\xyScaleY{1.5pc}\xyScaleX{2.0pc}L^{F^{A}}\ar[d]\sb(0.45){\text{seq}_{L}^{F,A}}\ar[r]\sb(0.5){(f^{A})^{\uparrow L}} & L^{G^{A}}\ar[d]\sp(0.45){\text{seq}_{L}^{G,A}}\\ F^{L^{A}}\ar[r]\sp(0.5){f^{L^{A}}} & G^{L^{A}} } -$Renaming $B$ to $A$, we rewrite the applicative naturality law\index{applicative naturality law!of sequence@of \texttt{sequence}} -of \lstinline!sequence! as: +$ \[ (f^{A})^{\uparrow L}\bef\text{seq}_{L}^{G,A}=\text{seq}_{L}^{F,A}\bef f^{L^{A}}\quad. \] +\par\end{center} \noindent Here we have written the full type parameters in $f^{X}$ and $\text{seq}_{L}^{F,A}$ for clarity. @@ -3379,15 +3402,21 @@ \subsection{Laws of \texttt{sequence}} The composition law~(\ref{eq:composition-law-of-traverse}) of \lstinline!traverse! leads to the following composition law of \lstinline!sequence!: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{trav}_{L}^{F,A,B}(f^{:A\rightarrow F^{B}})\bef\big(\text{trav}_{L}^{G,B,C}(g^{:B\rightarrow G^{C}})\big)^{\uparrow F}=f^{\uparrow L}\bef\text{seq}_{L}^{F,B}\bef\big(g^{\uparrow L}\bef\text{seq}_{L}^{G,C}\big)^{\uparrow F}\\ +{\color{greenunder}\text{left-hand side}:}\quad & \text{trav}_{L}^{F,A,B}(f^{:A\rightarrow F^{B}})\bef\big(\text{trav}_{L}^{G,B,C}(g^{:B\rightarrow G^{C}})\big)^{\uparrow F}\\ + & \quad=f^{\uparrow L}\bef\text{seq}_{L}^{F,B}\bef\big(g^{\uparrow L}\bef\text{seq}_{L}^{G,C}\big)^{\uparrow F}\\ & \quad=f^{\uparrow L}\bef\gunderline{\text{seq}_{L}^{F,B}\bef g^{\uparrow L\uparrow F}}\bef(\text{seq}_{L}^{G,C})^{\uparrow F}\\ {\color{greenunder}\text{naturality law~(\ref{eq:sequence-naturality-law})}:}\quad & \quad=f^{\uparrow L}\bef g^{\uparrow F\uparrow L}\bef\text{seq}_{L}^{F,G^{C}}\bef(\text{seq}_{L}^{G,C})^{\uparrow F}\quad,\\ {\color{greenunder}\text{right-hand side}:}\quad & \text{trav}_{L}^{F\circ G,A,C}(f\bef g^{\uparrow F})=(f\bef g^{\uparrow F})^{\uparrow L}\bef\text{seq}_{L}^{F\circ G,C}\quad. \end{align*} + +\begin{center} $\xymatrix{\xyScaleY{1.4pc}\xyScaleX{3.0pc}L^{F^{G^{A}}}\ar[r]\sp(0.55){\text{seq}_{L}^{F,G^{A}}}\ar[rd]\sb(0.4){\text{seq}_{L}^{F\circ G,A}} & F^{L^{G^{A}}}\ar[d]\sp(0.4){(\text{seq}_{L}^{G,A})^{\uparrow F}}\\ & F^{G^{L^{A}}} } -$Omitting the common function $(f\bef g^{\uparrow F})^{\uparrow L}$ +$ +\par\end{center} + +Omitting the common function $(f\bef g^{\uparrow F})^{\uparrow L}$ and renaming $C$ to $A$, we obtain the \index{composition law!of sequence@of \texttt{sequence}}\textbf{composition law} of \lstinline!sequence!: \begin{equation} @@ -3445,9 +3474,10 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- $M$ and $N$. We assume that $\text{seq}_{M}$ and $\text{seq}_{N}$ are already available and satisfy the laws, and define $\text{seq}_{L}$ as: -\[ -\text{seq}_{L}^{F,A}:M^{F^{A}}\times N^{F^{A}}\rightarrow F^{M^{A}\times N^{A}}\quad,\quad\quad\text{seq}_{L}^{F,A}\triangleq m^{:M^{F^{A}}}\times n^{:N^{F^{A}}}\rightarrow\text{zip}_{F}\big((m\triangleright\text{seq}_{M}^{F,A})\times(n\triangleright\text{seq}_{N}^{F,A})\big)\quad. -\] +\begin{align*} + & \text{seq}_{L}^{F,A}:M^{F^{A}}\times N^{F^{A}}\rightarrow F^{M^{A}\times N^{A}}\quad,\\ + & \text{seq}_{L}^{F,A}\triangleq m^{:M^{F^{A}}}\times n^{:N^{F^{A}}}\rightarrow\text{zip}_{F}\big((m\triangleright\text{seq}_{M}^{F,A})\times(n\triangleright\text{seq}_{N}^{F,A})\big)\quad. +\end{align*} In the point-free style, we can write the same code in a shorter formula: \[ \text{seq}_{L}^{F,A}\triangleq(\text{seq}_{M}^{F,A}\boxtimes\text{seq}_{N}^{F,A})\bef\text{zip}_{F}\quad. @@ -3463,9 +3493,11 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- To verify the composition law~(\ref{eq:composition-law-of-sequence}), begin with its left-hand side: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq}_{M}^{G,A}\boxtimes\text{seq}_{N}^{G,A})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ -{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad & =\gunderline{(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\big((\text{seq}_{M}^{G,A})^{\uparrow F}\boxtimes(\text{seq}_{N}^{G,A})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ -{\color{greenunder}\text{composition law~(\ref{eq:pair-product-composition-law})}:}\quad & =\big((\text{seq}_{M}^{F,G^{A}}\bef(\text{seq}_{M}^{G,A})^{\uparrow F})\boxtimes(\text{seq}_{N}^{F,G^{A}}\bef(\text{seq}_{N}^{G,A})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq}_{M}^{G,A}\boxtimes\text{seq}_{N}^{G,A})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad{\color{greenunder}\text{naturality law of }\text{zip}_{F}:}\quad\\ + & =\gunderline{(\text{seq}_{M}^{F,G^{A}}\boxtimes\text{seq}_{N}^{F,G^{A}})\bef\big((\text{seq}_{M}^{G,A})^{\uparrow F}\boxtimes(\text{seq}_{N}^{G,A})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad{\color{greenunder}\text{composition law~(\ref{eq:pair-product-composition-law})}:}\quad\\ + & =\big((\text{seq}_{M}^{F,G^{A}}\bef(\text{seq}_{M}^{G,A})^{\uparrow F})\boxtimes(\text{seq}_{N}^{F,G^{A}}\bef(\text{seq}_{N}^{G,A})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. \end{align*} By assumption, $\text{seq}_{M}$ and $\text{seq}_{N}$ satisfy their composition laws. So, we may rewrite the last line as: @@ -3492,7 +3524,7 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- are already available and satisfy the laws, and define $\text{seq}_{L}$ as: \[ -\text{seq}_{L}:M^{F^{A}}+N^{F^{A}}\rightarrow F^{M^{A}+N^{A}}\quad,\quad\quad\text{seq}_{L}\triangleq\,\begin{array}{|c||c|} +\text{seq}_{L}:M^{F^{A}}+N^{F^{A}}\rightarrow F^{M^{A}+N^{A}}\quad,\quad\text{seq}_{L}\triangleq\,\begin{array}{|c||c|} & F^{M^{A}+N^{A}}\\ \hline M^{F^{A}} & \text{seq}_{M}^{F,A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow F}\\ N^{F^{A}} & \text{seq}_{N}^{F,A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow F} @@ -3532,7 +3564,8 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- \hline M^{\text{Id}^{A}} & \text{seq}_{M}^{\text{Id},A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow\text{Id}}\\ N^{\text{Id}^{A}} & \text{seq}_{N}^{\text{Id},A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow\text{Id}} \end{array}\\ -{\color{greenunder}\text{identity laws of }\text{seq}_{M}\text{ and }\text{seq}_{N}:}\quad & =\,\begin{array}{|c||c|} + & \quad{\color{greenunder}\text{identity laws of }\text{seq}_{M}\text{ and }\text{seq}_{N}:}\quad\\ + & =\,\begin{array}{|c||c|} & M^{A}+N^{A}\\ \hline M^{A} & m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}}\\ N^{A} & n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n @@ -3546,7 +3579,8 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- To verify the composition law~(\ref{eq:composition-law-of-sequence}), write its two sides separately: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\,\begin{array}{||c|} +{\color{greenunder}\text{left-hand side}:}\quad & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ + & \quad=\,\begin{array}{||c|} \text{seq}_{M}^{F,G^{A}}\bef(m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})^{\uparrow F}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ \text{seq}_{N}^{F,G^{A}}\bef(n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)^{\uparrow F}\bef(\text{seq}_{L}^{G,A})^{\uparrow F} \end{array}\quad,\\ @@ -3558,7 +3592,8 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- The left-hand side contains some function compositions lifted to $F$. Write them separately: \begin{align*} - & (m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})\bef\text{seq}_{L}^{G,A}=\,\begin{array}{|c||cc|} + & (m^{:M^{G^{A}}}\rightarrow m+\bbnum 0^{:N^{G^{A}}})\bef\text{seq}_{L}^{G,A}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A}} & N^{G^{A}}\\ \hline M^{G^{A}} & \text{id} & \bbnum 0 \end{array}\,\bef\,\begin{array}{|c||c|} @@ -3567,7 +3602,8 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- N^{G^{A}} & \text{seq}_{N}^{G,A}\bef(n^{:N^{A}}\rightarrow\bbnum 0^{:M^{A}}+n)^{\uparrow G} \end{array}\\ & \quad=\text{seq}_{M}^{G,A}\bef(m^{:M^{A}}\rightarrow m+\bbnum 0^{:N^{A}})^{\uparrow G}\quad,\\ - & (n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)\bef\text{seq}_{L}^{G,A}=\,\begin{array}{|c||cc|} + & (n^{:N^{G^{A}}}\rightarrow\bbnum 0^{:M^{G^{A}}}+n)\bef\text{seq}_{L}^{G,A}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A}} & N^{G^{A}}\\ \hline N^{G^{A}} & \bbnum 0 & \text{id} \end{array}\,\bef\,\begin{array}{|c||c|} @@ -3636,7 +3672,8 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- To verify the composition law~(\ref{eq:composition-law-of-sequence}), write its two sides separately: \begin{align*} - & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F,G^{A},L^{G^{A}}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow S^{G^{A},\bullet}\uparrow F}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\quad,\\ + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ + & \quad=\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F,G^{A},L^{G^{A}}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow S^{G^{A},\bullet}\uparrow F}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\quad,\\ & \text{seq}_{L}^{F\circ G,A}=\big(\overline{\text{seq}}_{L}^{F\circ G,A}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\text{seq2}_{S}^{F\circ G,A,L^{A}}\quad. \end{align*} We use the naturality law of $\text{seq2}_{S}^{F,A,B}$ with respect @@ -3649,8 +3686,10 @@ \subsection{All polynomial functors are traversable\label{subsec:All-polynomial- \begin{align*} & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ & =\gunderline{\big(\overline{\text{seq}}_{L}^{F,G^{A}}\big)^{\uparrow S^{F^{G^{A}},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{G,A}\big)^{\uparrow F\uparrow S^{F^{G^{A}},\bullet}}}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}\\ -{\color{greenunder}\text{composition law~(\ref{eq:composition-law-of-sequence})}:}\quad & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}}\\ -{\color{greenunder}\text{composition law~(\ref{eq:composition-law-of-bisequence})}:}\quad & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F\circ G,A,L^{A}}}\quad. + & \quad{\color{greenunder}\text{composition law~(\ref{eq:composition-law-of-sequence})}:}\quad\\ + & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},G^{L^{A}}}\bef\big(\text{seq2}_{S}^{G,A,L^{A}}\big)^{\uparrow F}}\\ + & \quad{\color{greenunder}\text{composition law~(\ref{eq:composition-law-of-bisequence})}:}\quad\\ + & =(\text{seq}_{L}^{F\circ G,A})^{\uparrow S^{F^{G^{A}},\bullet}}\bef\gunderline{\text{seq2}_{S}^{F\circ G,A,L^{A}}}\quad. \end{align*} The two sides of the law~(\ref{eq:composition-law-of-sequence}) are now equal. $\square$ @@ -3693,9 +3732,9 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom Bitraversable bifunctors are used in the recursive-type construction for traversable functors. The properties of bitraversable bifunctors are similar to the properties of traversable functors. We will now -prove that all polynomial bifunctors are bitraversable. The proof -verifies that each of the five type constructions of polynomial bifunctors -will produce a bitraversable bifunctor satisfying the laws~(\ref{eq:identity-law-of-bisequence})\textendash (\ref{eq:composition-law-of-bisequence}). +prove that all polynomial bifunctors are bitraversable. This verifies +that each of the five type constructions of polynomial bifunctors +produces a bitraversable bifunctor satisfying the laws~(\ref{eq:identity-law-of-bisequence})\textendash (\ref{eq:composition-law-of-bisequence}). \paragraph{Fixed type} @@ -3731,9 +3770,10 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom bifunctors $M$ and $N$. We assume that $\text{seq2}_{M}$ and $\text{seq2}_{N}$ are already available and satisfy the laws, and define $\text{seq2}_{S}$ as: -\[ -\text{seq2}_{S}^{F,A,B}:M^{F^{A},F^{B}}\times N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}\times N^{A,B}}\quad,\quad\quad\text{seq2}_{S}^{F,A,B}\triangleq(\text{seq2}_{M}^{F,A,B}\boxtimes\text{seq2}_{N}^{F,A,B})\bef\text{zip}_{F}\quad. -\] +\begin{align*} + & \text{seq2}_{S}^{F,A,B}:M^{F^{A},F^{B}}\times N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}\times N^{A,B}}\quad,\\ + & \text{seq2}_{S}^{F,A,B}\triangleq(\text{seq2}_{M}^{F,A,B}\boxtimes\text{seq2}_{N}^{F,A,B})\bef\text{zip}_{F}\quad. +\end{align*} To verify the identity law~(\ref{eq:identity-law-of-bisequence}), use the fact that $\text{zip}_{\text{Id}}=\text{id}$: @@ -3745,10 +3785,12 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom To verify the composition law~(\ref{eq:composition-law-of-bisequence}), begin with its left-hand side: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ + & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ & =(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\gunderline{\text{zip}_{F}\bef(\text{seq2}_{M}^{G,A,B}\boxtimes\text{seq2}_{N}^{G,A,B})^{\uparrow F}}\bef\text{zip}_{G}^{\uparrow F}\\ -{\color{greenunder}\text{naturality of }\text{zip}_{F}:}\quad & =\gunderline{(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\big((\text{seq2}_{M}^{G,A,B})^{\uparrow F}\boxtimes(\text{seq2}_{N}^{G,A,B})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ -{\color{greenunder}\text{the law~(\ref{eq:pair-product-composition-law})}:}\quad & =\big((\text{seq2}_{M}^{F,G^{A},G^{B}}\bef(\text{seq2}_{M}^{G,A,B})^{\uparrow F})\boxtimes(\text{seq2}_{N}^{F,G^{A},G^{B}}\bef(\text{seq2}_{N}^{G,A,B})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. + & \quad{\color{greenunder}\text{naturality of }\text{zip}_{F}:}\quad\\ + & =\gunderline{(\text{seq2}_{M}^{F,G^{A},G^{B}}\boxtimes\text{seq2}_{N}^{F,G^{A},G^{B}})\bef\big((\text{seq2}_{M}^{G,A,B})^{\uparrow F}\boxtimes(\text{seq2}_{N}^{G,A,B})^{\uparrow F}\big)}\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\\ + & \quad{\color{greenunder}\text{the law~(\ref{eq:pair-product-composition-law})}:}\quad\\ + & =\big((\text{seq2}_{M}^{F,G^{A},G^{B}}\bef(\text{seq2}_{M}^{G,A,B})^{\uparrow F})\boxtimes(\text{seq2}_{N}^{F,G^{A},G^{B}}\bef(\text{seq2}_{N}^{G,A,B})^{\uparrow F})\big)\bef\text{zip}_{F}\bef\text{zip}_{G}^{\uparrow F}\quad. \end{align*} By assumption, $\text{seq2}_{M}$ and $\text{seq2}_{N}$ satisfy their composition laws. So, we may rewrite the last line as: @@ -3768,13 +3810,14 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom bifunctors $M$ and $N$. We assume that $\text{seq2}_{M}$ and $\text{seq2}_{N}$ are already available and satisfy the laws, and define $\text{seq2}_{S}$ as: -\[ -\text{seq2}_{S}:M^{F^{A},F^{B}}+N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}+N^{A,B}}\quad,\quad\text{seq2}_{S}\triangleq\,\begin{array}{|c||c|} +\begin{align*} + & \text{seq2}_{S}:M^{F^{A},F^{B}}+N^{F^{A},F^{B}}\rightarrow F^{M^{A,B}+N^{A,B}}\quad,\\ + & \text{seq2}_{S}\triangleq\,\begin{array}{|c||c|} & F^{M^{A,B}+N^{A,B}}\\ \hline M^{F^{A},F^{B}} & \text{seq2}_{M}^{F,A,B}\bef(m^{:M^{A,B}}\rightarrow m+\bbnum 0)^{\uparrow F}\\ N^{F^{A},F^{B}} & \text{seq2}_{N}^{F,A,B}\bef(n^{:N^{A,B}}\rightarrow\bbnum 0+n)^{\uparrow F} \end{array}\quad. -\] +\end{align*} To verify the identity law~(\ref{eq:identity-law-of-bisequence}): \begin{align*} @@ -3783,7 +3826,8 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom \hline M^{\text{Id}^{A},\text{Id}^{B}} & \text{seq2}_{M}^{\text{Id},A,B}\bef(m\rightarrow m+\bbnum 0)^{\uparrow\text{Id}}\\ N^{\text{Id}^{A}} & \text{seq2}_{N}^{\text{Id},A,B}\bef(n\rightarrow\bbnum 0+n)^{\uparrow\text{Id}} \end{array}\\ -{\color{greenunder}\text{identity laws of }\text{seq2}_{M}\text{ and }\text{seq2}_{N}:}\quad & =\,\begin{array}{|c||c|} + & \quad{\color{greenunder}\text{identity laws of }\text{seq2}_{M}\text{ and }\text{seq2}_{N}:}\quad\\ + & =\,\begin{array}{|c||c|} & M^{A,B}+N^{A,B}\\ \hline M^{A,B} & m\rightarrow m+\bbnum 0\\ N^{A,B} & n\rightarrow\bbnum 0+n @@ -3797,7 +3841,8 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom To verify the composition law~(\ref{eq:composition-law-of-bisequence}), write its two sides separately: \begin{align*} -{\color{greenunder}\text{left-hand side}:}\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\,\begin{array}{||c|} +{\color{greenunder}\text{left-hand side}:}\quad & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ + & \quad=\,\begin{array}{||c|} \text{seq2}_{M}^{F,G^{A},G^{B}}\bef(m\rightarrow m+\bbnum 0)^{\uparrow F}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ \text{seq2}_{N}^{F,G^{A},G^{B}}\bef(n\rightarrow\bbnum 0+n)^{\uparrow F}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F} \end{array}\quad,\\ @@ -3809,7 +3854,8 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom The left-hand side contains some function compositions lifted to $F$. Write them separately: \begin{align*} - & (m\rightarrow m+\bbnum 0)\bef\text{seq2}_{S}^{G,A,B}=\,\begin{array}{|c||cc|} + & (m\rightarrow m+\bbnum 0)\bef\text{seq2}_{S}^{G,A,B}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A},G^{B}} & N^{G^{A},G^{B}}\\ \hline M^{G^{A},G^{B}} & \text{id} & \bbnum 0 \end{array}\,\bef\,\begin{array}{|c||c|} @@ -3818,7 +3864,8 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom N^{G^{A},G^{B}} & \text{seq2}_{N}^{G,A,B}\bef(n\rightarrow\bbnum 0+n)^{\uparrow G} \end{array}\\ & \quad=\text{seq2}_{M}^{G,A,B}\bef(m^{:M^{A,B}}\rightarrow m+\bbnum 0^{:N^{A,B}})^{\uparrow G}\quad,\\ - & (n\rightarrow\bbnum 0+n)\bef\text{seq2}_{S}^{G,A,B}=\,\begin{array}{|c||cc|} + & (n\rightarrow\bbnum 0+n)\bef\text{seq2}_{S}^{G,A,B}\\ + & \quad=\,\begin{array}{|c||cc|} & M^{G^{A},G^{B}} & N^{G^{A},G^{B}}\\ \hline N^{G^{A},G^{B}} & \bbnum 0 & \text{id} \end{array}\,\bef\,\begin{array}{|c||c|} @@ -3879,38 +3926,39 @@ \subsection{All polynomial bifunctors are bitraversable\label{subsec:All-polynom reason, we omit those proofs. The conclusion will be that all polynomial $n$-functors are $n$-traversable for $n=1,2,3,...$ -Assume that a lawful $\text{seq3}_{T}$ is available and define $\text{seq2}_{S}$ +Assume that a lawful $\text{seq3}_{T}$ is available, and define $\text{seq2}_{S}$ as: -\[ -\text{seq2}_{S}^{F,A,B}:T^{F^{A},F^{B},S^{F^{A},F^{B}}}\rightarrow F^{T^{A,B,S^{A,B}}}\quad,\quad\quad\text{seq2}_{S}^{F,A,B}\triangleq\big(\overline{\text{seq2}}_{S}^{F,A,B}\big)^{\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,S^{A,B}}\quad. -\] +\begin{align*} + & \text{seq2}_{S}^{F,A,B}:T^{F^{A},F^{B},S^{F^{A},F^{B}}}\rightarrow F^{T^{A,B,S^{A,B}}}\quad,\\ + & \text{seq2}_{S}^{F,A,B}\triangleq\big(\overline{\text{seq2}}_{S}^{F,A,B}\big)^{\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,S^{A,B}}\quad. +\end{align*} The inductive assumption is that the recursively called $\overline{\text{seq2}}_{S}$ already obeys the laws we are proving. To verify the identity law~(\ref{eq:identity-law-of-bisequence}), we use the assumed law~(\ref{eq:identity-law-of-trisequence}): \[ -\text{seq2}_{S}^{\text{Id},A,B}=\big(\overline{\text{seq2}}_{S}^{\text{Id},A,B}\big)^{\uparrow T^{\text{Id}^{A},\text{Id}^{B},\bullet}}\bef\text{seq3}_{T}^{\text{Id},A,B,S^{A,B}}=\text{id}^{\uparrow T^{A,B,\bullet}}\bef\text{id}=\text{id}\quad. +\text{seq2}_{S}^{\text{Id},A,B}=\big(\overline{\text{seq2}}_{S}^{\text{Id},A,B}\big)^{\uparrow T^{\text{Id}^{A},\text{Id}^{B},\,\bullet}}\bef\text{seq3}_{T}^{\text{Id},A,B,S^{A,B}}=\text{id}^{\uparrow T^{A,B,\bullet}}\bef\text{id}=\text{id}\quad. \] To verify the composition law~(\ref{eq:composition-law-of-bisequence}): \begin{align*} - & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ - & \quad=\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},S^{G^{A},G^{B}}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow T^{G^{A},G^{B},\bullet}\uparrow F}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\quad,\\ - & \text{seq2}_{S}^{F\circ G,A,B}=\big(\overline{\text{seq2}}_{S}^{F\circ G,A,B}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}\quad. + & \text{seq2}_{S}^{F,G^{A},G^{B}}\bef(\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},S^{G^{A},G^{B}}}\\ + & \quad\quad\quad\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow T^{G^{A},G^{B},\bullet}\uparrow F}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\quad,\\ + & \text{seq2}_{S}^{F\circ G,A,B}=\big(\overline{\text{seq2}}_{S}^{F\circ G,A,B}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}\quad. \end{align*} We use the naturality law of $\text{seq3}_{T}^{F,A,B,C}$ with respect to the parameter $C$: \[ -\text{seq3}_{T}^{F,A,B,C}\bef(f^{:C\rightarrow D})^{\uparrow T^{A,B,\bullet}\uparrow F}=f^{\uparrow F\uparrow T^{F^{A},F^{B},\bullet}}\bef\text{seq3}_{T}^{F,A,B,D}\quad. +\text{seq3}_{T}^{F,A,B,C}\bef(f^{:C\rightarrow D})^{\uparrow T^{A,B,\bullet}\uparrow F}=f^{\uparrow F\uparrow T^{F^{A},F^{B},\,\bullet}}\bef\text{seq3}_{T}^{F,A,B,D}\quad. \] Then the left-hand side of the law~(\ref{eq:composition-law-of-bisequence}) becomes: \begin{align*} -\text{seq2}_{S}^{F,G^{A},G^{B}}\bef & (\text{seq2}_{S}^{G,A,B})^{\uparrow F}\\ - & =\gunderline{\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow F\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}}\bef\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\\ -{\color{greenunder}\text{Eq.~(\ref{eq:identity-law-of-bisequence})}:}\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\gunderline{\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}}\\ -{\color{greenunder}\text{Eq.~(\ref{eq:composition-law-of-trisequence})}:}\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\bullet}}\bef\gunderline{\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}}\quad. +\text{seq2}_{S}^{F,G^{A},G^{B}}\bef & (\text{seq2}_{S}^{G,A,B})^{\uparrow F}=\gunderline{\big(\overline{\text{seq2}}_{S}^{F,G^{A},G^{B}}\big)^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\big(\overline{\text{seq2}}_{S}^{G,A,B}\big)^{\uparrow F\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}}\\ + & \quad\quad\quad\bef\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}\\ +{\color{greenunder}\text{Eq.~(\ref{eq:identity-law-of-bisequence})}:}\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\gunderline{\text{seq3}_{T}^{F,G^{A},G^{B},G^{S^{A,B}}}\bef\big(\text{seq3}_{T}^{G,A,B,S^{A,B}}\big)^{\uparrow F}}\\ +{\color{greenunder}\text{Eq.~(\ref{eq:composition-law-of-trisequence})}:}\quad & =(\text{seq2}_{S}^{F\circ G,A,B})^{\uparrow T^{F^{G^{A}},F^{G^{B}},\,\bullet}}\bef\gunderline{\text{seq3}_{T}^{F\circ G,A,B,S^{A,B}}}\quad. \end{align*} The two sides of the law~(\ref{eq:identity-law-of-bisequence}) are now equal. @@ -4049,8 +4097,7 @@ \subsubsection{Exercise \label{subsec:Exercise-traversables-10-1-1-1}\ref{subsec \textbf{(b)} Show that the converse does not hold: if $\phi:M\leadsto N$ is an applicative morphism between two monads then $\phi$ is \emph{not} -necessarily a monad morphism. One example is where $M$ and $N$ are -\lstinline!State! monads {*}{*}{*}??? +necessarily a monad morphism. \subsubsection{Exercise \label{subsec:Exercise-traversables-10-3}\ref{subsec:Exercise-traversables-10-3}} @@ -4088,33 +4135,61 @@ \subsubsection{Exercise \label{subsec:Exercise-traversables-10-3-1}\ref{subsec:E \textbf{(c)} Prove that \lstinline!outMF! is \emph{not} a monoid morphism between $\text{MF}^{M}$ and $M$. +\subsubsection{Exercise \label{subsec:Exercise-traversables-10-1-1-2}\ref{subsec:Exercise-traversables-10-1-1-2}} + +For any applicative functor $F$ with a known \lstinline!zip! method, +define the \textsf{``}reversed\textsf{''} \lstinline!zip! method as: +\[ +\text{zip}_{\text{rev}F}:F^{A}\times F^{B}\rightarrow F^{A\times B}\quad,\quad\quad\text{zip}_{\text{rev}F}\triangleq\text{swap}\bef\text{zip}_{F}\bef\text{swap}^{\uparrow F}\quad. +\] + +\textbf{(a)} Show that $\text{zip}_{\text{rev}F}$ also provides a +lawful applicative instance for $F$ (where $F$\textsf{'}s \lstinline!pure! +method remains unchanged). Show that $\text{zip}_{\text{rev}F}=\text{zip}_{F}$ +whenever $F$ is commutative. + +\textbf{(b)} Show that the \textsf{``}applicative reversal\textsf{''} obeys an applicative +naturality law: for any applicative functors $F$, $G$ and an applicative +morphism $\phi:F^{A}\rightarrow G^{A}$, the following equation holds: +\[ +(p^{:F^{A}}\times q^{:F^{B}})\triangleright\text{zip}_{\text{rev}F}\triangleright\phi=(\phi(p)\times\phi(q))\triangleright\text{zip}_{\text{rev}G}\quad. +\] + + \section{Discussion and further developments} -\subsection{Laws of \texttt{traverse} and properties of \texttt{zipWithIndex}\label{subsec:Laws-of-traverse-and-zipWithIndex}} +\subsection{The missing laws of \texttt{traverse} and \texttt{zipWithIndex}\label{subsec:Laws-of-traverse-and-zipWithIndex}} + +The two laws of \lstinline!traverse! shown in this chapter do \emph{not} +in fact guarantee that \lstinline!traverse! behaves as programmers +expect. To see that, we generalize \lstinline!zipWithIndex! to arbitrary +traversable functors and then try proving two intuitively reasonable +properties of \lstinline!zipWithIndex! starting from the two laws +of \lstinline!traverse!. We will find that we \emph{cannot} prove +one of these properties without assuming some new laws of \lstinline!traverse!. +However, another approach based on more advanced techniques makes +it possible to prove all necessary properties. Sections~\ref{subsec:Decorating-a-tree1}\textendash \ref{subsec:Decorating-a-tree-breadth-first-traversal} -defined the method \lstinline!zipWithIndex! for different orders -of tree traversal. In a similar way, we may define \lstinline!zipWithIndex! +defined the method \lstinline!zipWithIndex! for certain choices of +traversals over binary trees. How can we define \lstinline!zipWithIndex! (denoted $\text{zwi}_{L}$ for brevity) for any traversable functor -$L$. In this section, we will prove some intuitively reasonable properties -of \lstinline!zipWithIndex! by assuming only that the laws of \lstinline!traverse! -hold. This will serve as an additional evidence that the laws of \lstinline!traverse! -correspond to a programmer\textsf{'}s intuitions about code. - -To implement \lstinline!zipWithIndex! for $L$, we use $L$\textsf{'}s \lstinline!traverse! -method ($\text{trav}_{L}^{F,A,B}$) and chose the applicative functor -$F$ as the \lstinline!State! monad with internal state of type \lstinline!Int!: +$L$? We use $L$\textsf{'}s \lstinline!traverse! method ($\text{trav}_{L}^{F,A,B}$) +and chose the applicative functor $F$ as the \lstinline!State! monad +with the internal state of type \lstinline!Int!: \[ F^{A}\triangleq\text{State}^{\text{Int},A}\triangleq\text{Int}\rightarrow A\times\text{Int}\quad. \] -The internal state represents a current value of the index. The code +The internal state represents the current value of the index while +we iterate over values of type $A$ stored within $L^{A}$. The code of \lstinline!zipWithIndex! applies \lstinline!traverse! to a function of type $A\rightarrow\text{State}^{S,A\times\text{Int}}$ that increments the index: -\begin{equation} -\text{zwi}_{L}^{A}:L^{A}\rightarrow L^{A\times\text{Int}}\quad,\quad\text{zwi}_{L}^{A}\triangleq\text{trav}_{L}^{F,A,A\times\text{Int}}(a^{:A}\rightarrow s^{:\text{Int}}\rightarrow(a\times s)\times(s+1))\bef\text{run}_{\text{State}}(0^{:\text{Int}})\quad,\label{eq:definition-of-zwi} -\end{equation} -Here $\text{run}_{\text{State}}(0^{:\text{Int}})$ is the \lstinline!State! +\begin{align} + & \text{zwi}_{L}^{A}:L^{A}\rightarrow L^{A\times\text{Int}}\quad,\nonumber \\ + & \text{zwi}_{L}^{A}\triangleq\text{trav}_{L}^{F,A,A\times\text{Int}}(a^{:A}\rightarrow s^{:\text{Int}}\rightarrow(a\times s)\times(s+1))\bef\text{run}_{\text{State}}(0^{:\text{Int}})\quad.\label{eq:definition-of-zwi} +\end{align} +Here, $\text{run}_{\text{State}}(0^{:\text{Int}})$ is the \lstinline!State! monad\textsf{'}s runner defined by Eq.~(\ref{eq:definition-of-runState}) and applied to the zero integer value $0^{:\text{Int}}$: \[ @@ -4125,48 +4200,46 @@ \subsection{Laws of \texttt{traverse} and properties of \texttt{zipWithIndex}\la when applied to arbitrary traversable functors $L$? First, \lstinline!zipWithIndex! applied to a value $p:L^{A}$ should produce a value of type $L^{A\times\text{Int}}$ that preserves the structure of $p$ and just adds indices at places -where some data of type $A$ is stored within $p$. Second, \lstinline!zipWithIndex! +where data of type $A$ is stored within $p$. Second, \lstinline!zipWithIndex! should produce a \emph{different} index for every value of type $A$ -stored within $p$. Let us now formulate those intuitions as equations -that rigorously express the expected properties of \lstinline!zipWithIndex!. - -The first property is that the value $p:L^{A}$ must be restored if -we remove the index values: +stored within $p$. To express these properties rigorously, let us +formulate them as equations. -\begin{wrapfigure}{l}{0.5\columnwidth}% -\vspace{-1\baselineskip} +The first property is that the value $p:L^{A}$ must be recovered +if we drop the index values: \begin{lstlisting} p.zipWithIndex.map(_._1) == p \end{lstlisting} -\vspace{-0.5\baselineskip} -\end{wrapfigure}% - -~\vspace{-0.5\baselineskip} \[ -p\triangleright\text{zwi}_{L}\triangleright\pi_{1}^{\uparrow L}=p\quad. +p\triangleright\text{zwi}_{L}\triangleright\pi_{1}^{\uparrow L}=p\quad,\quad\text{or equivalently}:\quad\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}\quad. \] -The second property means that each index can be mapped to a distinct -value of type $A$ stored within $p$. Begin by computing a value -$q\triangleq p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}$ -of type $L^{\text{Int}}$. Then $q$ has the same structure as $p$ -but carries integer index values instead of values of type $A$. We -expect that the original data ($p$) can be restored if we replace -the index values in $q$ by the corresponding values of type $A$. -In other words, there should exist a function $f:\text{Int}\rightarrow A$ -such that $p$ can be restored from $f$ and $q$ as $p=q\triangleright f^{\uparrow L}$. -This also means that there should be an injective map from the type -$L^{A}$ to the type $(\text{Int}\rightarrow A)\times L^{\text{Int}}$. +The second property says that each distinct value of type $A$ stored +within $p$ should get a different index. To express this property +via an equation, begin by computing $\text{zwi}_{L}(p)$ and then +discard the values of type $A$, leaving only the indices. The result +is a value $q\triangleq p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}$ +of type $L^{\text{Int}}$. We expect $q$ to have the same shape and +structure as $p$ except that $q$ carries integer index values instead +of values of type $A$. The original value ($p$) can be restored +if we replace all index values in $q$ by the corresponding values +of type $A$. So, for any given $p$ there should exist a function +$f_{p}:\text{Int}\rightarrow A$ such that $p$ can be recovered from +$f_{p}$ and $q$ as $p=q\triangleright f_{p}^{\uparrow L}$. In other +words: +\[ +\forall p^{:L^{A}}:\quad p=p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright f_{p}^{\uparrow L}\quad. +\] We will now prove the first property of \lstinline!zipWithIndex!, assuming only that $L$ is a lawful traversable functor. In that proof, -we will need a special subtype of the \lstinline!State! monad: +we will use a special subtype of the \lstinline!State! monad. \subsubsection{Statement \label{subsec:Statement-constant-value-state-monad}\ref{subsec:Statement-constant-value-state-monad}} -We define a \textsf{``}constant-function \lstinline!State! monad\textsf{''}, denoted -by $\text{CFState}^{S,A}$, like this: Write the type of a \lstinline!State! -monad equivalently as $\text{State}^{S,A}\triangleq S\rightarrow A\times S\cong(S\rightarrow A)\times(S\rightarrow S)$ +Assume that the type $S$ is not void and define a \textsf{``}constant-function +\lstinline!State! monad\textsf{''}, which we denote by $\text{CFState}^{S,A}$, +like this: Rewrite the type of a \lstinline!State! monad as $\text{State}^{S,A}\triangleq S\rightarrow A\times S\cong(S\rightarrow A)\times(S\rightarrow S)$ and consider values of that type, $p^{:S\rightarrow A}\times q^{:S\rightarrow S}$, such that $p^{:S\rightarrow A}$ is a\emph{ constant} function (independent of its argument). In other words, the wrapped value of type $A$ is @@ -4179,33 +4252,28 @@ \subsubsection{Statement \label{subsec:Statement-constant-value-state-monad}\ref This is a subtype of $\text{State}^{S,A}$ because there is a function \lstinline!fromCF! of type $\text{CFState}^{S,A}\rightarrow\text{State}^{S,A}$ that is an identity function that merely reassigns types: -\[ -\text{fromCF}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\quad\quad\text{fromCF}\triangleq p^{:\_\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p^{:S\rightarrow A}\times q^{:S\rightarrow S}\quad. -\] +\begin{align*} + & \text{fromCF}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\\ + & \text{fromCF}\triangleq p^{:\_\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p^{:S\rightarrow A}\times q^{:S\rightarrow S}\quad. +\end{align*} Assuming that $S$ is not a void type, we then have the following properties: \textbf{(a)} The type $\text{CFState}^{S,A}$ is a monad with the -same implementation code as $\text{State}^{S,A}$. +same implementation as $\text{State}^{S,A}$. \textbf{(b)} The function \lstinline!fromCF! is an injective monad morphism and applicative morphism. -\textbf{(c)} The monad \lstinline!CFState! has a runner, $\text{run}_{\text{CFState}}:\text{CFState}^{S,A}\rightarrow A$, -defined by: +\textbf{(c)} Define a runner for the monad \lstinline!CFState! by: \[ -\text{run}_{\text{CFState}}\triangleq\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})\quad, +\text{run}_{\text{CFState}}:\text{CFState}^{S,A}\rightarrow A\quad,\quad\quad\text{run}_{\text{CFState}}\triangleq\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})\quad, \] -where $s_{0}^{:S}$ is a fixed value. The function $\text{run}_{\text{CFState}}$ -is the same for all choices of $s_{0}$ and is both a monad morphism -and an applicative morphism. (Note that $\text{run}_{\text{State}}(s_{0})$ -is neither a monad morphism nor an applicative morphism of type $\text{State}^{S,A}\rightarrow A$.) - -\textbf{(d)} The monad \lstinline!CFState! is equivalent to a \lstinline!Writer! -monad. There exists a one-to-one (bijective) monad morphism $\text{CFState}^{S,A}\rightarrow\text{Writer}^{W,A}$ -where $\text{Writer}^{W,A}\triangleq A\times W$ and the type $W\triangleq S\rightarrow S$ -is a function composition monoid (denoted by $\text{MF}^{S}$ in the -proof of Statement~\ref{subsec:Statement-foldleft-foldmap-equivalence}). +where $s_{0}^{:S}$ is a fixed value. Then the function $\text{run}_{\text{CFState}}$ +is the same for all choices of $s_{0}$ and is an applicative morphism +between $\text{CFState}^{S,A}$ and the identity functor. (Note that +$\text{run}_{\text{State}}(s_{0})$ is neither a monad morphism nor +an applicative morphism of type $\text{State}^{S,A}\rightarrow A$.) \subparagraph{Proof} @@ -4215,7 +4283,8 @@ \subsubsection{Statement \label{subsec:Statement-constant-value-state-monad}\ref \begin{align*} & \text{pu}_{\text{State}}:A\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\quad\quad\text{pu}_{\text{State}}=a^{:A}\rightarrow(\_^{:S}\rightarrow a)\times\text{id}^{:S\rightarrow S}\quad,\\ & \text{ftn}_{\text{State}}:(S\rightarrow(S\rightarrow A)\times(S\rightarrow S))\times(S\rightarrow S)\rightarrow(S\rightarrow A)\times(S\rightarrow S)\quad,\\ - & \text{ftn}_{\text{State}}=p^{:S\rightarrow(S\rightarrow A)\times(S\rightarrow S)}\times q^{:S\rightarrow S}\rightarrow(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{1}))\times(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{2}))\quad. + & \text{ftn}_{\text{State}}=p^{:S\rightarrow(S\rightarrow A)\times(S\rightarrow S)}\times q^{:S\rightarrow S}\\ + & \quad\quad\quad\quad\quad\rightarrow(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{1}))\times(s^{:S}\rightarrow s\triangleright q\triangleright(s\triangleright p\triangleright\pi_{2}))\quad. \end{align*} The code of $\text{pu}_{\text{State}}$ is already of type $A\rightarrow\text{CFState}^{S,A}$ because $\text{pu}_{\text{State}}(a)$ returns a \lstinline!State! @@ -4239,8 +4308,8 @@ \subsubsection{Statement \label{subsec:Statement-constant-value-state-monad}\ref \textbf{(b)} The code of the function \lstinline!fromCF! is an identity function that only reassigns types. This indicates that \lstinline!CFState! -is a subtype of \lstinline!State! (in the sense of subtyping explained -in Section~\ref{subsec:Covariance,-contravariance,-and-subtyping}). +is a subtype of \lstinline!State! (in the sense of \textsf{``}subtyping\textsf{''} +explained in Section~\ref{subsec:Covariance,-contravariance,-and-subtyping}). The code of $\text{pu}_{\text{CFState}}$ and $\text{ftn}_{\text{CFState}}$ is the same as the code of $\text{pu}_{\text{State}}$ and $\text{ftn}_{\text{State}}$ @@ -4258,50 +4327,85 @@ \subsubsection{Statement \label{subsec:Statement-constant-value-state-monad}\ref Here $s_{0}$ is an arbitrary value of type $S$. That value exists because $S$ is not a void type. -It remains to verify that $\text{fromCF}\bef\text{toCF}=\text{id}$. -For any constant function $p\triangleq\_^{:S}\rightarrow a_{0}$ we -will have $p(s_{0})=a_{0}$ and so we can write: -\[ -\text{fromCF}\bef\text{toCF}=p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow p(s_{0}))\times q=p\times q\rightarrow(\_\rightarrow a_{0})\times q=p\times q\rightarrow p\times q=\text{id}\quad. -\] - -\textbf{(c)} The code {*}{*}{*} +Now we will show that $\text{fromCF}\bef\text{toCF}=\text{id}$. For +any constant function $p\triangleq\_^{:S}\rightarrow a_{0}$, we have +$p(s_{0})=a_{0}$ and then: +\begin{align*} +\text{fromCF}\bef\text{toCF} & =p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow p(s_{0}))\times q\\ + & =p\times q\rightarrow(\_\rightarrow a_{0})\times q=p\times q\rightarrow p\times q=\text{id}\quad. +\end{align*} -\textbf{(d)} A value of type $\text{CFState}^{S,A}=(\_^{:S}\rightarrow A)\times(S\rightarrow S)$ -is a pair of a constant function and a value of type $W$. When $S$ -is not void, the type of constant functions $(\_^{:S}\rightarrow A)$ -is equivalent to the type $A$: we can substitute an arbitrary value -$s_{0}:S$ into a constant function and obtain the corresponding value -of type $A$. So, we have the type equivalence $\text{CFState}^{S,A}\cong A\times(S\rightarrow S)\triangleq A\times W$. -The isomorphism is given by a function \lstinline!inCF! defined by: +\textbf{(c)} To see that the code of $\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})$ +does not depend on $s_{0}$, we first adapt the \lstinline!State! +monad\textsf{'}s runner ($\text{run}_{\text{State}}$) to the type $(S\rightarrow A)\times(S\rightarrow S)$, +which is equivalent to the type $\text{State}^{S,A}$: \[ -\text{inCF}:\text{Writer}^{W,A}\rightarrow\text{CFState}^{S,A}\quad,\quad\quad\text{inCF}\triangleq a^{:A}\times w^{:S\rightarrow S}\rightarrow(\_^{:S}\rightarrow a)\times w\quad. +\text{run}_{\text{State}}(s_{0})=(p^{:S\rightarrow A}\times q^{:S\rightarrow S})\rightarrow\big(p(s_{0})\times q(s_{0})\big)\triangleright\pi_{1}=p^{:S\rightarrow A}\times q^{:S\rightarrow S}\rightarrow p(s_{0})\quad. \] +Now we take any value $c$ of type $\text{CFState}^{S,A}$ and write: +\begin{align*} + & c\triangleright\text{fromCF}\bef\text{run}_{\text{State}}(s_{0})=(p^{:\_^{:S}\rightarrow A}\times q^{:S\rightarrow S})\triangleright\text{fromCF}\triangleright\text{run}_{\text{State}}(s_{0})\\ + & =(p\times q)\triangleright\text{run}_{\text{State}}(s_{0})=p(s_{0})\quad. +\end{align*} +The last value does not depend on $s_{0}$ because $p$ is a constant +function. + +To show that $\text{run}_{\text{CFState}}$ is an applicative morphism +between the applicative functors $\text{CFState}^{S,A}$ and $\text{Id}$, +first note that the \lstinline!pure! method of \lstinline!CFState! +is the same as that of the \lstinline!State! monad. A \textsf{``}pure\textsf{''} +value $\text{pu}_{\text{CFState}}(a^{:A})$ equals the function $s\rightarrow a\times s$. +Applying $\text{run}_{\text{State}}(s_{0})$ to the function $s\rightarrow a\times s$ +will always return just the value $a$. This is the same as the identity +functor\textsf{'}s \lstinline!pure! method (which is an identity function) +applied to the value \lstinline!a!. So, $\text{run}_{\text{CFState}}$ +will map \lstinline!CFState!\textsf{'}s \lstinline!pure! into the identity +functor\textsf{'}s \lstinline!pure!. + +It remains to show that $\text{run}_{\text{CFState}}$ maps \lstinline!CFState!\textsf{'}s +\lstinline!zip! method into the identity functor\textsf{'}s \lstinline!zip! +method (which is again an identity function, $a\times b\rightarrow a\times b$). +The code of \lstinline!CFState!\textsf{'}s \lstinline!zip! is: +\begin{align*} + & \text{zip}_{\text{CFState}}:(\_^{:S}\rightarrow A)\times(S\rightarrow S)\times(\_^{:S}\rightarrow B)\times(S\rightarrow S)\rightarrow(\_^{:S}\rightarrow A\times B)\times(S\rightarrow S)\quad,\\ + & \text{zip}_{\text{CFState}}:p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\times p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S}\rightarrow(s^{:S}\rightarrow p_{1}(s)\times p_{2}(s))\times(q_{1}\bef q_{2})\quad. +\end{align*} +The function $s^{:S}\rightarrow p(s)\times q(s)$ is a constant function +because $p$ and $q$ are. -It remains to verify that \lstinline!inCF! is a monad morphism. To -verify the identity law: +Applying $\text{zip}_{\text{CFState}}$ to arbitrary values: +\begin{align*} + & c_{1}:\text{CFState}^{S,A}\quad,\quad\quad c_{1}=p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\quad,\\ + & c_{2}:\text{CFState}^{S,B}\quad,\quad\quad c_{2}=p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S}\quad, +\end{align*} + and then applying $\text{run}_{\text{CFState}}$, we get: \begin{align*} - & \text{pu}_{\text{Writer}}\bef\text{inCF}=(a^{:A}\rightarrow a\times\text{id})\bef(a\times w\rightarrow(\_\rightarrow a)\times w)\\ - & =a\rightarrow(\_\rightarrow a)\times\text{id}=\text{pu}_{\text{State}}=\text{pu}_{\text{CFState}}\quad. + & (p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S}\times p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S})\triangleright\text{zip}_{\text{CFState}}\triangleright\text{run}_{\text{CFState}}\\ + & =(s^{:S}\rightarrow p_{1}(s)\times p_{2}(s))\times(q_{1}\bef q_{2})\triangleright\text{run}_{\text{CFState}}\\ + & =p_{1}(s_{0})\times p_{2}(s_{0})\quad. \end{align*} +Applying $\text{run}_{\text{CFState}}$ to the initial values, we +find: +\[ +(p_{1}^{:\_^{:S}\rightarrow A}\times q_{1}^{:S\rightarrow S})\triangleright\text{run}_{\text{CFState}}=p_{1}(s_{0})\quad,\quad\quad(p_{2}^{:\_^{:S}\rightarrow B}\times q_{2}^{:S\rightarrow S})\triangleright\text{run}_{\text{CFState}}=p_{2}(s_{0})\quad. +\] +So, the composition law of applicative morphisms holds: +\[ +(c_{1}\times c_{2})\triangleright\text{zip}_{\text{CFState}}\triangleright\text{run}_{\text{CFState}}=(c_{1}\triangleright\text{run}_{\text{CFState}})\times(c_{2}\triangleright\text{run}_{\text{CFState}})\quad. +\] $\square$ We are now ready to prove the first property of \lstinline!zipWithIndex!. \subsubsection{Statement \label{subsec:Statement-properties-of-zipWithIndex}\ref{subsec:Statement-properties-of-zipWithIndex}} -For any lawful traversable functor $L$, define the function \lstinline!zipWithIndex! +For any traversable functor $L$, define \lstinline!zipWithIndex! (denoted for brevity by $\text{zwi}_{L}$) via Eq.~(\ref{eq:definition-of-zwi}). -Then \lstinline!zipWithIndex! satisfies the equation: $\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}^{:L^{A}\rightarrow L^{A}}$. - -\textbf{(b)} There exists a \textsf{``}tabulating\textsf{''} function (denoted by -$\text{tab}_{L}^{A}$): +Then \lstinline!zipWithIndex! satisfies the equation: \[ -\text{tab}_{L}^{A}:L^{A\times\text{Int}}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad, +\text{zwi}_{L}\bef\pi_{1}^{\uparrow L}=\text{id}^{:L^{A}\rightarrow L^{A}}\quad. \] -such that $\text{zwi}_{L}\bef\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})=\text{id}^{:L^{A}\rightarrow L^{A}}$. -So, the function $\text{zwi}_{L}\bef\text{tab}_{L}$ is an injective -map of type $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$. + \subparagraph{Proof} @@ -4348,9 +4452,10 @@ \subsubsection{Statement \label{subsec:Statement-properties-of-zipWithIndex}\ref with $B\triangleq A$, $F^{A}\triangleq\text{CFState}^{\text{Int},A}$, $G^{A}\triangleq\text{State}^{\text{Int},A}$, $f^{:F^{B}\rightarrow G^{B}}=$ \lstinline!fromCF!, and $g^{:A\rightarrow F^{B}}=h$: -\[ -\text{trav}_{L}^{G,A,B}(g\bef f)=\text{trav}_{L}^{F,A,B}(g)\bef f\quad\quad\text{or equivalently:}\quad\quad\text{trav}_{L}(h\bef\text{fromCF})=\text{trav}_{L}(h)\bef\text{fromCF}\quad. -\] +\begin{align*} + & \text{trav}_{L}^{G,A,B}(g\bef f)=\text{trav}_{L}^{F,A,B}(g)\bef f\\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{trav}_{L}(h\bef\text{fromCF})=\text{trav}_{L}(h)\bef\text{fromCF}\quad. +\end{align*} Statement~\ref{subsec:Statement-constant-value-state-monad}(c) gives the formula $\text{run}_{\text{CFState}}=\text{fromCF}\bef r$, so we write: @@ -4370,12 +4475,120 @@ \subsubsection{Statement \label{subsec:Statement-properties-of-zipWithIndex}\ref \end{align*} $\square$ -The second property of \lstinline!zipWithIndex! does \emph{not} seem -to be provable using the laws of traverse; see Problem~\ref{par:Problem-traverse-law}(b). -However, it appears to be natural to expect that \lstinline!zipWithIndex! +The second property of \lstinline!zipWithIndex! says that \lstinline!zipWithIndex! assigns different indices to each value of type $A$ stored inside -a data structure of type $L^{A}$. Perhaps another law of \lstinline!traverse! -is needed? +a data structure of type $L^{A}$. This property does \emph{not} seem +to be provable using the two laws of \lstinline!traverse!. One reason +is that an \textsf{``}indexing\textsf{''} function $f_{p}:\text{Int}\rightarrow A$ +can be computed only by traversing the entire data structure $p$. +In other words, $f$ is itself a result of a traversal operation. +We want to prove a property of \lstinline!traverse! that combines +$f$ with another traversal (\lstinline!zipWithIndex!) of the same +initial data ($p$). But there are no laws of \lstinline!traverse! +that involve composition of traversals of the same initial container. +A new law of \lstinline!traverse! is necessary. + +Such a law (involving inverse-order traversals) was first proposed +in 2012.\footnote{See \texttt{\href{https://www.cs.ox.ac.uk/jeremy.gibbons/publications/backwards.pdf}{https://www.cs.ox.ac.uk/jeremy.gibbons/publications/backwards.pdf}}} +One year later, R.~Bird\index{Richard Bird} et al.~showed that +the second property of \lstinline!zipWithIndex! can be derived for +arbitrary polynomial functors $L$ without assuming any new laws of +\lstinline!traverse! by using techniques motivated by dependent type +theory.\footnote{\label{fn:uitbaf}See \texttt{\href{https://www.cs.ox.ac.uk/jeremy.gibbons/publications/uitbaf.pdf}{https://www.cs.ox.ac.uk/jeremy.gibbons/publications/uitbaf.pdf}}} +Those techniques are beyond the scope of this book, as the required +theory is complicated but has limited practical use. Because all polynomial +functors are traversable (and no other functors are), it is not as +important to be able to characterize \lstinline!traverse! solely +via laws. In practice, there is no uncertainty about how to implement +a law-abiding \lstinline!traverse! correctly, for any given polynomial +functor and any traversal order. + +It will suffice for our purposes to use the following statement from +Bird et al.: + +\subsubsection{Statement \label{subsec:Statement-Bird-representation-theorem-for-traversal}\ref{subsec:Statement-Bird-representation-theorem-for-traversal}} + +Given a traversable functor $L$ and a value $p:L^{A}$, there exists +an integer $n\ge0$ and a function \lstinline!make[A]! with type +signature: +\[ +\text{make}:\forall A.\,\underbrace{A\times A\times...\times A}_{n\text{ times}}\rightarrow L^{A}\quad, +\] +such that $p=\text{make}^{A}(a_{1}\times...\times a_{n})$ with suitable +values $a_{1}$, ..., $a_{n}$ of type $A$. The function \lstinline!make[A]! +is natural in the type parameter \lstinline!A!: +\[ +\text{for any }f^{:A\rightarrow B}:\quad(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}\triangleright f^{\uparrow L}=(f(a_{1})\times...\times f(a_{n}))\triangleright\text{make}^{B}\quad. +\] +The \lstinline!traverse! method of $L$ is expressed via \lstinline!make! +and the values $a_{1}$, ..., $a_{n}$ as: +\begin{align*} + & \quad{\color{greenunder}\text{for any }g^{:A\rightarrow F^{B}}:}\quad\\ + & p\triangleright\text{trav}_{L}(g)=\big(\text{zip}_{L}(g(a_{1})\times\text{zip}_{L}(g(a_{2})\times...\times\text{zip}_{L}(g(a_{n-1})\times g(a_{n}))...)\big)\triangleright\text{restore}^{\uparrow F}\quad,\\ + & \quad{\color{greenunder}\text{where we defined}:}\quad\\ + & \text{restore}\triangleq b_{1}\times(b_{2}\times(...\times(b_{n-1}\times b_{n})...)\rightarrow\text{make}^{B}(b_{1}\times...\times b_{n})\quad. +\end{align*} + + +\subparagraph{Proof} + +This is proved by Bird et al.\footnote{See Footnote~\ref{fn:uitbaf} on page~\pageref{fn:uitbaf}.}~as +the \textsf{``}representation theorem\textsf{''}. $\square$ + +\subsubsection{Statement \label{subsec:Statement-polynomial-functors-Int-A}\ref{subsec:Statement-polynomial-functors-Int-A}} + +For any traversable functor $L$, any type $A$, and any value $p^{:L^{A}}$: + +\textbf{(a)} There is a function $t_{p}:\text{Int}\rightarrow A$ +such that \lstinline!zipWithIndex! satisfies: +\[ +p=p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright t_{p}^{\uparrow L}\quad. +\] + +\textbf{(b)} There exists an injective function of type $L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$. + +\subparagraph{Proof} + +\textbf{(a)} By Statement~\ref{subsec:Statement-Bird-representation-theorem-for-traversal}, +there exist $a_{1}$, ..., $a_{n}$ of type $A$ such that: +\[ +p=(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}\quad. +\] +Then the definition of \lstinline!zipWithIndex! is evaluated to: +\[ +p\triangleright\text{zwi}_{L}=\big((a_{1}\times1^{:\text{Int}})\times(a_{2}\times2^{:\text{Int}})\times...\times(a_{n}\times n^{:\text{Int}})\big)\triangleright\text{make}^{A\times\text{Int}}\quad. +\] +By the naturality law of \lstinline!make!, we get: +\[ +p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}=\big(1^{:\text{Int}}\times2^{:\text{Int}}\times...\times n^{:\text{Int}}\big)\triangleright\text{make}^{\text{Int}}\quad. +\] +Now we define $t_{p}$ as a (partial) function of type $\text{Int}\rightarrow A$ +such that +\[ +t_{p}(i)\triangleq a_{i}\quad,\quad i=1,2,...,n\quad. +\] +We again use the naturality law of \lstinline!make! and prove the +required property: +\begin{align*} + & p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}\triangleright t_{p}^{\uparrow L}=\big(t_{p}(1)\times...\times t_{p}(n)\big)\triangleright\text{make}^{\text{Int}}\\ + & \quad=(a_{1}\times...\times a_{n})\triangleright\text{make}^{A}=p\quad. +\end{align*} + +\textbf{(b)} Note that $p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L}$ +is a value of type $L^{\text{Int}}$. We can combine that function +with $t_{p}$ and define a \textsf{``}tabulating\textsf{''} function (denoted by $\text{tab}_{L}$): +\begin{align*} + & \text{tab}_{L}^{A}:L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}\quad,\\ + & \text{tab}_{L}^{A}\triangleq p^{:L^{A}}\rightarrow t_{p}\times(p\triangleright\text{zwi}_{L}\triangleright\pi_{2}^{\uparrow L})\quad. +\end{align*} +Then the property of $\text{zwi}_{L}$ from \textbf{(a)} is rewritten +as: +\[ +\text{tab}_{L}\bef(f^{:\text{Int}\rightarrow A}\times q^{:L^{\text{Int}}}\rightarrow q\triangleright f^{\uparrow L})\overset{!}{=}\text{id}^{:L^{A}\rightarrow L^{A}}\quad. +\] +So, the function $\text{tab}_{L}$ is an injective function of type +$L^{A}\rightarrow(\text{Int}\rightarrow A)\times L^{\text{Int}}$. +$\square$ \subsection{Traversable contrafunctors and profunctors are not useful} @@ -4495,9 +4708,10 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab \] Then $L$ is a lawful traversable functor with the \lstinline!sequence! function defined as: -\[ -\text{seq}_{L}^{F,A}:S^{F^{A},L^{P^{F^{A}}}}\rightarrow F^{S^{A,L^{P^{A}}}}\quad,\quad\quad\text{seq}_{L}^{F,A}\triangleq\big(\text{seq}_{P}^{F,A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{F,P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}\bef\text{seq2}_{S}^{F,A,L^{P^{A}}}\quad. -\] +\begin{align*} + & \text{seq}_{L}^{F,A}:S^{F^{A},L^{P^{F^{A}}}}\rightarrow F^{S^{A,L^{P^{A}}}}\quad,\\ + & \text{seq}_{L}^{F,A}\triangleq\big(\text{seq}_{P}^{F,A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{F,P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}\bef\text{seq2}_{S}^{F,A,L^{P^{A}}}\quad. +\end{align*} \[ \xymatrix{\xyScaleY{1.4pc}\xyScaleX{6pc}S^{F^{A},L^{P^{F^{A}}}}\ar[r]\sp(0.5){\big(\text{seq}_{P}^{F,A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}} & S^{F^{A},L^{F^{P^{A}}}}\ar[r]\sp(0.5){\big(\overline{\text{seq}}_{L}^{F,P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}} & S^{F^{A},F^{L^{P^{A}}}}\ar[r]\sp(0.5){\text{seq2}_{S}^{F,A,L^{P^{A}}}} & F^{S^{A,L^{P^{A}}}}} \] @@ -4512,12 +4726,13 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab \text{seq}_{L}^{\text{Id},A}=\big(\text{seq}_{P}^{\text{Id},A}\big)^{\uparrow L\uparrow S^{F^{A},\bullet}}\bef\big(\overline{\text{seq}}_{L}^{\text{Id},P^{A}}\big)^{\uparrow S^{F^{A},\bullet}}\bef\text{seq2}_{S}^{\text{Id},A,L^{P^{A}}}=\text{id}^{\uparrow L\uparrow S}\bef\text{id}^{\uparrow S}\bef\text{id}=\text{id}\quad. \] To verify the composition law~(\ref{eq:composition-law-of-sequence}), -write its two sides, omitting some type parameters for brevity: +write its two sides: \begin{align*} - & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}\\ - & \quad=\big(\text{seq}_{P}^{F,G^{A}}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad,\\ + & \text{seq}_{L}^{F,G^{A}}\bef(\text{seq}_{L}^{G,A})^{\uparrow F}=\big(\text{seq}_{P}^{F,G^{A}}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\\ + & \quad\quad\quad\quad\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad,\\ & \text{seq}_{L}^{F\circ G,A}=\big(\text{seq}_{P}^{F\circ G,A}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F\circ G,P^{A}}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F\circ G,A,L^{P^{A}}}\\ - & \quad=\big(\text{seq}_{P}^{F,G^{A}}\bef(\text{seq}_{P}^{G,A})^{\uparrow F}\big)^{\uparrow L\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{F,G^{P^{A}}}\bef(\overline{\text{seq}}_{L}^{G,P^{A}})^{\uparrow F}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\bef\big(\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad. + & \quad=\big(\text{seq}_{P}^{F,G^{A}}\bef(\text{seq}_{P}^{G,A})^{\uparrow F}\big)^{\uparrow L\uparrow S}\\ + & \quad\quad\quad\quad\bef\big(\overline{\text{seq}}_{L}^{F,G^{P^{A}}}\bef(\overline{\text{seq}}_{L}^{G,P^{A}})^{\uparrow F}\big)^{\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\bef\big(\text{seq2}_{S}^{G,A,L^{P^{A}}}\big)^{\uparrow F}\quad. \end{align*} To get the last line, we used the assumed composition laws of $\text{seq}_{P}$, $\overline{\text{seq}}_{L}$, and $\text{seq2}_{S}$. @@ -4536,8 +4751,7 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab \begin{align*} {\color{greenunder}\text{left-hand side}:}\quad & \big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\gunderline{\text{seq2}_{S}^{F,G^{A},L^{P^{G^{A}}}}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L}\bef\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow S\uparrow F}}\\ {\color{greenunder}\text{naturality law of }\text{seq2}_{S}:}\quad & =\gunderline{\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\big)^{\uparrow S}\bef\big((\text{seq}_{P}^{G,A})^{\uparrow L}\bef\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\\ -{\color{greenunder}\text{composition under }^{\uparrow S}:}\quad & =\big(\gunderline{\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\quad.\\ -{\color{greenunder}\text{naturality law of }\overline{\text{seq}}_{L}:}\quad & =\big(\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}} +{\color{greenunder}\text{composition under }^{\uparrow S}:}\quad & =\big(\gunderline{\overline{\text{seq}}_{L}^{F,P^{G^{A}}}\bef(\text{seq}_{P}^{G,A})^{\uparrow L\uparrow F}}\big)^{\uparrow S}\bef\big(\overline{\text{seq}}_{L}^{G,P^{A}}\big)^{\uparrow F\uparrow S}\bef\text{seq2}_{S}^{F,G^{A},G^{L^{P^{A}}}}\quad. \end{align*} It remains to show that: \[ @@ -4631,10 +4845,50 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab of type $F^{A\times A\times...\times A}$, which we will then need to convert to the type $F^{N\times N\rightarrow A}$. The only way of performing these computations is by enumerating all possible values -of type $N$. +of type $N$.Note that the type \lstinline!Sq! sets the type parameter +\lstinline!N! in \lstinline!SqSize[N, A]! as \lstinline!N = Unit!. +This forces the type parameters \lstinline!N! in all of the \lstinline!Next()! +constructors to be \lstinline!Unit! wrapped in a number of \lstinline!Option! +constructors. All values of a type of this form can be enumerated +explicitly. However, the type \lstinline!SqSize[N, A]! does not ensure +that \lstinline!N! will be a type with a known finite number of values. +This problem prevents us from implementing the \lstinline!sequence! +method for our current definition of \lstinline!Sq!. + +A solution is to add a typeclass constraint (with a typeclass called +\textsf{``}\lstinline!Finite!\textsf{''}) on the type parameter \lstinline!N!. A +suitable typeclass instance of \lstinline!Finite[N]! contains a list +of all values of type \lstinline!N!: +\begin{lstlisting} +type Finite[N] = List[N] // A list of all possible values of type N. +\end{lstlisting} +We can implement functions that create typeclass instances automatically +for all the types we will actually use instead of the type parameter +\lstinline!N!, namely, the types \lstinline!Unit!, \lstinline!Option[Unit]!, +\lstinline!Option[Option[Unit]]! and so on. Suitable typeclass instances +are defined inductively: +\begin{lstlisting} +implicit val finiteUnit: Finite[Unit] = List(()) +implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map(Some(_)) +\end{lstlisting} + +Using these definitions, we can now extract all values of type $A$ +from a value of type $N\times N\rightarrow A$: +\begin{lstlisting} +def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { + case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) + case Next(next) => access[Option[N], A](next, i, j) +} +\end{lstlisting} +Let us test this code: +\begin{lstlisting} +scala> access(matrix2x2, 0, 1) +res0: Int = 12 +\end{lstlisting} + +Here is the complete code of \lstinline!sequence! for the type constructor +\lstinline!Sq!: -\begin{figure} -\begin{centering} \begin{lstlisting}[frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm] type Finite[N] = List[N] // A list of all possible values of type N. @@ -4668,7 +4922,7 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab (0 until length).map(i => (0 until length).map(j => access(s, i, j))) } -// Test: visualize the matrix defined previously by converting it to nested lists. +// Test: visualize matrix2x2 by converting it to nested lists. scala> toSeqSeq(matrix2x2) res1: List[List[Int]] = List(List(11, 12), List(21, 22)) @@ -4693,56 +4947,9 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab case Next(next) => sequence[Option[N], F, A](next).map(Next(_)) } \end{lstlisting} -\par\end{centering} -\caption{Implementing \lstinline!sequence! for square matrices.\label{fig:Full-code-implementing-traverse-for-square-matrix}} -\end{figure} - -Note that the type \lstinline!Sq! sets the type parameter \lstinline!N! -in \lstinline!SqSize[N, A]! as \lstinline!N = Unit!. This forces -the type parameters \lstinline!N! in all of the \lstinline!Next()! -constructors to be \lstinline!Unit! wrapped in a number of \lstinline!Option! -constructors. All values of a type of this form can be enumerated -explicitly. However, the type \lstinline!SqSize[N, A]! does not ensure -that \lstinline!N! will be a type with a known finite number of values. -This problem prevents us from implementing the \lstinline!sequence! -method for our current definition of \lstinline!Sq!. - -A solution is to add a typeclass constraint (with a typeclass called -\textsf{``}\lstinline!Finite!\textsf{''}) on the type parameter \lstinline!N!. A -suitable typeclass instance of \lstinline!Finite[N]! contains a list -of all values of type \lstinline!N!: -\begin{lstlisting} -type Finite[N] = List[N] // A list of all possible values of type N. -\end{lstlisting} -We can implement functions that create typeclass instances automatically -for all the types we will actually use instead of the type parameter -\lstinline!N!, namely, the types \lstinline!Unit!, \lstinline!Option[Unit]!, -\lstinline!Option[Option[Unit]]! and so on. Suitable typeclass instances -are defined inductively: -\begin{lstlisting} -implicit val finiteUnit: Finite[Unit] = List(()) -implicit def finiteOptionN[N: Finite]: Finite[Option[N]] = None +: Finite[N].map(Some(_)) -\end{lstlisting} -Using these definitions, we can now extract all values of type $A$ -from a value of type $N\times N\rightarrow A$: -\begin{lstlisting} -def access[N: Finite, A](s: SqSize[N, A], i: Int, j: Int): A = s match { - case Matrix(byIndex) => byIndex((Finite[N].apply(i), Finite[N].apply(j))) - case Next(next) => access[Option[N], A](next, i, j) -} -\end{lstlisting} -Let us test this code: -\begin{lstlisting} -scala> access(matrix2x2, 0, 1) -res0: Int = 12 -\end{lstlisting} - -Figure~\ref{fig:Full-code-implementing-traverse-for-square-matrix} -shows the complete code of \lstinline!sequence! for \lstinline!Sq!. -For testing (Figure~\ref{fig:Full-code-implementing-traverse-for-square-matrix-tests}), -we define a value \lstinline!matrix2x2List! that represents a square -matrix of lists: +To test this code, we define a value \lstinline!matrix2x2List! that +represents a square matrix of lists: \[ \text{matrix2x2List}:\text{Sq}^{\text{List}^{\text{Int}}}\quad,\quad\quad\text{matrix2x2List}\triangleq\left|\begin{array}{cc} \left[0,10,100\right] & \left[1,11,101\right]\\ @@ -4755,19 +4962,16 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab \text{seq}_{\text{Sq}}\,(\text{matrix2x2List})=\big[\left|\begin{array}{cc} 0 & 1\\ 2 & 3 -\end{array}\right|,\left|\begin{array}{cc} +\end{array}\right|,\,\left|\begin{array}{cc} 10 & 11\\ 12 & 13 -\end{array}\right|,\left|\begin{array}{cc} +\end{array}\right|,\,\left|\begin{array}{cc} 100 & 101\\ 102 & 103 \end{array}\right|\big]\quad. \] This represents a kind of transposition operation for tensors of dimension -$2\times2\times3$. - -\begin{figure} -\begin{centering} +$2\times2\times3$. The test code is: \begin{lstlisting}[frame=single,fillcolor={\color{black}},framesep={0.2mm},framexleftmargin=2mm,framexrightmargin=2mm,framextopmargin=2mm,framexbottommargin=2mm] // Test: use List as an Applicative Functor. implicit val applicativeList: Applicative[List] = new Applicative[List] { @@ -4794,9 +4998,6 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab scala> toSeqSeq(list2x2Matrix) res1: List[List[List[Int]]] = List(List(List(0, 1), List(2, 3)), List(List(10, 11), List(12, 13)), List(List(100, 101), List(102, 103))) \end{lstlisting} -\par\end{centering} -\caption{Tests for the \lstinline!sequence! method implemented in Figure~\ref{fig:Full-code-implementing-traverse-for-square-matrix}.\label{fig:Full-code-implementing-traverse-for-square-matrix-tests}} -\end{figure} The type \lstinline!Sq[A]! assures (at compile time) that all matrices have consistent shapes. However, it is hard to use because of complicated @@ -4807,7 +5008,7 @@ \subsubsection{Statement \label{subsec:Statement-nested-recursive-type-traversab time, one could use macros or other metaprogramming features to assure that all matrix operations are consistent, without resorting to complicated type constructors. Alternatively, one can use dependent types to constrain -matrix dimensions at compile time.\footnote{See, for example, the \texttt{NDScala} library for Scala 3: \href{https://github.com/SciScala/NDScala}{https://github.com/SciScala/NDScala}} +matrix dimensions at compile time.\footnote{See, for example, the \texttt{NDScala} library for Scala 3: \texttt{\href{https://github.com/SciScala/NDScala}{https://github.com/SciScala/NDScala}}} \begin{comment} this is chapter 9 of the functional programming tutorial traversable functors to motivate the interrupted introduction of these factors diff --git a/sofp-src/sofp-typeclasses.lyx b/sofp-src/sofp-typeclasses.lyx index 7b2d4de58..980531642 100644 --- a/sofp-src/sofp-typeclasses.lyx +++ b/sofp-src/sofp-typeclasses.lyx @@ -191,7 +191,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \master sofp.lyx \maintain_unincluded_children false @@ -11258,7 +11258,7 @@ status open \begin_layout Plain Layout -def f(x: Int): Int = x + 1 +def f(i: Int): Int = i + 1 \end_layout \begin_layout Plain Layout @@ -14201,8 +14201,8 @@ Eq \end_inset - instance is unambiguous and can be automated with libraries such as the - + instance is unambiguous and can be in many cases performed automatically + with libraries such as \family typewriter kittens \family default @@ -14248,11 +14248,11 @@ literal "false" \end_inset - or + \family typewriter scalaz-deriving \family default -. +, \begin_inset Foot status open @@ -14267,6 +14267,29 @@ literal "false" \end_inset +\end_layout + +\end_inset + + and +\family typewriter +zio-deriving +\family default +. +\begin_inset Foot +status open + +\begin_layout Plain Layout + +\family typewriter +\begin_inset CommandInset href +LatexCommand href +target "https://github.com/zio/zio-deriving" +literal "false" + +\end_inset + + \end_layout \end_inset @@ -15555,8 +15578,12 @@ status open \begin_layout Plain Layout -Left(x) |+| Left(y) |+| Left(z) == Left(x |+| y |+| z) == Left(x) |+| ( - Left(y) |+| Left(z) ) +Left(x) |+| Left(y) |+| Left(z) == Left(x |+| y |+| z) +\end_layout + +\begin_layout Plain Layout + + == Left(x) |+| ( Left(y) |+| Left(z) ) \end_layout \end_inset @@ -18841,7 +18868,7 @@ status open \begin_inset Formula $124$ \end_inset -; any other result would break our intuition about +; any other result would contradict our intuition about \begin_inset Quotes eld \end_inset @@ -18850,7 +18877,7 @@ wrapping \end_inset . - We can generalize this situation to an arbitrary value + We can generalize this idea to an arbitrary value \begin_inset Formula $x^{:A}$ \end_inset @@ -18940,26 +18967,12 @@ pure \end_inset -; it must hold for any +. + For any \begin_inset Formula $f^{:A\rightarrow B}$ \end_inset : -\end_layout - -\begin_layout Standard -\begin_inset Wrap figure -lines 0 -placement l -overhang 0in -width "40col%" -status open - -\begin_layout Plain Layout -\begin_inset VSpace -80baselineskip% -\end_inset - - \begin_inset listings inline false status open @@ -18972,23 +18985,6 @@ pure(x).map(f) == pure(f(x)) \end_inset -\begin_inset VSpace -50baselineskip% -\end_inset - - -\end_layout - -\end_inset - - -\end_layout - -\begin_layout Standard -\noindent -\begin_inset VSpace -50baselineskip% -\end_inset - - \begin_inset Formula \[ \text{pu}_{F}(x)\triangleright f^{\uparrow F}=\text{pu}_{F}(f(x))\quad. @@ -19037,7 +19033,7 @@ B\ar[r]\sp(0.5){\text{pu}_{F}} & F^{B} \end_inset This motivates the following definition: A functor -\begin_inset Formula $F^{\bullet}$ +\begin_inset Formula $F$ \end_inset is @@ -19342,7 +19338,7 @@ def pure[A](x: A): F[A] = wu.map { _ => x } \end_inset -In code notation: + \begin_inset Formula \begin{equation} \text{pu}_{F}^{:A\rightarrow F^{A}}\triangleq x^{:A}\rightarrow\text{wu}_{F}\triangleright(\_\rightarrow x)^{\uparrow F}\quad.\label{eq:pu-via-wu-def} @@ -19350,12 +19346,15 @@ In code notation: \end_inset -Does this function satisfy the naturality law with respect to an arbitrary - +The function +\begin_inset Formula $\text{pu}_{F}$ +\end_inset + + obeys the naturality law with respect to an arbitrary \begin_inset Formula $f^{:A\rightarrow B}$ \end_inset -? It does: +: \begin_inset Formula \begin{align*} \text{expect to equal }x\triangleright f\bef\text{pu}_{F}:\quad & x\triangleright\text{pu}_{F}\bef f^{\uparrow F}\\ @@ -22765,12 +22764,11 @@ f^{\uparrow F} & \bbnum 0\\ \end{array}\,\bef\,\begin{array}{||c|} \text{ex}_{F}\\ \text{ex}_{G} -\end{array}\\ -\text{matrix function composition}:\quad & =\,\,\begin{array}{||c|} +\end{array}\,=\,\begin{array}{||c|} \gunderline{f^{\uparrow F}\bef\text{ex}_{F}}\\ \gunderline{f^{\uparrow G}\bef\text{ex}_{G}} \end{array}\\ -\text{naturality laws of }\text{ex}_{F}\text{ and }\text{ex}_{G}:\quad & =\,\begin{array}{||c|} +\text{naturality laws of }\text{ex}_{F}\text{ and }\text{ex}_{G}:\quad & =\,\,\begin{array}{||c|} \text{ex}_{F}\,\gunderline{\bef f}\\ \text{ex}_{G}\,\gunderline{\bef f} \end{array}\,=\,\gunderline{\begin{array}{||c|} @@ -23901,13 +23899,14 @@ pointed : \begin_inset Formula -\begin{equation} -\text{cpu}_{C}\triangleright f^{\downarrow C}=\text{cpu}_{C}\quad,\quad\text{or equivalently}:\quad\text{cmap}_{C}(f^{:A\rightarrow B})(\text{cpu}_{C}^{:C^{B}})=\text{cpu}_{C}^{:C^{A}}\quad.\label{eq:naturality-law-for-pure-for-contrafunctors} -\end{equation} +\begin{align} + & \text{cpu}_{C}\triangleright f^{\downarrow C}=\text{cpu}_{C}\quad,\label{eq:naturality-law-for-pure-for-contrafunctors}\\ +\text{or equivalently}:\quad & \text{cmap}_{C}(f^{:A\rightarrow B})(\text{cpu}_{C}^{:C^{B}})=\text{cpu}_{C}^{:C^{A}}\quad.\nonumber +\end{align} \end_inset - +This is illustrated by the type diagram: \begin_inset Formula \[ \xymatrix{\xyScaleY{2.0pc}\xyScaleX{3.0pc}\bbnum 1\ar[rd]\sb(0.5){}\ar[r]\sb(0.5){} & \text{cpu}_{C}:C^{B}\ar[d]\sp(0.45){\text{cmap}_{C}(f)}\\ @@ -28458,8 +28457,12 @@ def f[F[_]: Functor, A, B](p: F[(A, B)]): (F[A], F[B]) = \begin_layout Plain Layout - (p.map { case (a, b) => a }, p.map { case (a, b) => b }) // Or (p.map(_._1), - p.map(_._2)) + (p.map { case (a, b) => a }, p.map { case (a, b) => b }) +\end_layout + +\begin_layout Plain Layout + +// Shorter code: (p.map(_._1), p.map(_._2)) \end_layout \end_inset @@ -28517,7 +28520,7 @@ we will find that \emph on can \emph default - be implemented for functors such as + be implemented for functors \begin_inset Formula $F^{A}\triangleq A\times A$ \end_inset @@ -35195,8 +35198,7 @@ implicit val c1 = Semigroup[Int](_ + _) \begin_layout Plain Layout -implicit val c2 = Monoid[Int](0) // Works only if a `Semigroup[Int]` is - available. +implicit val c2 = Monoid[Int](0) // Requires a Semigroup[Int] instance. \end_layout \end_inset @@ -36566,7 +36568,7 @@ status open \begin_layout Plain Layout -def productTC[A, B](u: P[A] => A, v: P[B] => B): P[(A, B)] => (A, B) = +def productTC[A, B](u: P[A] => A, v: P[B] => B): P[(A, B)] => (A, B) = { \end_layout \begin_layout Plain Layout @@ -36574,6 +36576,11 @@ def productTC[A, B](u: P[A] => A, v: P[B] => B): P[(A, B)] => (A, B) = p => ( u(p.map(_._1)), v(p.map(_._2)) ) \end_layout +\begin_layout Plain Layout + +} +\end_layout + \end_inset @@ -36915,11 +36922,10 @@ In this way, the recursive-type construction works for any \begin_layout Standard Similar arguments can be made for type constructor typeclasses, although - it is more difficult to reason about type constructors with several extra - type parameters. - The product-type, the function-type, and the recursive-type constructions - work for functors, contrafunctors, pointed functors, and pointed contrafunctors -, as well as for other important + their properties are more difficult to prove. + This book shows that the product-type, the function-type, and the recursive-typ +e constructions work for functors, contrafunctors, pointed functors, and + pointed contrafunctors, as well as for other important \begin_inset Formula $P$ \end_inset @@ -37051,7 +37057,7 @@ Copointed \end_inset even if we add more type parameters. - However, the methods of these typeclasses can be written as + However, the instance values of these typeclasses can be written as \begin_inset Formula $A\rightarrow P^{A}$ \end_inset @@ -37061,7 +37067,8 @@ Copointed . Based on that description, some general results can be proved also for - those typeclasses; for instance, the + those typeclasses. + For example, the \emph on co-product \emph default diff --git a/sofp-src/sofp-typeclasses.tex b/sofp-src/sofp-typeclasses.tex index d702ca05b..6ab996a3e 100644 --- a/sofp-src/sofp-typeclasses.tex +++ b/sofp-src/sofp-typeclasses.tex @@ -1630,7 +1630,7 @@ \subsection{Extractors} terminates. Why does it? A recursive definition of the form $x\triangleq f(x)$ could create an infinite loop, as in this code: \begin{lstlisting} -def f(x: Int): Int = x + 1 +def f(i: Int): Int = i + 1 def x: Int = f(x) scala> x // Infinite loop: f(f(f(f(...))) @@ -2014,9 +2014,11 @@ \subsection{Equality comparison: The \texttt{Eq} typeclass\label{subsec:The-Eq-t polynomial or recursive polynomial type expressions containing primitive types or type parameters constrained to be \lstinline!Eq!-comparable. The derivation of the \lstinline!Eq! instance is unambiguous and -can be automated with libraries such as the \texttt{kittens},\footnote{\texttt{\href{https://github.com/typelevel/kittens}{https://github.com/typelevel/kittens}}} +can be in many cases performed automatically with libraries such as +\texttt{kittens},\footnote{\texttt{\href{https://github.com/typelevel/kittens}{https://github.com/typelevel/kittens}}} \texttt{magnolia},\footnote{\texttt{\href{https://github.com/propensive/magnolia}{https://github.com/propensive/magnolia}}} -or \texttt{scalaz-deriving}.\footnote{\texttt{\href{https://github.com/scalaz/scalaz-deriving}{https://github.com/scalaz/scalaz-deriving}}} +\texttt{scalaz-deriving},\footnote{\texttt{\href{https://github.com/scalaz/scalaz-deriving}{https://github.com/scalaz/scalaz-deriving}}} +and \texttt{zio-deriving}.\footnote{\texttt{\href{https://github.com/zio/zio-deriving}{https://github.com/zio/zio-deriving}}} \begin{table} \begin{centering} @@ -2264,7 +2266,8 @@ \subsection{Semigroups\label{subsec:Semigroups-constructions}} operation of the semigroup $A$, which is associative since we assume that $A$ is a lawful semigroup: \begin{lstlisting} -Left(x) |+| Left(y) |+| Left(z) == Left(x |+| y |+| z) == Left(x) |+| ( Left(y) |+| Left(z) ) +Left(x) |+| Left(y) |+| Left(z) == Left(x |+| y |+| z) + == Left(x) |+| ( Left(y) |+| Left(z) ) \end{lstlisting} The same argument applies to three values of type \lstinline!Right!. @@ -2788,27 +2791,20 @@ \subsection{Pointed functors: motivation and laws\label{subsec:Pointed-functors- Do these two methods need to be compatible in some way? If we \textsf{``}wrap\textsf{''} a value $123$ in a \lstinline!List! and then apply \lstinline!.map(x => x + 1)!, we expect to obtain a list containing $124$; any other result would -break our intuition about \textsf{``}wrapping\textsf{''}. We can generalize this situation -to an arbitrary value $x^{:A}$ wrapped using \lstinline!pure! and -a function $f^{:A\rightarrow B}$ applied to the wrapped value via -\lstinline!map!: +contradict our intuition about \textsf{``}wrapping\textsf{''}. We can generalize this +idea to an arbitrary value $x^{:A}$ wrapped using \lstinline!pure! +and a function $f^{:A\rightarrow B}$ applied to the wrapped value +via \lstinline!map!: \begin{lstlisting}[mathescape=true] pure(x).map(f) // $\color{dkgreen}\text{pu}_{F}(x)\triangleright\, \scriptstyle{f^{\uparrow F}}$ \end{lstlisting} We expect that the result should be the same as a wrapped $f(x)$. This expectation can be formulated as a law, called the \textbf{naturality -law}\index{naturality law!of pure@of \texttt{pure}} of \lstinline!pure!; -it must hold for any $f^{:A\rightarrow B}$: - -\begin{wrapfigure}{l}{0.4\columnwidth}% -\vspace{-0.8\baselineskip} +law}\index{naturality law!of pure@of \texttt{pure}} of \lstinline!pure!. +For any $f^{:A\rightarrow B}$: \begin{lstlisting} pure(x).map(f) == pure(f(x)) \end{lstlisting} -\vspace{-0.5\baselineskip} -\end{wrapfigure}% - -\noindent \vspace{-0.5\baselineskip} \[ \text{pu}_{F}(x)\triangleright f^{\uparrow F}=\text{pu}_{F}(f(x))\quad. \] @@ -2824,11 +2820,10 @@ \subsection{Pointed functors: motivation and laws\label{subsec:Pointed-functors- B\ar[r]\sp(0.5){\text{pu}_{F}} & F^{B} } \] -This motivates the following definition: A functor $F^{\bullet}$ -is \index{pointed functor|textit}\textbf{pointed} if there exists -a function $\text{pu}_{F}:\forall A.\,A\rightarrow F^{A}$ satisfying -the naturality law~(\ref{eq:naturality-law-of-pure}) for any function -$f^{:A\rightarrow B}$. +This motivates the following definition: A functor $F$ is \index{pointed functor|textit}\textbf{pointed} +if there exists a function $\text{pu}_{F}:\forall A.\,A\rightarrow F^{A}$ +satisfying the naturality law~(\ref{eq:naturality-law-of-pure}) +for any function $f^{:A\rightarrow B}$. It turns out that we can avoid checking the naturality law of pointed functors if we use a trick: reduce \lstinline!pure! to a simpler @@ -2874,12 +2869,11 @@ \subsection{Pointed functors: motivation and laws\label{subsec:Pointed-functors- \begin{lstlisting} def pure[A](x: A): F[A] = wu.map { _ => x } \end{lstlisting} -In code notation: \begin{equation} \text{pu}_{F}^{:A\rightarrow F^{A}}\triangleq x^{:A}\rightarrow\text{wu}_{F}\triangleright(\_\rightarrow x)^{\uparrow F}\quad.\label{eq:pu-via-wu-def} \end{equation} -Does this function satisfy the naturality law with respect to an arbitrary -$f^{:A\rightarrow B}$? It does: +The function $\text{pu}_{F}$ obeys the naturality law with respect +to an arbitrary $f^{:A\rightarrow B}$: \begin{align*} {\color{greenunder}\text{expect to equal }x\triangleright f\bef\text{pu}_{F}:}\quad & x\triangleright\text{pu}_{F}\bef f^{\uparrow F}\\ {\color{greenunder}\text{definition of }\text{pu}_{F}:}\quad & =\text{wu}_{F}\triangleright(\_\rightarrow x)^{\uparrow F}\bef f^{\uparrow F}\\ @@ -3490,12 +3484,11 @@ \subsection{Co-pointed functors\label{subsec:Co-pointed-functors}} \end{array}\,\bef\,\begin{array}{||c|} \text{ex}_{F}\\ \text{ex}_{G} -\end{array}\\ -{\color{greenunder}\text{matrix function composition}:}\quad & =\,\,\begin{array}{||c|} +\end{array}\,=\,\begin{array}{||c|} \gunderline{f^{\uparrow F}\bef\text{ex}_{F}}\\ \gunderline{f^{\uparrow G}\bef\text{ex}_{G}} \end{array}\\ -{\color{greenunder}\text{naturality laws of }\text{ex}_{F}\text{ and }\text{ex}_{G}:}\quad & =\,\begin{array}{||c|} +{\color{greenunder}\text{naturality laws of }\text{ex}_{F}\text{ and }\text{ex}_{G}:}\quad & =\,\,\begin{array}{||c|} \text{ex}_{F}\,\gunderline{\bef f}\\ \text{ex}_{G}\,\gunderline{\bef f} \end{array}\,=\,\gunderline{\begin{array}{||c|} @@ -3699,9 +3692,11 @@ \subsection{Pointed contrafunctors\label{subsec:Pointed-contrafunctors}} type $\forall A.\,C^{A}$; we called such contrafunctors \textbf{pointed}. We also needed to assume that the naturality law holds for all functions $f^{:A\rightarrow B}$: -\begin{equation} -\text{cpu}_{C}\triangleright f^{\downarrow C}=\text{cpu}_{C}\quad,\quad\text{or equivalently}:\quad\text{cmap}_{C}(f^{:A\rightarrow B})(\text{cpu}_{C}^{:C^{B}})=\text{cpu}_{C}^{:C^{A}}\quad.\label{eq:naturality-law-for-pure-for-contrafunctors} -\end{equation} +\begin{align} + & \text{cpu}_{C}\triangleright f^{\downarrow C}=\text{cpu}_{C}\quad,\label{eq:naturality-law-for-pure-for-contrafunctors}\\ +{\color{greenunder}\text{or equivalently}:}\quad & \text{cmap}_{C}(f^{:A\rightarrow B})(\text{cpu}_{C}^{:C^{B}})=\text{cpu}_{C}^{:C^{A}}\quad.\nonumber +\end{align} +This is illustrated by the type diagram: \[ \xymatrix{\xyScaleY{2.0pc}\xyScaleX{3.0pc}\bbnum 1\ar[rd]\sb(0.5){}\ar[r]\sb(0.5){} & \text{cpu}_{C}:C^{B}\ar[d]\sp(0.45){\text{cmap}_{C}(f)}\\ & \text{cpu}_{C}:C^{A} @@ -4397,7 +4392,8 @@ \subsubsection{Example \label{subsec:tc-Example-10}\ref{subsec:tc-Example-10}} \] \begin{lstlisting} def f[F[_]: Functor, A, B](p: F[(A, B)]): (F[A], F[B]) = - (p.map { case (a, b) => a }, p.map { case (a, b) => b }) // Or (p.map(_._1), p.map(_._2)) + (p.map { case (a, b) => a }, p.map { case (a, b) => b }) +// Shorter code: (p.map(_._1), p.map(_._2)) \end{lstlisting} A shorter code for $f$ via the \textsf{``}diagonal\textsf{''} function $\Delta\triangleq(q^{:Q}\rightarrow q\times q)$ and the pair product $\boxtimes$ is: @@ -4411,14 +4407,13 @@ \subsubsection{Example \label{subsec:tc-Example-10}\ref{subsec:tc-Example-10}} \begin{equation} g:\forall(A,B).\,F^{A}\times F^{B}\rightarrow F^{A\times B}\quad,\label{eq:type-signature-of-g-zip} \end{equation} -we will find that $g$ \emph{can} be implemented for functors such -as $F^{A}\triangleq A\times A$, $F^{A}\triangleq\bbnum 1+A$, and -$F^{A}\triangleq P\rightarrow A$. It is not obvious how to find a -functor $F$ for which the function $g$ has no implementation. By -looking through the known functor constructions (Table~\ref{tab:f-Functor-constructions}) -and trying various combinations, we eventually find a suitable functor: -$F^{A}\triangleq(P\rightarrow A)+(Q\rightarrow A)$. The type signature -of $g$ becomes: +we will find that $g$ \emph{can} be implemented for functors $F^{A}\triangleq A\times A$, +$F^{A}\triangleq\bbnum 1+A$, and $F^{A}\triangleq P\rightarrow A$. +It is not obvious how to find a functor $F$ for which the function +$g$ has no implementation. By looking through the known functor constructions +(Table~\ref{tab:f-Functor-constructions}) and trying various combinations, +we eventually find a suitable functor: $F^{A}\triangleq(P\rightarrow A)+(Q\rightarrow A)$. +The type signature of $g$ becomes: \[ \left((P\rightarrow A)+(Q\rightarrow A)\right)\times\left((P\rightarrow B)+(Q\rightarrow B)\right)\rightarrow(P\rightarrow A\times B)+(Q\rightarrow A\times B)\quad. \] @@ -5524,7 +5519,7 @@ \subsection{Inheritance and automatic conversions of typeclasses\label{subsec:In having an instance of \lstinline!Semigroup! for \lstinline!T!: \begin{lstlisting} implicit val c1 = Semigroup[Int](_ + _) -implicit val c2 = Monoid[Int](0) // Works only if a `Semigroup[Int]` is available. +implicit val c2 = Monoid[Int](0) // Requires a Semigroup[Int] instance. \end{lstlisting} Given a \lstinline!Monoid[T]! instance, how can we recover the inherited @@ -5704,8 +5699,9 @@ \subsection{$P$-typeclasses, their laws and structure\label{subsec:P-typeclasses type $A\times B$ can be derived automatically using the function \lstinline!productTC!: \begin{lstlisting} -def productTC[A, B](u: P[A] => A, v: P[B] => B): P[(A, B)] => (A, B) = +def productTC[A, B](u: P[A] => A, v: P[B] => B): P[(A, B)] => (A, B) = { p => ( u(p.map(_._1)), v(p.map(_._2)) ) +} \end{lstlisting} \begin{align*} \text{productTC} & :(P^{A}\rightarrow A)\times(P^{B}\rightarrow B)\rightarrow P^{A\times B}\rightarrow A\times B\quad,\\ @@ -5776,13 +5772,12 @@ \subsection{$P$-typeclasses, their laws and structure\label{subsec:P-typeclasses instances.) Similar arguments can be made for type constructor typeclasses, although -it is more difficult to reason about type constructors with several -extra type parameters. The product-type, the function-type, and the -recursive-type constructions work for functors, contrafunctors, pointed -functors, and pointed contrafunctors, as well as for other important -$P$-typeclasses such as filterable functors (Chapter~\ref{chap:Filterable-functors}), -monads (Chapter~\ref{chap:Semimonads-and-monads}), and applicative -functors (Chapter~\ref{chap:8-Applicative-functors,-contrafunctors}). +their properties are more difficult to prove. This book shows that +the product-type, the function-type, and the recursive-type constructions +work for functors, contrafunctors, pointed functors, and pointed contrafunctors, +as well as for other important $P$-typeclasses such as filterable +functors (Chapter~\ref{chap:Filterable-functors}), monads (Chapter~\ref{chap:Semimonads-and-monads}), +and applicative functors (Chapter~\ref{chap:8-Applicative-functors,-contrafunctors}). We will see in Chapter~\ref{chap:Free-type-constructions} that another general construction also works for all $P$-typeclasses, \textemdash{} the \textsf{``}free\textsf{''} type construction. @@ -5792,13 +5787,14 @@ \subsection{$P$-typeclasses, their laws and structure\label{subsec:P-typeclasses which is not of the form $P^{A}\rightarrow A$ for any functor $P$. Another such typeclass is \lstinline!Copointed!, whose method $F^{A}\rightarrow A$ is not of the form $P^{F}\rightarrow F$ even if we add more type -parameters. However, the methods of these typeclasses can be written -as $A\rightarrow P^{A}$ with some functor $P$. Based on that description, -some general results can be proved also for those typeclasses; for -instance, the \emph{co-product} construction (rather than the product -construction) works for them. Given values of types $A\rightarrow P^{A}$ -and $B\rightarrow P^{B}$, we can produce a value of type $A+B\rightarrow P^{A+B}$, -i.e., a co-product instance, but not necessarily a value of type $A\times B\rightarrow P^{A\times B}$, +parameters. However, the instance values of these typeclasses can +be written as $A\rightarrow P^{A}$ with some functor $P$. Based +on that description, some general results can be proved also for those +typeclasses. For example, the \emph{co-product} construction (rather +than the product construction) works for them. Given values of types +$A\rightarrow P^{A}$ and $B\rightarrow P^{B}$, we can produce a +value of type $A+B\rightarrow P^{A+B}$, i.e., a co-product instance, +but not necessarily a value of type $A\times B\rightarrow P^{A\times B}$, which would be a product-type instance. An example of a typeclass to which neither description applies is diff --git a/sofp-src/sofp.lyx b/sofp-src/sofp.lyx index 0e489d51d..bac76b20f 100644 --- a/sofp-src/sofp.lyx +++ b/sofp-src/sofp.lyx @@ -193,7 +193,7 @@ \renewcommand{\ogreaterthan}{\boxrightarrow} \renewcommand{\varogreaterthan}{\boxrightarrow} \end_preamble -\options open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt +\options numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt \use_default_options true \maintain_unincluded_children false \language english @@ -340,7 +340,7 @@ by Sergei Winitzki, Ph.D. \end_layout \begin_layout Date -Draft version of +Version of \begin_inset ERT status open @@ -452,7 +452,7 @@ Git commit: INSERTGITCOMMIT \begin_inset Newline newline \end_inset -PDF file built by PDFTEXVERSION on BUILDDATE by BUILDOPERATINGSYSTEM +PDF file built on BUILDDATE by PDFTEXVERSION on BUILDOPERATINGSYSTEM \size default \begin_inset Newline newline @@ -485,6 +485,20 @@ plural "false" caps "false" noprefix "false" +\end_inset + + on page +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand pageref +reference "sec:GFDL" +plural "false" +caps "false" +noprefix "false" + \end_inset ). @@ -561,7 +575,7 @@ sofp-src.tar.bz2 . See the file \family typewriter -README.md +README_build.md \family default for build instructions. \end_layout @@ -570,11 +584,8 @@ README.md \size scriptsize This book is a pedagogical in-depth tutorial and reference on the theory - of functional programming (FP) as practiced in the early 21 -\begin_inset Formula $^{\text{st}}$ -\end_inset - - century. + of functional programming (FP) as it was practiced at the beginning of + the XXI 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. diff --git a/sofp-src/sofp.tex b/sofp-src/sofp.tex index dddec265c..f3bbe79f3 100644 --- a/sofp-src/sofp.tex +++ b/sofp-src/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[10pt,russian,english,open=any,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt]{scrbook} +\documentclass[10pt,russian,english,numbers=noenddot,index=totoc,bibliography=totoc,listof=totoc,fontsize=12pt]{scrbook} \usepackage{amsmath} \usepackage{mathpazo} \usepackage{helvet} @@ -320,16 +320,16 @@ {\footnotesize{}ISBN (e-book): 978-0-359-76877-6}\\ {\footnotesize{}ISBN: 978-0-359-76877-6}\\ \\ -{\scriptsize{}Source hash (sha256): ec0738b0430889d9068e4daba10d170c93f96968d29a567165fcd1a63e50fc9e}\\ -{\scriptsize{}Git commit: 09779879d173b6f32e4c7a624cd029b73c213a9b}\\ -{\scriptsize{}PDF file built by pdfTeX 3.141592653-2.6-1.40.25 (TeX Live 2023) on Sat, 17 Feb 2024 09:54:10 +0100 by Darwin 22.6.0}\\ +{\scriptsize{}Source hash (sha256): f92108878a7587a7534416b56b5a228e4d5210d45462ca18880cfd7ace1b4c3f}\\ +{\scriptsize{}Git commit: a39f1213457c397d0ab5f236aa0415d68ecf53ac}\\ +{\scriptsize{}PDF file built on Sun, 10 Mar 2024 10:41:19 +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}).}\\ +\textsf{``}GNU Free Documentation License\textsf{''} (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{} @@ -339,11 +339,11 @@ attachment\textsf{''} 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.md}{\scriptsize{} +jxvf sofp-src.tar.bz2`}{\scriptsize{}. See the file }\texttt{\scriptsize{}README\_build.md}{\scriptsize{} for build instructions.}} \lowertitleback{{\scriptsize{}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 +on the theory of functional programming (FP) as it was practiced at +the beginning of the XXI 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 @@ -357,10 +357,10 @@ parametricity theorems.}\\ {\scriptsize{}}\\ {\scriptsize{}Long and difficult, yet boring explanations are logically -developed in excruciating detail through 1879 Scala -code snippets, 189 statements with step-by-step derivations, +developed in excruciating detail through 1880 Scala +code snippets, 191 statements with step-by-step derivations, 103 diagrams, 216 examples with tested Scala -code, and 295 exercises. Discussions build upon each +code, and 297 exercises. Discussions build upon each chapter\textsf{'}s material further.}\\ {\scriptsize{}}\\ {\scriptsize{}Beginners in FP will find tutorials about the map/reduce