diff --git a/sofp-src/lyx/sofp-appendices.lyx b/sofp-src/lyx/sofp-appendices.lyx index bbb58b6c5..ed9e8d897 100644 --- a/sofp-src/lyx/sofp-appendices.lyx +++ b/sofp-src/lyx/sofp-appendices.lyx @@ -5725,7 +5725,7 @@ noprefix "false" \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" @@ -5878,19 +5878,13 @@ Other laws that follow automatically from parametricity are composition \end_layout \begin_layout Standard -\begin_inset Wrap table -lines 0 -placement l -overhang 0in -width "54.5col%" +\begin_inset Float table +wide false +sideways false status open \begin_layout Plain Layout \align center -\begin_inset VSpace -20baselineskip% -\end_inset - - \begin_inset Tabular @@ -5984,7 +5978,7 @@ None \end_inset - + \end_layout \end_inset @@ -6045,7 +6039,7 @@ F[A] \end_inset - + \end_layout \end_inset @@ -41086,8 +41080,8 @@ status open \begin_layout Plain Layout - else if (p(x)) Some(x) else converge(p)(f(x))(m-1)(f) - } + else if (p(x)) Some(x) else converge(p)(f(x))(m - 1)(f) + } \end_layout \begin_layout Plain Layout diff --git a/sofp-src/lyx/sofp-curry-howard.lyx b/sofp-src/lyx/sofp-curry-howard.lyx index 7931c488e..780755c33 100644 --- a/sofp-src/lyx/sofp-curry-howard.lyx +++ b/sofp-src/lyx/sofp-curry-howard.lyx @@ -106,7 +106,7 @@ % extendedchars=true, % %numbers=none, % numberstyle=\tiny\color{gray}, -% keywordstyle=\color{blue}, +% keywordstyle=\color{red}, % commentstyle=\color{dkgreen}, % stringstyle=\color{mauve}, % frame=single, @@ -828,14 +828,15 @@ case ... \end_inset ) of a pattern-matching expression. - In other words, we should be able to implement the following type signature: + For that, one would need to implement the following type signature via + fully parametric code: \begin_inset listings inline false status open \begin_layout Plain Layout -def bad[A, B](f: A => B)(pa: Option[A]): A = ??? +def bad[A, B](f: A => B)(pa: Option[A]): A = ??? // Cannot implement. \end_layout \end_inset @@ -1379,9 +1380,123 @@ f: A => C \end_layout \begin_layout Standard -In all these examples, we see that the impossibility of implementing a type - signature means that the information given in a function's arguments is - in some way insufficient for computing the result value. +Could we try to switch between functions of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A => B +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A => C +\end_layout + +\end_inset + + depending on a given value of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A +\end_layout + +\end_inset + +? This idea means that we are working with a different type signature, which + has an additional argument of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A +\end_layout + +\end_inset + +. + That type signature +\emph on +can +\emph default + be implemented, for instance, by this Scala code: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def q[A, B, C](g: A => Either[B, C])(a: A): Either[A => B, A => C] = +\end_layout + +\begin_layout Plain Layout + + g(a) match { +\end_layout + +\begin_layout Plain Layout + + case Left(b) => Left(_ => b) +\end_layout + +\begin_layout Plain Layout + + case Right(c) => Right(_ => c) +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\end_inset + +But +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +q +\end_layout + +\end_inset + + does not have the required type signature of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +bad3 +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Standard +In all these examples, we see that the a type signature cannot be implemented + because the information given in a function's arguments is in some way + insufficient for computing the result value. \end_layout \begin_layout Standard @@ -1413,7 +1528,7 @@ This type signature \emph on can \emph default - be implemented, but only in one way: + be implemented: \begin_inset listings inline false status open @@ -1505,7 +1620,7 @@ bad3 \end_inset - cannot be implemented by any fully parametric code? Or, perhaps, we were + cannot be implemented by any fully parametric code? Or, perhaps, we are mistaken and a clever trick \emph on could @@ -1611,8 +1726,8 @@ ave a value of type So, we are interested in proving statements like this: \begin_inset Formula \begin{align} - & \text{a fully parametric expression can compute a value of type }A\nonumber \\ - & \text{using previously given values of types }X,Y,...,Z\quad.\label{eq:ch-CH-proposition-def} + & \text{a fully parametric function can compute a value of type }A\nonumber \\ + & \text{using given arguments of types }X,Y,...,Z\quad.\label{eq:ch-CH-proposition-def} \end{align} \end_inset @@ -1646,7 +1761,7 @@ Here \end_layout \begin_layout Standard -If values of types +If arguments of types \begin_inset Formula $X$ \end_inset @@ -1678,7 +1793,7 @@ already have \begin_inset Formula ${\cal CH}(Z)$ \end_inset - will be already true. + will be true. So, proposition \begin_inset space ~ \end_inset @@ -1832,8 +1947,8 @@ sequent (in logic)!goal \end_layout \begin_layout Standard -Sequents provide a notation for the questions about types of fully parametric - functions. +Sequents provide a notation for questions about implementability of fully + parametric functions. Since our goal is to answer such questions rigorously, we will need to be able to \emph on @@ -1899,35 +2014,36 @@ proof (in logic) logics \emph default . - We will need to discover the correct logic for reasoning about sequents - with + We need to discover the correct logic for reasoning about sequents with + \begin_inset Formula ${\cal CH}$ \end_inset -propositions. - To discover that logic's complete set of axioms and derivation rules, we - need to examine systematically what types and code constructions are possible + To find that logic's complete set of axioms and derivation rules, we will + systematically examine all the types and code constructions that are possible in a fully parametric function. The resulting logic is known under the name \begin_inset Quotes eld \end_inset -constructive logic +constructive propositional logic \begin_inset Quotes erd \end_inset . That logic's axioms and derivation rules directly correspond to programming language constructions allowed by fully parametric code. - For that reason, constructive logic gives correct answers about implementable - and non-implementable type signatures of fully parametric functions. + For that reason, constructive propositional logic gives correct answers + about implementable and non-implementable type signatures of fully parametric + functions. \end_layout \begin_layout Standard -We will then be able to borrow the results and methods already available - in the mathematical literature on formal logic. +We will then be able to borrow the results and methods available in the + mathematical literature. The main result is an algorithm (called LJT) for finding a proof for a - given sequent in the constructive logic. + given sequent in the constructive propositional logic. If a proof is found, the algorithm also provides the code of a function that has the type signature corresponding to the sequent. If a proof is not found, it means that the given type signature cannot @@ -1935,11 +2051,7 @@ We will then be able to borrow the results and methods already available \end_layout \begin_layout Subsection -Type notation and -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for standard type constructions +Type notation for standard type constructions \begin_inset CommandInset label LatexCommand label name "subsec:Type-notation-and-standard-type-constructions" @@ -1950,8 +2062,7 @@ name "subsec:Type-notation-and-standard-type-constructions" \end_layout \begin_layout Standard -Here and in the following sections, we will be reasoning about sequents - of the form: +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) @@ -1960,8 +2071,7 @@ Here and in the following sections, we will be reasoning about sequents \end_inset that represent type signatures of fully parametric functions. - It will be convenient to shorten the notation and to denote the set of - all premises by the symbol + It will be convenient to denote the set of all premises by the symbol \begin_inset Formula $\Gamma$ \end_inset @@ -1975,69 +2085,10 @@ that represent type signatures of fully parametric functions. \end_inset . - \end_layout \begin_layout Standard -In Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Disjunctions-and-conjunctions" -plural "false" -caps "false" -noprefix "false" - -\end_inset - - we saw examples of reasoning about -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for case classes and for disjunctive types. - We will now extend this reasoning systematically to all type constructions - that fully parametric programs could use. - The result will be that we rewrite -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions with arbitrary type expressions, such as -\begin_inset Formula ${\cal CH}($ -\end_inset - - -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Either[(A, A), Option[B] => Either[(A, B), C]] -\end_layout - -\end_inset - - -\begin_inset Formula $)$ -\end_inset - -, in terms of -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for simple type parameters: -\begin_inset Formula ${\cal CH}(A)$ -\end_inset - -, -\begin_inset Formula ${\cal CH}(B)$ -\end_inset - -, etc. - A special type notation +A special type notation \begin_inset Index idx status open @@ -2076,7 +2127,7 @@ noprefix "false" \end_inset - for a summary of the type notation.) + for a full summary of the type notation.) \end_layout \begin_layout Standard @@ -2151,92 +2202,81 @@ co-product types co-product types \series default ), function types, parameterized types, and recursive types. - We will now derive the rules for writing -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for each of these type constructions except recursive types. + \end_layout -\begin_layout Paragraph -1a) Rule for the -\family typewriter -Unit -\family default - type +\begin_layout Standard +We now define a shorter notation for those types. + This notation is often found in the literature on functional programming + languages, except we are using +\emph on +superscripts +\emph default + to denote type parameters. \end_layout \begin_layout Standard -The -\begin_inset listings -inline true -status open +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text \begin_layout Plain Layout -Unit +\series bold +\size small +Description \end_layout \end_inset - - type has only a single value -\begin_inset listings -inline true -status open + + +\begin_inset Text \begin_layout Plain Layout -() +\series bold +\size small +Scala syntax \end_layout \end_inset - -, an -\begin_inset Quotes eld -\end_inset - -empty tuple -\begin_inset Quotes erd -\end_inset - -. - This value can be -\emph on -always -\emph default - computed since it does not need any previous data: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def f[...]: ... - = { -\end_layout + + +\begin_inset Text \begin_layout Plain Layout - ... +\series bold +\size small +Type notation \end_layout -\begin_layout Plain Layout - - val x: Unit = () // We can always compute a `Unit` value. -\end_layout +\end_inset + + + + +\begin_inset Text \begin_layout Plain Layout - ... +\size small +Unit type \end_layout \end_inset + + +\begin_inset Text -So, the proposition -\begin_inset Formula ${\cal CH}($ -\end_inset - - +\begin_layout Plain Layout \begin_inset listings inline true status open @@ -2249,388 +2289,336 @@ Unit \end_inset -\begin_inset Formula $)$ -\end_inset - - is always true. - In the type notation, the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Unit \end_layout \end_inset + + +\begin_inset Text - type is denoted by +\begin_layout Plain Layout \begin_inset Formula $\bbnum 1$ \end_inset -. - We may write the rule as -\begin_inset Formula $\mathcal{CH}(\bbnum 1)=True$ -\end_inset - -. - -\end_layout - -\begin_layout Standard -Named unit types -\begin_inset Index idx -status open -\begin_layout Plain Layout -unit type!named \end_layout \end_inset - - also have a single value that is always possible to compute. - For example: -\begin_inset listings -inline false -status open + + + + +\begin_inset Text \begin_layout Plain Layout -final case class N1() +\size small +Void type \end_layout \end_inset + + +\begin_inset Text -defines a named unit type. - We can compute a value of type +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -N1 +Nothing \end_layout \end_inset - without using any other given values: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout -val x: N1 = N1() \end_layout \end_inset + + +\begin_inset Text -So, the proposition -\begin_inset Formula ${\cal CH}($ +\begin_layout Plain Layout +\begin_inset Formula $\bbnum 0$ \end_inset -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -N1 \end_layout \end_inset + + + + +\begin_inset Text +\begin_layout Plain Layout -\begin_inset Formula $)$ -\end_inset +\size small +Built-in types +\end_layout - is always true. - In the type notation, named unit types are also denoted by -\begin_inset Formula $\bbnum 1$ \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout -, just as the +\size small \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +Int \end_layout \end_inset - type itself. -\end_layout - -\begin_layout Paragraph -1b) Rule for the void type -\end_layout - -\begin_layout Standard -The Scala type +, \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing +String \end_layout \end_inset - has no values, so the proposition -\begin_inset Formula ${\cal CH}($ +, ... +\end_layout + \end_inset + + +\begin_inset Text +\begin_layout Plain Layout -\begin_inset listings -inline true -status open +\size small +\begin_inset Formula $\text{Int}$ +\end_inset -\begin_layout Plain Layout +, +\begin_inset Formula $\text{String}$ +\end_inset -Nothing +, ... \end_layout \end_inset + + + + +\begin_inset Text +\begin_layout Plain Layout + +\size small +Tuple type +\end_layout -\begin_inset Formula $)$ \end_inset + + +\begin_inset Text - is always false. - The type +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing +(A, B) \end_layout \end_inset - is denoted by -\begin_inset Formula $\bbnum 0$ + +\end_layout + \end_inset + + +\begin_inset Text - in the type notation. - So, the rule is -\begin_inset Formula $\mathcal{CH}(\bbnum 0)=False$ +\begin_layout Plain Layout +\begin_inset Formula $A\times B$ \end_inset -. -\end_layout -\begin_layout Paragraph -1c) Rule for primitive types \end_layout -\begin_layout Standard -For a specific primitive (or library-defined) type such as -\begin_inset listings -inline true -status open +\end_inset + + + + +\begin_inset Text \begin_layout Plain Layout -Int +\size small +Disjunctive type \end_layout \end_inset + + +\begin_inset Text - or +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -String +Either[A, B] \end_layout \end_inset -, the corresponding -\begin_inset Formula ${\cal CH}$ -\end_inset - --proposition is -\emph on -always true -\emph default - because we may use a constant value, e.g.: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout -def f[...]: ... - { \end_layout -\begin_layout Plain Layout - - ... -\end_layout +\end_inset + + +\begin_inset Text \begin_layout Plain Layout - - val x: String = -\begin_inset Quotes eld +\begin_inset Formula $A+B$ \end_inset -abc -\begin_inset Quotes erd -\end_inset - // We can always compute a `String` value. \end_layout -\begin_layout Plain Layout - - ... -\end_layout +\end_inset + + + + +\begin_inset Text \begin_layout Plain Layout -} +\size small +Function type \end_layout \end_inset + + +\begin_inset Text -So, the rule for primitive types is the same as that for the +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +A => B \end_layout \end_inset - type. - For example, -\begin_inset Formula $\mathcal{CH}(\text{String})=True$ -\end_inset -. \end_layout -\begin_layout Paragraph -2) Rule for tuple types -\end_layout - -\begin_layout Standard -To compute a value of a tuple type -\begin_inset listings -inline true -status open +\end_inset + + +\begin_inset Text \begin_layout Plain Layout +\begin_inset Formula $A\rightarrow B$ +\end_inset + -(A, B) \end_layout \end_inset - - requires computing a value of type -\begin_inset listings -inline true -status open + + + + +\begin_inset Text \begin_layout Plain Layout -A +\size small +Parameterized types \end_layout \end_inset + + +\begin_inset Text - -\emph on -and -\emph default - a value of type +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -B +def f[A]: F[A] \end_layout \end_inset -. - This is expressed by the logical formula -\begin_inset Formula ${\cal CH}($ -\end_inset +\end_layout -\begin_inset listings -inline true -status open +\end_inset + + +\begin_inset Text \begin_layout Plain Layout - -(A, B) -\end_layout - +\begin_inset Formula $f^{A}:F^{A}$ \end_inset -\begin_inset Formula $)={\cal CH}(A)\wedge{\cal CH}(B)$ +\size small + or +\begin_inset Formula $f:\forall A.\,F^{A}$ \end_inset -. - A similar formula holds for case classes, as Eq. -\begin_inset space ~ -\end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:curry-howard-example-case-class" -plural "false" -caps "false" -noprefix "false" +\end_layout \end_inset + + + -) shows. - In the type notation, the tuple -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout +\end_inset -(A, B) + \end_layout +\begin_layout Standard +Tuples and case classes with more than two parts are denoted by +\begin_inset Formula $A\times B\times C$ \end_inset - is written as -\begin_inset Formula $A\times B$ -\end_inset - -. - Tuples and case classes with more than two parts are denoted by -\begin_inset Formula $A\times B\times...\times C$ + or +\begin_inset Formula $A\times B\times C\times D$ \end_inset -. +, etc. For example, the Scala definition: \begin_inset listings inline false @@ -2648,75 +2636,11 @@ is written in the type notation as \end_inset . - So, the rule for tuples is: -\begin_inset Formula -\[ -{\cal CH}\left(A\times B\times...\times C\right)={\cal CH}(A)\wedge{\cal CH}(B)\wedge...\wedge{\cal CH}(C)\quad. -\] - -\end_inset - - -\end_layout - -\begin_layout Paragraph -3) Rule for disjunctive types + \end_layout \begin_layout Standard -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. -\begin_inset space ~ -\end_inset - -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:curry-howard-example-disjunction" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -). - For the standard disjunctive type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Either[A, B] -\end_layout - -\end_inset - -, we have the logical formula -\begin_inset Formula ${\cal CH}($ -\end_inset - - -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Either[A, B] -\end_layout - -\end_inset - - -\begin_inset Formula $)={\cal CH}(A)\vee{\cal CH}(B)$ -\end_inset - -. - In the type notation, the Scala type +The Scala type \begin_inset listings inline true status open @@ -2732,7 +2656,11 @@ Either[A, B] \begin_inset Formula $A+B$ \end_inset -. +, and disjunctive types with more parts are written as +\begin_inset Formula $A+B+C$ +\end_inset + + and so on. As another example, the Scala definition: \begin_inset listings inline false @@ -2769,138 +2697,11 @@ is translated to the type notation as: \end_inset 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 -\[ -{\cal CH}\left(A+B+...+C\right)={\cal CH}(A)\vee{\cal CH}(B)\vee...\vee{\cal CH}(C)\quad. -\] - -\end_inset - - -\end_layout - -\begin_layout Paragraph -4) Rule for function types -\end_layout - -\begin_layout Standard -Consider now a function type such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A => B -\end_layout - -\end_inset - -. - This type is written in the type notation as -\begin_inset Formula $A\rightarrow B$ -\end_inset - -. - To compute a value of that type, we need to write code like this: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -val f: A => B = { (a: A) => -\end_layout - -\begin_layout Plain Layout - - ??? // Compute a value of type B in this scope. -\end_layout - -\begin_layout Plain Layout - -} -\end_layout - -\end_inset - -The inner scope of this function needs to compute a value of type -\begin_inset Formula $B$ -\end_inset - -, and the given value -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -a: A -\end_layout - -\end_inset - - may be used for that. - So, -\begin_inset Formula ${\cal CH}(A\rightarrow B)$ -\end_inset - - is true if and only if we are able to compute a value of type -\begin_inset Formula $B$ -\end_inset - - when we are given a value of type -\begin_inset Formula $A$ -\end_inset - -. - To translate this statement into the language of logical propositions, - we need to use the logical -\begin_inset Index idx -status open - -\begin_layout Plain Layout -logical implication -\end_layout - -\end_inset - - -\series bold -implication -\series default -, -\begin_inset Formula ${\cal CH}(A)\Rightarrow{\cal CH}(B)$ -\end_inset - -, which means that -\begin_inset Formula ${\cal CH}(B)$ -\end_inset - - can be proved if we already have a proof of -\begin_inset Formula ${\cal CH}(A)$ -\end_inset - -. - So, the rule for function types is: -\begin_inset Formula -\[ -{\cal CH}(A\rightarrow B)={\cal CH}(A)\Rightarrow{\cal CH}(B)\quad. -\] - -\end_inset - - -\end_layout - -\begin_layout Paragraph -5) Rule for parameterized types + names and part names from the Scala type definitions. \end_layout \begin_layout Standard -Here is an example of a function with type parameters: +To clarify our notation for parameterized types, consider this code: \begin_inset listings inline false status open @@ -2912,135 +2713,6 @@ def f[A, B]: A => (A => B) => B = { x => g => g(x) } \end_inset -Being able to define the body of such a function is the same as being able - to compute a value of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A => (A => B) => B -\end_layout - -\end_inset - - for -\emph on -all -\emph default - possible Scala types -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A -\end_layout - -\end_inset - - and -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -B -\end_layout - -\end_inset - -. - In the notation of logic, this is written as: -\begin_inset Formula -\[ -{\cal CH}\left(\forall(A,B).\,A\rightarrow(A\rightarrow B)\rightarrow B\right)\quad, -\] - -\end_inset - -and is equivalent to: -\begin_inset Formula -\[ -\forall(A,B).\,{\cal CH}\left(A\rightarrow(A\rightarrow B)\rightarrow B\right)\quad. -\] - -\end_inset - -The symbol -\begin_inset Formula $\forall$ -\end_inset - - means -\begin_inset Quotes eld -\end_inset - -for all -\begin_inset Quotes erd -\end_inset - - and is called the -\begin_inset Index idx -status open - -\begin_layout Plain Layout -universal quantifier ( -\begin_inset Formula $\forall$ -\end_inset - -) -\end_layout - -\end_inset - - -\series bold -universal quantifier -\series default - in logic. - We read -\begin_inset Formula $\forall A.\,{\cal CH}(B)$ -\end_inset - - as the proposition -\begin_inset Quotes eld -\end_inset - -for all types -\begin_inset Formula $A$ -\end_inset - -, we can compute a value of type -\begin_inset Formula $B$ -\end_inset - - -\begin_inset Quotes erd -\end_inset - -. -\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 inline true @@ -3053,7 +2725,7 @@ f \end_inset - is written in one of the following ways: + may be written as: \begin_inset Formula \[ f^{A,B}:A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\quad\text{or equivalently}:\quad f:\forall(A,B).\,A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad. @@ -3061,7 +2733,11 @@ f^{A,B}:A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\quad\text{or \end_inset -The type quantifier ( +The type quantifier +\begin_inset Formula $\forall(A,B)$ +\end_inset + + (reads \begin_inset Quotes eld \end_inset @@ -3093,8 +2769,7 @@ for all \end_layout \begin_layout Standard -In Scala, longer type expressions can be named, and those names (called - +In Scala, type expressions can be named, and those names (called \series bold type aliases \series default @@ -3110,7 +2785,8 @@ 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 + Defining and using a type alias for the type signature of the function + \begin_inset listings inline true status open @@ -3149,10 +2825,10 @@ f^{A,B}:F^{A,B} & \triangleq x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g( \end_inset -or equivalently (although somewhat less readably) as: +or equivalently (although less readably) as: \begin_inset Formula \[ -f:\big(\forall(A,B).\,F^{A,B}\big)\triangleq\forall(A,B).\,x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad. +f:\big(\forall(A,B).\,F^{A,B}\big)\triangleq\,^{A,B}\rightarrow x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad. \] \end_inset @@ -3208,93 +2884,10 @@ val f: [A, B] => A => (A => B) => B = { // Valid only in Scala 3. \end_inset This syntax closely corresponds to the code notation -\begin_inset Formula $\forall(A,B).\,x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)$ -\end_inset - -. -\end_layout - -\begin_layout Standard -Case classes and disjunctive types use -\emph on -names -\emph default - 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 notation is designed to support nameless type expressions. -\end_layout - -\begin_layout Standard -The rules just shown will allow us to express -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for complicated types via -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions for type parameters. - Then any type signature can be rewritten as a sequent that contains -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions only for the individual type parameters. - -\end_layout - -\begin_layout Standard -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 - -the type signature can be implemented -\begin_inset Quotes erd +\begin_inset Formula $\,^{A,B}\rightarrow x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)$ \end_inset . - This is the first part of the Curry-Howard correspondence. -\end_layout - -\begin_layout Standard -Table -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:ch-correspondence-type-notation-CH-propositions" -plural "false" -caps "false" -noprefix "false" - -\end_inset - - summarizes the type notation and shows how to translate it into logic formulas - with -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions. - Apart from recursive types (which we do not consider in this chapter), - Table -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:ch-correspondence-type-notation-CH-propositions" -plural "false" -caps "false" -noprefix "false" - -\end_inset - - lists all type constructions that may be used in the code of a fully parametric - function. \end_layout \begin_layout Standard @@ -3308,8 +2901,8 @@ type notation!operator precedence \end_inset - of operators in the type notation is chosen to have fewer parentheses in - the type expressions that are frequently used. + of operators in the type notation is chosen in order to write fewer parentheses + in some frequently used type expressions. The rules of precedence are: \end_layout @@ -3326,7 +2919,7 @@ The type product operator ( \begin_inset Formula $A+B\times C$ \end_inset - have the same operator precedence as in standard arithmetic. + have the same operator precedence as in arithmetic. That is, \begin_inset Formula $A+B\times C$ \end_inset @@ -3401,394 +2994,345 @@ The type quantifiers group weaker than all other operators, so we can write without parentheses. 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 + When that is not the case, parentheses are necessary. + An example is the type expression \begin_inset Formula $\left(\forall A.\,A\rightarrow A\rightarrow A\right)\rightarrow\bbnum 1+\bbnum 1$ \end_inset . \end_layout -\begin_layout Standard -\begin_inset Float table -wide false -sideways false -status open +\begin_layout Subsection +Rules for writing +\begin_inset Formula ${\cal CH}$ +\end_inset -\begin_layout Plain Layout -\align center -\begin_inset Tabular - - - - - - - -\begin_inset Text +-propositions +\end_layout -\begin_layout Plain Layout +\begin_layout Standard -\series bold -\size small -Scala syntax \end_layout +\begin_layout Standard +In Section +\begin_inset space ~ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\series bold -\size small -Type notation -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Disjunctions-and-conjunctions" +plural "false" +caps "false" +noprefix "false" \end_inset - - -\begin_inset Text -\begin_layout Plain Layout - -\series bold -\size small + we saw examples of reasoning about \begin_inset Formula ${\cal CH}$ \end_inset --proposition -\end_layout +-propositions for case classes and for disjunctive types. + This reasoning needs to be extended systematically to all type constructions + that fully parametric programs may use. + Then we will be able to express +\begin_inset Formula ${\cal CH}$ +\end_inset +-propositions with arbitrary type expressions, such as +\begin_inset Formula ${\cal CH}($ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout + \begin_inset listings inline true status open \begin_layout Plain Layout -[A] +Either[(A, A), Option[B] => Either[(A, B), C]] \end_layout \end_inset -\end_layout +\begin_inset Formula $)$ +\end_inset +, in terms of +\begin_inset Formula ${\cal CH}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $A$ +-propositions for simple type parameters: +\begin_inset Formula ${\cal CH}(A)$ \end_inset +, +\begin_inset Formula ${\cal CH}(B)$ +\end_inset +, etc. + \end_layout -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(A)$ +\begin_layout Standard +We will now derive the rules for writing +\begin_inset Formula ${\cal CH}$ \end_inset - +-propositions for each of the standard type constructions except recursive + types. \end_layout -\end_inset - - - - -\begin_inset Text +\begin_layout Paragraph +1a) Rule for the +\family typewriter +Unit +\family default + type +\end_layout -\begin_layout Plain Layout +\begin_layout Standard +The \begin_inset listings inline true status open \begin_layout Plain Layout -(A, B) +Unit \end_layout \end_inset - -\end_layout - -\end_inset - - -\begin_inset Text + type has only a single value +\begin_inset listings +inline true +status open \begin_layout Plain Layout -\begin_inset Formula $A\times B$ -\end_inset - +() \end_layout \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(A)$ +, an +\begin_inset Quotes eld \end_inset - -\begin_inset Formula $\wedge$ +empty tuple +\begin_inset Quotes erd \end_inset - -\begin_inset Formula ${\cal CH}(B)$ -\end_inset +. + This value can be +\emph on +always +\emph default + computed as it does not need any previous data: +\begin_inset listings +inline false +status open +\begin_layout Plain Layout +def f[...]: ... + = { \end_layout -\end_inset - - - - -\begin_inset Text - \begin_layout Plain Layout -\begin_inset listings -inline true -status open + + ... +\end_layout \begin_layout Plain Layout -Either[A, B] + val x: Unit = () // We can always compute a `Unit` value. \end_layout -\end_inset - +\begin_layout Plain Layout + ... \end_layout \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $A+B$ +So, the proposition +\begin_inset Formula ${\cal CH}($ \end_inset -\end_layout - -\end_inset - - -\begin_inset Text +\begin_inset listings +inline true +status open \begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(A)$ -\end_inset - -\begin_inset Formula $\vee$ -\end_inset +Unit +\end_layout - -\begin_inset Formula ${\cal CH}(B)$ \end_inset -\end_layout - +\begin_inset Formula $)$ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout + is always true. + In the type notation, the \begin_inset listings inline true status open \begin_layout Plain Layout -A => B +Unit \end_layout \end_inset - -\end_layout - + type is denoted by +\begin_inset Formula $\bbnum 1$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $A\rightarrow B$ +. + We may write the rule as +\begin_inset Formula $\mathcal{CH}(\bbnum 1)=True$ \end_inset - +. + \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard +Named unit types +\begin_inset Index idx +status open \begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(A)$ -\end_inset +unit type!named +\end_layout - -\begin_inset Formula $\Rightarrow$ \end_inset - -\begin_inset Formula ${\cal CH}(B)$ -\end_inset + also have a single value that is always possible to compute. + For example: +\begin_inset listings +inline false +status open +\begin_layout Plain Layout +final case class N1() \end_layout \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout +defines a named unit type. + We can compute a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +N1 \end_layout \end_inset + without using any previously given values: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout +val x: N1 = N1() \end_layout \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $\bbnum 1$ +So, the proposition +\begin_inset Formula ${\cal CH}($ \end_inset -\end_layout - -\end_inset - - -\begin_inset Text +\begin_inset listings +inline true +status open \begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(\bbnum 1)=True$ -\end_inset - +N1 \end_layout \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout -\size small +\begin_inset Formula $)$ +\end_inset + + is always true. + In the type notation, named unit types are also denoted by +\begin_inset Formula $\bbnum 1$ +\end_inset + +, same as the \begin_inset listings inline true status open \begin_layout Plain Layout -Int +Unit \end_layout \end_inset -, + type itself. +\end_layout + +\begin_layout Paragraph +1b) Rule for the void type +\end_layout + +\begin_layout Standard +The Scala type \begin_inset listings inline true status open \begin_layout Plain Layout -String +Nothing \end_layout \end_inset -, ... -\end_layout - + has no values, so the proposition +\begin_inset Formula ${\cal CH}($ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\size small -\begin_inset Formula $\text{Int}$ -\end_inset +\begin_inset listings +inline true +status open -, -\begin_inset Formula $\text{String}$ -\end_inset +\begin_layout Plain Layout -, ... +Nothing \end_layout \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(\text{Int})=True$ -\end_inset -\end_layout - +\begin_inset Formula $)$ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout + is always false. + The type \begin_inset listings inline true status open @@ -3800,380 +3344,449 @@ Nothing \end_inset - -\end_layout - + is denoted by +\begin_inset Formula $\bbnum 0$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $\bbnum 0$ + in the type notation. + So, the rule is +\begin_inset Formula $\mathcal{CH}(\bbnum 0)=False$ \end_inset +. +\end_layout +\begin_layout Paragraph +1c) Rule for primitive types \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard +For a specific primitive (or library-defined) type such as +\begin_inset listings +inline true +status open \begin_layout Plain Layout -\begin_inset Formula ${\cal CH}(\bbnum 0)=False$ -\end_inset - +Int \end_layout \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout + or \begin_inset listings inline true status open \begin_layout Plain Layout -def f[A]: F[A] +String \end_layout \end_inset +, the corresponding +\begin_inset Formula ${\cal CH}$ +\end_inset + +-proposition is +\emph on +always true +\emph default + because we may always create a constant value of that type, e.g.: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout +def f[...]: ... + { \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Plain Layout + + ... +\end_layout \begin_layout Plain Layout -\begin_inset Formula $f^{A}:F^{A}$ + + val x: String = +\begin_inset Quotes eld \end_inset +abc +\begin_inset Quotes erd +\end_inset + // We can always compute a `String` value. \end_layout -\end_inset - - -\begin_inset Text - \begin_layout Plain Layout -\begin_inset Formula $\forall A.\,{\cal CH}(F^{A})$ -\end_inset + ... +\end_layout + +\begin_layout Plain Layout +} \end_layout \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout +So, the rule for primitive types is the same as that for the \begin_inset listings inline true status open \begin_layout Plain Layout -val f: [A] => F[A] -\end_layout - -\end_inset - - -\size small - (Scala 3) +Unit \end_layout \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $f:\forall A.\,F^{A}$ + type. + For example, +\begin_inset Formula $\mathcal{CH}(\text{String})=True$ \end_inset +. +\end_layout +\begin_layout Paragraph +2) Rule for tuple types \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard +To compute a value of a tuple type +\begin_inset listings +inline true +status open \begin_layout Plain Layout -\begin_inset Formula $\forall A.\,{\cal CH}(F^{A})$ -\end_inset - +(A, B) \end_layout \end_inset - - - -\end_inset + requires computing a value of type +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +A \end_layout -\begin_layout Plain Layout -\begin_inset Caption Standard +\end_inset -\begin_layout Plain Layout -The correspondence -\begin_inset Index idx + +\emph on +and +\emph default + a value of type +\begin_inset listings +inline true status open \begin_layout Plain Layout -type notation + +B \end_layout \end_inset - between types and -\begin_inset Formula ${\cal CH}$ +. + This is expressed by the logical formula +\begin_inset Formula ${\cal CH}($ \end_inset --propositions. -\begin_inset CommandInset label -LatexCommand label -name "tab:ch-correspondence-type-notation-CH-propositions" -\end_inset +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +(A, B) \end_layout \end_inset -\end_layout +\begin_inset Formula $)={\cal CH}(A)\wedge{\cal CH}(B)$ +\end_inset +. + A similar formula holds for case classes, as Eq. +\begin_inset space ~ \end_inset +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:curry-howard-example-case-class" +plural "false" +caps "false" +noprefix "false" -\end_layout +\end_inset -\begin_layout Subsection -Examples: Type notation -\begin_inset Index idx +) shows. + In the type notation, the tuple +\begin_inset listings +inline true status open \begin_layout Plain Layout -examples (with code) + +(A, B) \end_layout \end_inset + is written as +\begin_inset Formula $A\times B$ +\end_inset + +, and tuples with more parts are written similarly. + So, we write the rule for tuples as: +\begin_inset Formula +\[ +{\cal CH}\left(A\times B\times...\times C\right)={\cal CH}(A)\wedge{\cal CH}(B)\wedge...\wedge{\cal CH}(C)\quad. +\] + +\end_inset -\end_layout -\begin_layout Standard -From now on, we will prefer to write types in the type notation rather than - in the Scala syntax. - The type notation allows us to write nameless type expressions and makes - the structure of complicated types clearer than in the Scala syntax. - Names of types and parts of types are, of course, helpful for reminding - programmers of the meaning of data in a program. - However, writing names for every part of every type does not help reasoning - about the properties of types. - Once the programmer has finished deriving the necessary types and verifying - their properties, the type notation can be straightforwardly translated - into Scala code. - Let us get some experience doing that. \end_layout -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-dupl-function" +\begin_layout Paragraph +3) Rule for disjunctive types +\end_layout +\begin_layout Standard +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. +\begin_inset space ~ \end_inset - +( \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Example-ch-dupl-function" +reference "eq:curry-howard-example-disjunction" plural "false" caps "false" noprefix "false" \end_inset - -\end_layout - -\begin_layout Standard -Define a function +). + For the standard disjunctive type \begin_inset listings inline true status open \begin_layout Plain Layout -delta +Either[A, B] \end_layout \end_inset - taking an argument -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -x -\end_layout - +, we have the logical formula +\begin_inset Formula ${\cal CH}($ \end_inset - and returning the pair + \begin_inset listings inline true status open \begin_layout Plain Layout -(x, x) +Either[A, B] \end_layout \end_inset -. - Derive the most general type for this function. - Write the type signature of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -delta -\end_layout +\begin_inset Formula $)={\cal CH}(A)\vee{\cal CH}(B)$ \end_inset - in the type notation, and translate it into a -\begin_inset Formula ${\cal CH}$ +. + In the type notation, disjunctive types with more than two parts are written + similarly as +\begin_inset Formula $A+B+...+C$ \end_inset --proposition. - Simplify the -\begin_inset Formula ${\cal CH}$ +. + So, the rule for disjunctive types is written as: +\begin_inset Formula +\[ +{\cal CH}\left(A+B+...+C\right)={\cal CH}(A)\vee{\cal CH}(B)\vee...\vee{\cal CH}(C)\quad. +\] + \end_inset --proposition if possible. + \end_layout -\begin_layout Subparagraph -Solution +\begin_layout Paragraph +4) Rule for function types \end_layout \begin_layout Standard -Begin by writing the code of the function: +Consider now a function type such as \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def delta(x: ...) = (x, x) +A => B \end_layout \end_inset -To derive the most general type for +. + This type is written in the type notation as +\begin_inset Formula $A\rightarrow B$ +\end_inset + +. + To compute a value of that type, we need to write code like this: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -delta +val f: A => B = { (a: A) => \end_layout -\end_inset +\begin_layout Plain Layout -, first assume -\begin_inset listings -inline true -status open + ??? // Compute a value of type B in this scope. +\end_layout \begin_layout Plain Layout -x: A +} \end_layout \end_inset -, where +The inner scope of this function needs to compute a value of type +\begin_inset Formula $B$ +\end_inset + +, and the given value \begin_inset listings inline true status open \begin_layout Plain Layout -A +a: A \end_layout \end_inset - is a type parameter; then the tuple -\begin_inset listings -inline true + may be used for that. + So, +\begin_inset Formula ${\cal CH}(A\rightarrow B)$ +\end_inset + + is true if and only if we are able to compute a value of type +\begin_inset Formula $B$ +\end_inset + + when we are given a value of type +\begin_inset Formula $A$ +\end_inset + +. + To translate this statement into the language of logical propositions, + we need to use the logical +\begin_inset Index idx status open \begin_layout Plain Layout - -(x, x) +logical implication \end_layout \end_inset - has type + +\series bold +implication +\series default +, +\begin_inset Formula ${\cal CH}(A)\Rightarrow{\cal CH}(B)$ +\end_inset + +, which means that +\begin_inset Formula ${\cal CH}(B)$ +\end_inset + + can be proved if we already have a proof of +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + +. + So, the rule for function types is: +\begin_inset Formula +\[ +{\cal CH}(A\rightarrow B)={\cal CH}(A)\Rightarrow{\cal CH}(B)\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Paragraph +5) Rule for parameterized types +\end_layout + +\begin_layout Standard +Consider this function with type parameters: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -(A, A) +def f[A, B]: A => (A => B) => B = { x => g => g(x) } \end_layout \end_inset -. - We do not see any constraints on the type parameter +Being able to define the body of such a function is the same as being able + to compute a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -A +A => (A => B) => B \end_layout \end_inset -. - So, + for +\emph on +all +\emph default + possible Scala types \begin_inset listings inline true status open @@ -4185,1097 +3798,1197 @@ A \end_inset - represents an arbitrary type and needs to be added to the type signature - of + and \begin_inset listings inline true status open \begin_layout Plain Layout -delta +B \end_layout \end_inset -: -\begin_inset listings -inline false +. + In the notation of logic, this is written as: +\begin_inset Formula +\[ +{\cal CH}\left(\forall(A,B).\,A\rightarrow(A\rightarrow B)\rightarrow B\right)\quad, +\] + +\end_inset + +and is equivalent to: +\begin_inset Formula +\[ +\forall(A,B).\,{\cal CH}\left(A\rightarrow(A\rightarrow B)\rightarrow B\right)\quad. +\] + +\end_inset + +The symbol +\begin_inset Formula $\forall$ +\end_inset + + means +\begin_inset Quotes eld +\end_inset + +for all +\begin_inset Quotes erd +\end_inset + + and is called the +\begin_inset Index idx status open \begin_layout Plain Layout +universal quantifier ( +\begin_inset Formula $\forall$ +\end_inset -def delta[A](x: A): (A, A) = (x, x) +) \end_layout \end_inset -We find that the most general type of + +\series bold +universal quantifier +\series default + in logic. + We read +\begin_inset Formula $\forall A.\,{\cal CH}(F^{A})$ +\end_inset + + as the proposition +\begin_inset Quotes eld +\end_inset + +for all types \begin_inset listings inline true status open \begin_layout Plain Layout -delta +A \end_layout \end_inset - is +, we can compute a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -A => (A, A) +F[A] \end_layout \end_inset + +\begin_inset Quotes erd +\end_inset + . - We also note that + Here, \begin_inset listings inline true status open \begin_layout Plain Layout -delta +F[A] \end_layout \end_inset - seems to be the only way of implementing a fully parametric function with - type signature + can be any type expression that depends on \begin_inset listings inline true status open \begin_layout Plain Layout -A => (A, A) -\end_layout - -\end_inset - -. +A \end_layout -\begin_layout Standard -We will use the letter -\begin_inset Formula $\Delta$ \end_inset - for the function + (or even a type expression that does not depend on \begin_inset listings inline true status open \begin_layout Plain Layout -delta +A \end_layout \end_inset -. - In the type notation, the type signature of -\begin_inset Formula $\Delta$ +). +\end_layout + +\begin_layout Standard +So, the rule for parameterized types of the form +\begin_inset Formula $\forall A.\,F^{A}$ \end_inset is: \begin_inset Formula \[ -\Delta^{A}:A\rightarrow A\times A\quad. +{\cal CH}(\forall A.\,F^{A})=\forall A.\,{\cal CH}(F^{A})\quad. \] \end_inset -So, the proposition -\begin_inset Formula ${\cal CH}(\Delta)$ -\end_inset - - (meaning -\begin_inset Quotes eld -\end_inset - -the function -\begin_inset Formula $\Delta$ -\end_inset - - can be implemented -\begin_inset Quotes erd -\end_inset - -) is: -\begin_inset Formula -\[ -{\cal CH}(\Delta)=\forall A.{\cal \,CH}\left(A\rightarrow A\times A\right)\quad. -\] - -\end_inset -In the type expression -\begin_inset Formula $A\rightarrow A\times A$ -\end_inset +\end_layout -, the product symbol ( -\begin_inset Formula $\times$ +\begin_layout Standard +The rules just shown will allow us to express +\begin_inset Formula ${\cal CH}$ \end_inset -) binds stronger than the function arrow ( -\begin_inset Formula $\rightarrow$ +-propositions for complicated types via +\begin_inset Formula ${\cal CH}$ \end_inset -), so the parentheses in -\begin_inset Formula $A\rightarrow\left(A\times A\right)$ +-propositions for type parameters. + Then any type signature can be rewritten as a sequent that contains +\begin_inset Formula ${\cal CH}$ \end_inset - may be omitted. +-propositions only for the individual type parameters. + \end_layout \begin_layout Standard -Using the rules for transforming -\begin_inset Formula ${\cal CH}$ +In this way, we find a correspondence between a fully parametric type signature + and a logical sequent that expresses the statement +\begin_inset Quotes eld \end_inset --propositions, we rewrite: -\begin_inset Formula -\begin{align*} - & {\cal CH}(A\rightarrow A\times A)\\ -\text{rule for function types}:\quad & ={\cal CH}(A)\Rightarrow{\cal CH}(A\times A)\\ -\text{rule for tuple types}:\quad & ={\cal CH}(A)\Rightarrow\left({\cal CH}(A)\wedge{\cal CH}(A)\right)\quad. -\end{align*} - +the type signature can be implemented +\begin_inset Quotes erd \end_inset -Thus the proposition -\begin_inset Formula ${\cal CH}(\Delta)$ -\end_inset +. + This is the first part of the +\series bold +Curry-Howard correspondence +\series default - is equivalent to: -\begin_inset Formula -\[ -{\cal CH}(\Delta)=\forall A.\,{\cal CH}(A)\Rightarrow({\cal CH}(A)\wedge{\cal CH}(A))\quad. -\] +\begin_inset Index idx +status open -\end_inset +\begin_layout Plain Layout +Curry-Howard correspondence +\end_layout +\end_inset +. \end_layout \begin_layout Standard -It is intuitively clear that the proposition -\begin_inset Formula ${\cal CH}(\Delta)$ +Table +\begin_inset space ~ \end_inset - is true: it just says that if -\begin_inset Formula ${\cal CH}(A)$ -\end_inset - is true then -\begin_inset Formula ${\cal CH}(A)$ -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:ch-correspondence-type-notation-CH-propositions" +plural "false" +caps "false" +noprefix "false" - and -\begin_inset Formula ${\cal CH}(A)$ \end_inset - is true. - The point of writing -\begin_inset Formula ${\cal CH}(\Delta)$ + summarizes the type notation and shows how to translate it into logic formulas + with +\begin_inset Formula ${\cal CH}$ \end_inset - in a mathematical notation is to prepare for proving this proposition rigorousl -y rather than based on intuition. -\end_layout - -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-notation-function-1" - +-propositions. + Apart from recursive types (which we do not consider in this chapter), + Table +\begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Example-ch-notation-function-1" +reference "tab:ch-correspondence-type-notation-CH-propositions" plural "false" caps "false" noprefix "false" \end_inset - + lists all type constructions that may be used in the code of a fully parametric + function. \end_layout \begin_layout Standard -The standard types -\begin_inset listings -inline true +\begin_inset Float table +wide false +sideways false status open +\begin_layout Plain Layout +\align center +\begin_inset Tabular + + + + + + + +\begin_inset Text + \begin_layout Plain Layout -Either[A, B] +\series bold +\size small +Scala syntax \end_layout \end_inset - - and -\begin_inset listings -inline true -status open + + +\begin_inset Text \begin_layout Plain Layout -Option[A] +\series bold +\size small +Type notation \end_layout \end_inset - - are written in the type notation as: -\begin_inset Formula -\[ -\text{Either}^{A,B}\triangleq A+B\quad,\quad\quad\text{Opt}^{A}\triangleq\bbnum 1+A\quad. -\] - -\end_inset - -The type -\begin_inset listings -inline true -status open + + +\begin_inset Text \begin_layout Plain Layout -Either[A, B] -\end_layout - +\series bold +\size small +\begin_inset Formula ${\cal CH}$ \end_inset - is written as -\begin_inset Formula $A+B$ -\end_inset +-proposition +\end_layout - by definition of the disjunctive type notation ( -\begin_inset Formula $+$ \end_inset + + + + +\begin_inset Text -). - The type +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -Option[A] +Unit \end_layout \end_inset - has two disjoint cases, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -None \end_layout \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\bbnum 1$ +\end_inset - and -\begin_inset listings -inline true -status open + +\end_layout + +\end_inset + + +\begin_inset Text \begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(\bbnum 1)=True$ +\end_inset + -Some[A] \end_layout \end_inset + + + + +\begin_inset Text -. - The case class +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -None +Nothing \end_layout \end_inset - is a -\begin_inset Quotes eld + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\bbnum 0$ \end_inset -\begin_inset Index idx -status open +\end_layout + +\end_inset + + +\begin_inset Text \begin_layout Plain Layout -unit type!named +\begin_inset Formula ${\cal CH}(\bbnum 0)=False$ +\end_inset + + \end_layout \end_inset + + + + +\begin_inset Text -named +\begin_layout Plain Layout + +\size small \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +Int \end_layout \end_inset - -\begin_inset Quotes erd -\end_inset - - and is denoted by -\begin_inset Formula $\bbnum 1$ -\end_inset - -. - The case class +, \begin_inset listings inline true status open \begin_layout Plain Layout -Some[A] +String \end_layout \end_inset - contains a single value of type -\begin_inset Formula $A$ -\end_inset +, ... +\end_layout -. - So, the type notation for -\begin_inset listings -inline true -status open +\end_inset + + +\begin_inset Text \begin_layout Plain Layout -Option[A] +\size small +\begin_inset Formula $\text{Int}$ +\end_inset + +, +\begin_inset Formula $\text{String}$ +\end_inset + +, ... \end_layout \end_inset + + +\begin_inset Text - is -\begin_inset Formula $\bbnum 1+A$ +\begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(\text{Int})=True$ \end_inset -. - We will also sometimes write -\begin_inset Formula $\text{Opt}^{A}$ + +\end_layout + \end_inset + + + + +\begin_inset Text - to denote +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -Option[A] +(A, B) \end_layout \end_inset -. + \end_layout -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-notation-function-1-a" +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +\begin_inset Formula $A\times B$ \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-ch-notation-function-1-a" -plural "false" -caps "false" -noprefix "false" +\end_layout \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(A)$ +\end_inset -\end_layout + +\begin_inset Formula $\wedge$ +\end_inset -\begin_layout Standard -The Scala definition of the disjunctive type -\begin_inset listings -inline true -status open + +\begin_inset Formula ${\cal CH}(B)$ +\end_inset -\begin_layout Plain Layout -UserAction \end_layout \end_inset + + + + +\begin_inset Text -: +\begin_layout Plain Layout \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -sealed trait UserAction +Either[A, B] \end_layout -\begin_layout Plain Layout - -final case class SetName(first: String, last: String) extends UserAction -\end_layout +\end_inset -\begin_layout Plain Layout -final case class SetEmail(email: String) extends UserAction \end_layout +\end_inset + + +\begin_inset Text + \begin_layout Plain Layout +\begin_inset Formula $A+B$ +\end_inset + -final case class SetUserId(id: Long) extends UserAction \end_layout \end_inset + + +\begin_inset Text -is written in the type notation as: -\begin_inset Formula -\begin{equation} -\text{UserAction}\triangleq\text{String}\times\text{String}+\text{String}+\text{Long}\quad.\label{eq:ch-example-case-class-type-notation} -\end{equation} - +\begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(A)$ \end_inset -The type operation -\begin_inset Formula $\times$ + +\begin_inset Formula $\vee$ \end_inset - groups stronger than -\begin_inset Formula $+$ + +\begin_inset Formula ${\cal CH}(B)$ \end_inset -, as in arithmetic. - To derive the type notation -\begin_inset space ~ -\end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-example-case-class-type-notation" -plural "false" -caps "false" -noprefix "false" +\end_layout \end_inset + + + + +\begin_inset Text -), we first drop all names from case classes and get three nameless tuples - +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -(String, String) +A => B \end_layout \end_inset -, -\begin_inset listings -inline true -status open -\begin_layout Plain Layout - -(String) \end_layout \end_inset - -, and -\begin_inset listings -inline true -status open + + +\begin_inset Text \begin_layout Plain Layout +\begin_inset Formula $A\rightarrow B$ +\end_inset + -(Long) \end_layout \end_inset + + +\begin_inset Text -. - Each of these tuples is then converted into a product using the operator - -\begin_inset Formula $\times$ +\begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(A)$ \end_inset -, and all products are -\begin_inset Quotes eld + +\begin_inset Formula $\Rightarrow$ \end_inset -summed -\begin_inset Quotes erd + +\begin_inset Formula ${\cal CH}(B)$ \end_inset - in the type notation using the operator -\begin_inset Formula $+$ -\end_inset -. \end_layout -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-notation-function-2" +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A +\end_layout \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-ch-notation-function-2" -plural "false" -caps "false" -noprefix "false" +\size small + (type parameter) +\end_layout + +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +\begin_inset Formula $A$ \end_inset \end_layout -\begin_layout Standard -The parameterized disjunctive type -\begin_inset listings -inline true -status open +\end_inset + + +\begin_inset Text \begin_layout Plain Layout +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + -Either3 \end_layout \end_inset + + + + +\begin_inset Text - is a generalization of +\begin_layout Plain Layout \begin_inset listings inline true status open \begin_layout Plain Layout -Either +def f[A]: F[A] \end_layout \end_inset -: -\begin_inset listings -inline false -status open + +\end_layout + +\end_inset + + +\begin_inset Text \begin_layout Plain Layout +\begin_inset Formula $f^{A}:F^{A}$ +\end_inset + -sealed trait Either3[A, B, C] \end_layout +\end_inset + + +\begin_inset Text + \begin_layout Plain Layout +\begin_inset Formula $\forall A.\,{\cal CH}(F^{A})$ +\end_inset + -final case class Left[A, B, C](x: A) extends Either3[A, B, C] \end_layout +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset listings +inline true +status open + \begin_layout Plain Layout -final case class Middle[A, B, C](x: B) extends Either3[A, B, C] +val f: [A] => F[A] \end_layout -\begin_layout Plain Layout +\end_inset -final case class Right[A, B, C](x: C) extends Either3[A, B, C] + +\size small + (Scala 3) \end_layout \end_inset + + +\begin_inset Text -This disjunctive type is written in the type notation as -\begin_inset Formula $\text{Either3}^{A,B,C}\triangleq A+B+C$ +\begin_layout Plain Layout +\begin_inset Formula $f:\forall A.\,F^{A}$ \end_inset -. + \end_layout -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-notation-function-3" +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +\begin_inset Formula $\forall A.\,{\cal CH}(F^{A})$ \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-ch-notation-function-3" -plural "false" -caps "false" -noprefix "false" +\end_layout + +\end_inset + + + \end_inset \end_layout -\begin_layout Standard -Define a Scala type constructor -\begin_inset listings -inline true -status open +\begin_layout Plain Layout +\begin_inset Caption Standard \begin_layout Plain Layout +The correspondence +\begin_inset Index idx +status open -F[A] +\begin_layout Plain Layout +type notation \end_layout \end_inset - corresponding to the type notation: -\begin_inset Formula -\[ -F^{A}\triangleq\bbnum 1+\text{Int}\times A\times A+\text{Int}\times\left(\text{Int}\rightarrow A\right)\quad. -\] + between types and +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions. +\begin_inset CommandInset label +LatexCommand label +name "tab:ch-correspondence-type-notation-CH-propositions" \end_inset \end_layout -\begin_layout Subparagraph -Solution +\end_inset + + \end_layout -\begin_layout Standard -The formula for -\begin_inset Formula $F^{A}$ \end_inset - defines a disjunctive type -\begin_inset listings -inline true + +\end_layout + +\begin_layout Subsection +Examples: Type notation +\begin_inset Index idx status open \begin_layout Plain Layout - -F[A] +examples (with code) \end_layout \end_inset - with three parts. - To implement -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\end_layout -F[A] +\begin_layout Standard +From now on, we will prefer to write types in the type notation rather than + in the Scala syntax. + The type notation allows us to write nameless type expressions and makes + the structure of complicated types clearer than in the Scala syntax. + Names are, of course, helpful for reminding programmers of the meaning + of data represented by case classes and disjunctive types. + However, writing names for every part of every type does not help in reasoning + about the properties of types. + Once the programmer has finished deriving the necessary types and verifying + their properties, the type notation can be straightforwardly translated + into Scala code. + Let us get some experience doing that. \end_layout +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-ch-dupl-function" + \end_inset - in Scala, we need to choose names for each of the disjoint parts, which - will become case classes. - For the purposes of this example, let us choose names + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-ch-dupl-function" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Define a function \begin_inset listings inline true status open \begin_layout Plain Layout -F1 +delta \end_layout \end_inset -, + taking an argument \begin_inset listings inline true status open \begin_layout Plain Layout -F2 +x \end_layout \end_inset -, and + and returning the pair \begin_inset listings inline true status open \begin_layout Plain Layout -F3 +(x, x) \end_layout \end_inset . - Each of these case classes needs to have the same type parameter + Derive the most general type for this function. + Write the type signature of \begin_inset listings inline true status open \begin_layout Plain Layout -A +delta \end_layout \end_inset -. - So, we begin writing the code as: -\begin_inset listings -inline false -status open + in the type notation, and translate it into a +\begin_inset Formula ${\cal CH}$ +\end_inset -\begin_layout Plain Layout +-proposition. + Simplify the +\begin_inset Formula ${\cal CH}$ +\end_inset -sealed trait F[A] +-proposition if possible. \end_layout -\begin_layout Plain Layout - -final case class F1[A](...) extends F[A] +\begin_layout Subparagraph +Solution \end_layout -\begin_layout Plain Layout - -final case class F2[A](...) extends F[A] -\end_layout +\begin_layout Standard +Begin by writing the code of the function: +\begin_inset listings +inline false +status open \begin_layout Plain Layout -final case class F3[A](...) extends F[A] +def delta(x: ...) = (x, x) \end_layout \end_inset -Each of these case classes represents one part of the disjunctive type: - +To derive the most general type for \begin_inset listings inline true status open \begin_layout Plain Layout -F1 +delta \end_layout \end_inset - represents -\begin_inset Formula $\bbnum 1$ -\end_inset - -, +, first assume \begin_inset listings inline true status open \begin_layout Plain Layout -F2 +x: A \end_layout \end_inset - represents -\begin_inset Formula $\text{Int}\times A\times A$ -\end_inset - -, and +, where \begin_inset listings inline true status open \begin_layout Plain Layout -F3 +A \end_layout \end_inset - represents -\begin_inset Formula $\text{Int}\times\left(\text{Int}\rightarrow A\right)$ -\end_inset - -. - It remains to choose names and define the case classes: + is a type parameter; then the tuple \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -sealed trait F[A] -\end_layout - -\begin_layout Plain Layout - -final case class F1[A]() extends F[A] // Named unit - type. +(x, x) \end_layout -\begin_layout Plain Layout +\end_inset -final case class F2[A](n: Int, x1: A, x2: A) extends F[A] -\end_layout + has type +\begin_inset listings +inline true +status open \begin_layout Plain Layout -final case class F3[A](n: Int, f: Int => A) extends F[A] +(A, A) \end_layout \end_inset -The names +. + We do not see any constraints on the type parameter \begin_inset listings inline true status open \begin_layout Plain Layout -n +A \end_layout \end_inset -, +. + So, \begin_inset listings inline true status open \begin_layout Plain Layout -x1 +A \end_layout \end_inset -, + represents an arbitrary type and needs to be added to the type signature + of \begin_inset listings inline true status open \begin_layout Plain Layout -x2 +delta \end_layout \end_inset -, and +: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -f +def delta[A](x: A): (A, A) = (x, x) \end_layout \end_inset - are chosen arbitrarily. -\end_layout - -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-ch-notation-function-4" - -\end_inset +We find that the most general type of +\begin_inset listings +inline true +status open +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-ch-notation-function-4" -plural "false" -caps "false" -noprefix "false" +delta +\end_layout \end_inset - -\end_layout - -\begin_layout Standard -Write the type signature of the following function in the type notation: + is \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def fmap[A, B](f: A => B): Option[A] => Option[B] +A => (A, A) \end_layout \end_inset - -\end_layout - -\begin_layout Subparagraph -Solution -\end_layout - -\begin_layout Standard -This is a curried function, so we first rewrite the type signature as: +. + We also note that \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def fmap[A, B]: (A => B) => Option[A] => Option[B] +delta \end_layout \end_inset -The type notation for + seems to be the only way of implementing a fully parametric function with + type signature \begin_inset listings inline true status open \begin_layout Plain Layout -Option[A] +A => (A, A) \end_layout \end_inset - is -\begin_inset Formula $\bbnum 1+A$ +. +\end_layout + +\begin_layout Standard +We will use the letter +\begin_inset Formula $\Delta$ \end_inset -. - Now we can write the type signature of + for the function \begin_inset listings inline true status open \begin_layout Plain Layout -fmap +delta \end_layout \end_inset - as: +. + In the type notation, the type signature of +\begin_inset Formula $\Delta$ +\end_inset + + is: \begin_inset Formula -\begin{align*} - & \text{fmap}^{A,B}:\left(A\rightarrow B\right)\rightarrow\bbnum 1+A\rightarrow\bbnum 1+B\quad,\\ -\text{or equivalently}:\quad & \text{fmap}:\forall(A,B).\,\left(A\rightarrow B\right)\rightarrow\bbnum 1+A\rightarrow\bbnum 1+B\quad. -\end{align*} +\[ +\Delta^{A}:A\rightarrow A\times A\quad. +\] \end_inset -We do not put parentheses around -\begin_inset Formula $\bbnum 1+A$ +So, the proposition +\begin_inset Formula ${\cal CH}(\Delta)$ \end_inset - and -\begin_inset Formula $\bbnum 1+B$ + (meaning +\begin_inset Quotes eld \end_inset - because the function arrow ( -\begin_inset Formula $\rightarrow$ +the function +\begin_inset Formula $\Delta$ \end_inset -) groups weaker than the other type operations. - But parentheses around -\begin_inset Formula $\left(A\rightarrow B\right)$ + can be implemented +\begin_inset Quotes erd \end_inset - are required. -\end_layout +) is: +\begin_inset Formula +\[ +{\cal CH}(\Delta)=\forall A.{\cal \,CH}\left(A\rightarrow A\times A\right)\quad. +\] -\begin_layout Standard -We will usually prefer to write type parameters in superscripts rather than - under type quantifiers. - So, for example, we will write -\begin_inset Formula $\text{id}^{A}\triangleq x^{:A}\rightarrow x$ \end_inset - rather than -\begin_inset Formula $\text{id}\triangleq\forall A.\,x^{:A}\rightarrow x$ +In the type expression +\begin_inset Formula $A\rightarrow A\times A$ \end_inset -. -\end_layout - -\begin_layout Subsection -Exercises: Type notation -\begin_inset Index idx -status open - -\begin_layout Plain Layout -exercises -\end_layout +, the product symbol ( +\begin_inset Formula $\times$ +\end_inset +) binds stronger than the function arrow ( +\begin_inset Formula $\rightarrow$ \end_inset +), so the parentheses in +\begin_inset Formula $A\rightarrow\left(A\times A\right)$ +\end_inset + may be omitted. \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:Exercise-type-notation-1" +\begin_layout Standard +Using the rules for transforming +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions, we rewrite: +\begin_inset Formula +\begin{align*} + & {\cal CH}(A\rightarrow A\times A)\\ +\text{rule for function types}:\quad & ={\cal CH}(A)\Rightarrow{\cal CH}(A\times A)\\ +\text{rule for tuple types}:\quad & ={\cal CH}(A)\Rightarrow\left({\cal CH}(A)\wedge{\cal CH}(A)\right)\quad. +\end{align*} \end_inset +Thus the proposition +\begin_inset Formula ${\cal CH}(\Delta)$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Exercise-type-notation-1" -plural "false" -caps "false" -noprefix "false" + is equivalent to: +\begin_inset Formula +\[ +{\cal CH}(\Delta)=\forall A.\,{\cal CH}(A)\Rightarrow({\cal CH}(A)\wedge{\cal CH}(A))\quad. +\] \end_inset @@ -5283,41 +4996,43 @@ noprefix "false" \end_layout \begin_layout Standard -Define a Scala disjunctive type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Q[T, A] -\end_layout +It is intuitively clear that the proposition +\begin_inset Formula ${\cal CH}(\Delta)$ +\end_inset + is true: it just says that if +\begin_inset Formula ${\cal CH}(A)$ \end_inset - corresponding to this type notation: -\begin_inset Formula -\[ -Q^{T,A}\triangleq\bbnum 1+T\times A+\text{Int}\times(T\rightarrow T)+\text{String}\times A\quad. -\] + is true then +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + and +\begin_inset Formula ${\cal CH}(A)$ \end_inset + is true. + The point of writing +\begin_inset Formula ${\cal CH}(\Delta)$ +\end_inset + in a mathematical notation is to prepare for proving that proposition rigorousl +y. \end_layout \begin_layout Subsubsection -Exercise +Example \begin_inset CommandInset label LatexCommand label -name "subsec:Exercise-type-notation-2" +name "subsec:Example-ch-notation-function-1" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Exercise-type-notation-2" +reference "subsec:Example-ch-notation-function-1" plural "false" caps "false" noprefix "false" @@ -5328,1857 +5043,1573 @@ noprefix "false" \end_layout \begin_layout Standard -Convert the type +The standard types \begin_inset listings inline true status open \begin_layout Plain Layout -Either[(A, Int), Either[(A, Char), (A, Float)]] +Either[A, B] \end_layout \end_inset - from Scala syntax to the type notation. - -\end_layout - -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:Exercise-type-notation-3" - -\end_inset + and +\begin_inset listings +inline true +status open +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Exercise-type-notation-3" -plural "false" -caps "false" -noprefix "false" +Option[A] +\end_layout \end_inset + are written in the type notation as: +\begin_inset Formula +\[ +\text{Either}^{A,B}\triangleq A+B\quad,\quad\quad\text{Opt}^{A}\triangleq\bbnum 1+A\quad. +\] -\end_layout +\end_inset -\begin_layout Standard -Define a Scala type +The type \begin_inset listings inline true status open \begin_layout Plain Layout -Opt2[A, B] +Either[A, B] \end_layout \end_inset - written in the type notation as -\begin_inset Formula $\bbnum 1+A+B$ + is written as +\begin_inset Formula $A+B$ \end_inset -. -\end_layout + by definition of the disjunctive type notation ( +\begin_inset Formula $+$ +\end_inset -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:Exercise-type-notation-4" +). + The type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Option[A] +\end_layout \end_inset + has two disjoint cases, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Exercise-type-notation-4" -plural "false" -caps "false" -noprefix "false" +None +\end_layout \end_inset + and +\begin_inset listings +inline true +status open -\end_layout +\begin_layout Plain Layout -\begin_layout Standard -Write a Scala type signature for the fully parametric function: -\begin_inset Formula -\[ -\text{flatMap}^{A,B}:\bbnum 1+A\rightarrow\left(A\rightarrow\bbnum 1+B\right)\rightarrow\bbnum 1+B -\] +Some[A] +\end_layout \end_inset -and implement this function, preserving information as much as possible. +. + The case class +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +None \end_layout -\begin_layout Section -The logic of -\begin_inset Formula ${\cal CH}$ \end_inset --propositions -\begin_inset CommandInset label -LatexCommand label -name "sec:The-logic-of-ch-propositions" - + is a +\begin_inset Quotes eld \end_inset +\begin_inset Index idx +status open + +\begin_layout Plain Layout +unit type!named \end_layout -\begin_layout Standard -So far, we were able to convert statements such as -\begin_inset Quotes eld \end_inset +named +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Unit +\end_layout -\emph on -a fully parametric function can compute values of type -\emph default - -\begin_inset Formula $A$ \end_inset \begin_inset Quotes erd \end_inset - into logical propositions that we called -\begin_inset Formula ${\cal CH}$ + and is denoted by +\begin_inset Formula $\bbnum 1$ \end_inset --propositions. - The next step is to determine the proof rules suitable for rigorous reasoning - about -\begin_inset Formula ${\cal CH}$ -\end_inset +. + The case class +\begin_inset listings +inline true +status open --propositions. - Those rules will be rules of a formal logic. +\begin_layout Plain Layout + +Some[A] \end_layout -\begin_layout Standard -This section is an extended voyage into certain aspects of formal logic - that enable us to obtain proofs of -\begin_inset Formula ${\cal CH}$ \end_inset --propositions and to derive program code from those proofs. - While that theory (known as the -\begin_inset Index idx + contains a single value of type +\begin_inset Formula $A$ +\end_inset + +. + So, the type notation for +\begin_inset listings +inline true status open \begin_layout Plain Layout -Curry-Howard correspondence + +Option[A] \end_layout \end_inset -Curry-Howard correspondence) is important as a technique of reasoning about - types in functional programs, the material of Section -\begin_inset space ~ + is +\begin_inset Formula $\bbnum 1+A$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "sec:The-logic-of-ch-propositions" -plural "false" -caps "false" -noprefix "false" - +. + We will also sometimes write +\begin_inset Formula $\text{Opt}^{A}$ \end_inset - is used only for the discussions in Section -\begin_inset space ~ -\end_inset + to denote +\begin_inset listings +inline true +status open +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "sec:Discussion-curry-howard" -plural "false" -caps "false" -noprefix "false" +Option[A] +\end_layout \end_inset . - The rest of the book does not depend on the Curry-Howard correspondence. \end_layout -\begin_layout Subsection -Motivation and first examples +\begin_layout Subsubsection +Example \begin_inset CommandInset label LatexCommand label -name "subsec:ch-Motivation-and-first-examples" +name "subsec:Example-ch-notation-function-1-a" \end_inset -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-ch-notation-function-1-a" +plural "false" +caps "false" +noprefix "false" -\begin_layout Standard -Formal logic uses axioms and derivation rules for proving that certain formulas - are true or false. - We will use Greek letters ( -\begin_inset Formula $\alpha$ \end_inset -, -\begin_inset Formula $\beta$ -\end_inset -, etc.) to denote propositions in logic. \end_layout \begin_layout Standard -We will often need logical formulas that talk about properties of -\emph on -arbitrary -\emph default - propositions. - This is denoted by the -\series bold -universal quantifier -\series default - -\begin_inset Index idx +The Scala definition of the disjunctive type +\begin_inset listings +inline true status open \begin_layout Plain Layout -universal quantifier ( -\begin_inset Formula $\forall$ -\end_inset -) +UserAction \end_layout \end_inset - symbol ( -\begin_inset Formula $\forall$ -\end_inset - -), which means -\begin_inset Quotes eld -\end_inset - -for all -\begin_inset Quotes erd -\end_inset - -. - The universal quantifier will be usually located in front of the formula, - for example: -\begin_inset Formula -\[ -\forall(\alpha,\beta).\,\left(\alpha\Rightarrow\beta\right)\Rightarrow\alpha\Rightarrow\alpha\quad. -\] - -\end_inset - -The symbol -\begin_inset Formula $\Rightarrow$ -\end_inset - - denotes -\begin_inset Index idx +: +\begin_inset listings +inline false status open \begin_layout Plain Layout -implication (in logic) + +sealed trait UserAction \end_layout -\end_inset +\begin_layout Plain Layout +final case class SetName(first: String, last: String) extends UserAction +\end_layout -\begin_inset Index idx -status open +\begin_layout Plain Layout + +final case class SetEmail(email: String) extends UserAction +\end_layout \begin_layout Plain Layout -logical implication + +final case class SetUserId(id: Long) extends UserAction \end_layout \end_inset +is written in the type notation as: +\begin_inset Formula +\begin{equation} +\text{UserAction}\triangleq\text{String}\times\text{String}+\text{String}+\text{Long}\quad.\label{eq:ch-example-case-class-type-notation} +\end{equation} -\series bold -implication -\series default -: -\begin_inset Formula $\alpha\Rightarrow\beta$ \end_inset - means that -\emph on -if -\emph default - -\begin_inset Formula $\alpha$ +The type operation +\begin_inset Formula $\times$ \end_inset - is proved true -\emph on -then -\emph default - -\begin_inset Formula $\beta$ + groups stronger than +\begin_inset Formula $+$ \end_inset - will be proved true. -\end_layout - -\begin_layout Standard -Formulas whose propositions are all universally quantified correspond to - type signatures that are made entirely from type parameters. - For instance, the formula shown above corresponds to the following type - signature: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def f[A, B]: (A => B) => A => A -\end_layout - +, as in arithmetic. + To derive the type notation +\begin_inset space ~ \end_inset -The universal quantifier -\begin_inset Formula $\forall(\alpha,\beta)$ +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-example-case-class-type-notation" +plural "false" +caps "false" +noprefix "false" + \end_inset - corresponds to the fact that the function +), we first drop all names from case classes and get three nameless tuples + \begin_inset listings inline true status open \begin_layout Plain Layout -f +(String, String) \end_layout \end_inset - works with any choice of types +, \begin_inset listings inline true status open \begin_layout Plain Layout -A +(String) \end_layout \end_inset - and +, and \begin_inset listings inline true status open \begin_layout Plain Layout -B +(Long) \end_layout \end_inset . -\end_layout - -\begin_layout Standard -A simple example of a true logical formula is -\begin_inset Quotes eld + Each of these tuples is then converted into a product using the operator + +\begin_inset Formula $\times$ \end_inset -any proposition -\begin_inset Formula $\alpha$ +, and all products are +\begin_inset Quotes eld \end_inset - follows from itself +summed \begin_inset Quotes erd \end_inset -: -\begin_inset Formula -\begin{equation} -\forall\alpha.\,\alpha\Rightarrow\alpha\quad.\label{eq:ch-type-sig-1a} -\end{equation} - -\end_inset - -If the proposition -\begin_inset Formula $\alpha$ -\end_inset - - is a -\begin_inset Formula ${\cal CH}$ -\end_inset - --proposition, that is, if -\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ -\end_inset - - for some type -\begin_inset Formula $A$ -\end_inset - -, we obtain from Eq. -\begin_inset space ~ -\end_inset - -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-type-sig-1a" -plural "false" -caps "false" -noprefix "false" - + in the type notation using the operator +\begin_inset Formula $+$ \end_inset -) the formula: -\begin_inset Formula -\begin{equation} -\forall A.\,{\cal CH}(A)\Rightarrow{\cal CH}(A)\quad.\label{eq:ch-type-sig-1} -\end{equation} +. +\end_layout -\end_inset +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-ch-notation-function-2" -We expect true -\begin_inset Formula ${\cal CH}$ \end_inset --propositions to correspond to types that -\emph on -can -\emph default - be computed in a fully parametric function. - Let us see if this example fits our expectations. - We can rewrite Eq. -\begin_inset space ~ -\end_inset -( \begin_inset CommandInset ref LatexCommand ref -reference "eq:ch-type-sig-1" +reference "subsec:Example-ch-notation-function-2" plural "false" caps "false" noprefix "false" \end_inset -) as: -\begin_inset Formula -\begin{align*} - & \forall A.\,\gunderline{{\cal CH}(A)\Rightarrow{\cal CH}(A)}\\ -\text{rule for function types}:\quad & =\gunderline{\forall A}.\,{\cal CH}\left(A\rightarrow A\right)\\ -\text{rule for parameterized types}:\quad & ={\cal CH}\left(\forall A.\,A\rightarrow A\right)\quad. -\end{align*} - -\end_inset - -The last line shows a -\begin_inset Formula ${\cal CH}$ -\end_inset - --proposition that corresponds to the type -\begin_inset Formula $\forall A.\,A\rightarrow A$ -\end_inset - -. - Translating this type notation into a Scala type signature, we get: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout -def f[A]: A => A \end_layout -\end_inset - -This type signature can be implemented by an identity function: +\begin_layout Standard +The parameterized disjunctive type \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def f[A]: A => A = { x => x } +Either3 \end_layout \end_inset -This example shows a true -\begin_inset Formula ${\cal CH}$ -\end_inset - --proposition that corresponds to a type signature of a function + is a generalization of \begin_inset listings inline true status open \begin_layout Plain Layout -f +Either \end_layout \end_inset -, and we see that +: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -f +sealed trait Either3[A, B, C] \end_layout -\end_inset +\begin_layout Plain Layout - -\emph on -can -\emph default - be implemented in code. +final case class Left[A, B, C](x: A) extends Either3[A, B, C] \end_layout -\begin_layout Standard -While the correctness of the formula -\begin_inset Formula $\forall\alpha.\,\alpha\Rightarrow\alpha$ -\end_inset - - may be self-evident, the point of using formal logic is to have a set of - axioms and proof rules that allow us to verify -\emph on -all -\emph default - true formulas systematically, without guessing or testing. - What axioms and proof rules are suitable for proving -\begin_inset Formula ${\cal CH}$ -\end_inset +\begin_layout Plain Layout --propositions? +final case class Middle[A, B, C](x: B) extends Either3[A, B, C] \end_layout -\begin_layout Standard -A set of axioms and proof rules defines a -\series bold -formal logic -\series default - -\begin_inset Index idx -status open - \begin_layout Plain Layout -formal logic + +final case class Right[A, B, C](x: C) extends Either3[A, B, C] \end_layout \end_inset -. - Mathematicians have studied many different logics that are useful for solving - different problems. - We are now looking for a specific formal logic that gives correct answers - when reasoning about -\begin_inset Formula ${\cal CH}$ +This disjunctive type is written in the type notation as +\begin_inset Formula $\text{Either3}^{A,B,C}\triangleq A+B+C$ \end_inset --propositions. -\begin_inset Foot -status open +. +\end_layout -\begin_layout Plain Layout +\begin_layout Subsubsection +Example \begin_inset CommandInset label LatexCommand label -name "fn:Bornat-proof-book" - -\end_inset - - -\begin_inset Index idx -status open - -\begin_layout Plain Layout -Richard Bornat -\end_layout - -\end_inset - -For an overview and more details about that logic and the necessary proof - techniques, see the book by R. -\begin_inset space ~ -\end_inset - -Bornat, -\begin_inset Quotes eld -\end_inset +name "subsec:Example-ch-notation-function-3" -Proof and disproof in formal logic: an introduction for programmers -\begin_inset Quotes erd \end_inset -. - An early draft version of that book is available at -\family typewriter -\begin_inset CommandInset href -LatexCommand href -target "https://homepages.phonecoop.coop/randj/richard/books/ProofandDisproof.pdf" -literal "false" +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-ch-notation-function-3" +plural "false" +caps "false" +noprefix "false" \end_inset \end_layout -\end_inset +\begin_layout Standard +Define a Scala type constructor +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +F[A] \end_layout -\begin_layout Subsection -The rules of proof for -\begin_inset Formula ${\cal CH}$ \end_inset --propositions -\begin_inset CommandInset label -LatexCommand label -name "subsec:The-rules-of-proof" + corresponding to the type notation: +\begin_inset Formula +\[ +F^{A}\triangleq\bbnum 1+\text{Int}\times A\times A+\text{Int}\times\left(\text{Int}\rightarrow A\right)\quad. +\] \end_inset \end_layout -\begin_layout Standard -To derive the suitable logical axioms and proof rules systematically, let - us examine what could make a sequent with -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions true. +\begin_layout Subparagraph +Solution \end_layout \begin_layout Standard -A sequent -\begin_inset Formula ${\cal CH}(A)\vdash{\cal CH}(X)$ +The formula for +\begin_inset Formula $F^{A}$ \end_inset - is true when a value of type -\begin_inset Formula $X$ -\end_inset + defines a disjunctive type +\begin_inset listings +inline true +status open - can be computed by fully parametric code that may only use a given value - of type -\begin_inset Formula $A$ -\end_inset +\begin_layout Plain Layout + +F[A] +\end_layout -. - To describe all possible ways of computing a value of type -\begin_inset Formula $X$ \end_inset -, we need to enumerate all possible ways of -\emph on -writing code -\emph default - for a fully parametric function body. - The requirement of full parametricity means that we are not allowed to - use any specific types such as + with three parts. + To implement \begin_inset listings inline true status open \begin_layout Plain Layout -Int +F[A] \end_layout \end_inset - or + in Scala, we need to choose names for each of the disjoint parts, which + will become case classes. + For the purposes of this example, let us choose names \begin_inset listings inline true status open \begin_layout Plain Layout -String +F1 \end_layout \end_inset -, any concrete values such as +, \begin_inset listings inline true status open \begin_layout Plain Layout -123 +F2 \end_layout \end_inset - or +, and \begin_inset listings inline true status open \begin_layout Plain Layout -\begin_inset Quotes eld -\end_inset +F3 +\end_layout -hello -\begin_inset Quotes erd \end_inset +. + Each of these case classes needs to have the same type parameter +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +A \end_layout \end_inset -, or any library functions that work with specific (non-parametric) types. - We are only allowed to work with values of unknown types described by the - given type parameters. - However, we are permitted to use fully parametric types such as +. + So, we begin writing the code as: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -Either[A, B] +sealed trait F[A] +\end_layout + +\begin_layout Plain Layout + +final case class F1[A](...) extends F[A] +\end_layout + +\begin_layout Plain Layout + +final case class F2[A](...) extends F[A] +\end_layout + +\begin_layout Plain Layout + +final case class F3[A](...) extends F[A] \end_layout \end_inset - or +Each of these case classes represents one part of the disjunctive type: + \begin_inset listings inline true status open \begin_layout Plain Layout -Option[A] +F1 \end_layout \end_inset -. - -\end_layout - -\begin_layout Standard -In fact, we can enumerate all the allowed constructions that may be used - by fully parametric code implementing a -\begin_inset Formula ${\cal CH}$ + represents +\begin_inset Formula $\bbnum 1$ \end_inset --proposition. - There are -\emph on -eight -\emph default - code constructions -\begin_inset Index idx +, +\begin_inset listings +inline true status open \begin_layout Plain Layout -eight code constructions + +F2 \end_layout \end_inset + represents +\begin_inset Formula $\text{Int}\times A\times A$ +\end_inset -\begin_inset Index idx +, and +\begin_inset listings +inline true status open \begin_layout Plain Layout -fully parametric!code constructions + +F3 \end_layout \end_inset - as illustrated by this code: + represents +\begin_inset Formula $\text{Int}\times\left(\text{Int}\rightarrow A\right)$ +\end_inset + +. + It remains to choose names and define the case classes: \begin_inset listings inline false status open \begin_layout Plain Layout -def f[A, B, ...](a: A, b: B): X = { // Any given type signature. +sealed trait F[A] \end_layout \begin_layout Plain Layout - val x1: Unit = () // 1) Use a value of type Unit. +final case class F1[A]() extends F[A] // Named unit + type. \end_layout \begin_layout Plain Layout - val x2: A = a // 2) Use a given argument value. +final case class F2[A](n: Int, x1: A, x2: A) extends F[A] \end_layout \begin_layout Plain Layout - val x3 = { x: A => b } // 3) Create a function. +final case class F3[A](n: Int, f: Int => A) extends F[A] \end_layout -\begin_layout Plain Layout +\end_inset - val x4: D = x3(x2) // 4) Use a function. -\end_layout +The names +\begin_inset listings +inline true +status open \begin_layout Plain Layout - val x5: (A, B) = (a, b) // 5) Create a tuple. +n \end_layout -\begin_layout Plain Layout +\end_inset - val x6: B = x5._2 // 6) Use a tuple. -\end_layout +, +\begin_inset listings +inline true +status open \begin_layout Plain Layout - val x7: Either[A, B] = Right(x6) // 7) Create values of a disjunctive - type. +x1 \end_layout -\begin_layout Plain Layout +\end_inset - val x8 = x7 match { ... - } // 8) Use values of a disjunctive type. -\end_layout +, +\begin_inset listings +inline true +status open \begin_layout Plain Layout -} // 9) Call f() itself recursively. - Not included here because recursion is not supported by CH-propositions. +x2 \end_layout \end_inset -The proposition -\begin_inset Formula ${\cal CH}(X)$ -\end_inset - - is true if we can create a sequence of computed values such as +, and \begin_inset listings inline true status open \begin_layout Plain Layout -x1 +f \end_layout \end_inset -, + are chosen arbitrarily. +\end_layout + +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-ch-notation-function-4" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-ch-notation-function-4" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Write the type signature of the following function in the type notation: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -x2 +def fmap[A, B](f: A => B): Option[A] => Option[B] \end_layout \end_inset -, ..., + +\end_layout + +\begin_layout Subparagraph +Solution +\end_layout + +\begin_layout Standard +This is a curried function, so we first rewrite the type signature as: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -xN +def fmap[A, B]: (A => B) => Option[A] => Option[B] \end_layout \end_inset -, each using one of these eight code constructs, with +The type notation for \begin_inset listings inline true status open \begin_layout Plain Layout -xN +Option[A] \end_layout \end_inset - having type -\begin_inset Formula $X$ + is +\begin_inset Formula $\bbnum 1+A$ \end_inset . - -\end_layout + Now we can write the type signature of +\begin_inset listings +inline true +status open -\begin_layout Standard -So, each of the eight code constructs will give a proof rule in the logic. +\begin_layout Plain Layout + +fmap \end_layout -\begin_layout Standard -It is important that there are only a finite number of allowed code construction -s. - This defines rigorously the concept of -\begin_inset Quotes eld \end_inset -fully parametric code -\begin_inset Quotes erd -\end_inset + as: +\begin_inset Formula +\begin{align*} + & \text{fmap}^{A,B}:\left(A\rightarrow B\right)\rightarrow\bbnum 1+A\rightarrow\bbnum 1+B\quad,\\ +\text{or equivalently}:\quad & \text{fmap}:\forall(A,B).\,\left(A\rightarrow B\right)\rightarrow\bbnum 1+A\rightarrow\bbnum 1+B\quad. +\end{align*} +\end_inset -\begin_inset Index idx -status open +We do not put parentheses around +\begin_inset Formula $\bbnum 1+A$ +\end_inset -\begin_layout Plain Layout -fully parametric!code|textit -\end_layout + and +\begin_inset Formula $\bbnum 1+B$ +\end_inset + because the function arrow ( +\begin_inset Formula $\rightarrow$ \end_inset - and allows us to -\emph on -prove -\emph default - -\begin_inset Formula ${\cal CH}$ +) groups weaker than the other type operations. + But parentheses around +\begin_inset Formula $\left(A\rightarrow B\right)$ \end_inset --propositions. + are required. \end_layout \begin_layout Standard -Reasoning about proof rules is easier with a compact notation. - To obtain that notation, we first need to translate the eight code constructs - into the notation of sequents. - A proof of a sequent, e.g., -\begin_inset Formula $\mathcal{CH}(A)\vdash\mathcal{CH}(X)$ -\end_inset - -, will consist of applying some of those proof rules. - We will then combine the code constructs corresponding to each rule and - obtain some code that computes a value of type -\begin_inset Formula $X$ +We will usually prefer to write type parameters in superscripts rather than + under type quantifiers. + For example, we will prefer to write the type signature of an identity + function as +\begin_inset Formula $\text{id}^{A}:A\rightarrow A$ \end_inset - using an argument of type -\begin_inset Formula $A$ + rather than as +\begin_inset Formula $\text{id}:\forall A.\,A\rightarrow A$ \end_inset . - \end_layout -\begin_layout Standard -Conversely, any fully parametric (and non-recursive) code computing a value - of type -\begin_inset Formula $X$ -\end_inset - - must be a combination of some of the eight code constructs +\begin_layout Subsection +Exercises: Type notation \begin_inset Index idx status open \begin_layout Plain Layout -eight code constructions +exercises \end_layout \end_inset -. - That code combination can be translated into a combination of logic rules, - which will produce a proof of the proposition -\begin_inset Formula ${\cal CH}(X)$ -\end_inset -. \end_layout -\begin_layout Standard -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 Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-type-notation-1" -\begin_layout Standard -In the following text, we will need to write -\begin_inset Formula ${\cal CH}$ \end_inset --propositions such as Eq. -\begin_inset space ~ -\end_inset -( \begin_inset CommandInset ref LatexCommand ref -reference "eq:ch-CH-proposition-def" +reference "subsec:Exercise-type-notation-1" plural "false" caps "false" noprefix "false" \end_inset -) as sequents such as Eq. -\begin_inset space ~ -\end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-example-sequent" -plural "false" -caps "false" -noprefix "false" +\end_layout -\end_inset +\begin_layout Standard +Define a Scala disjunctive type +\begin_inset listings +inline true +status open -). - As we have seen, -\begin_inset Formula ${\cal CH}$ -\end_inset +\begin_layout Plain Layout --propositions involving complicated type expressions can be always rewritten - via -\begin_inset Formula ${\cal CH}$ -\end_inset +Q[T, A] +\end_layout --propositions for individual type parameters ( -\begin_inset Formula ${\cal CH}(A)$ \end_inset -, -\begin_inset Formula ${\cal CH}(B)$ -\end_inset + corresponding to this type notation: +\begin_inset Formula +\[ +Q^{T,A}\triangleq\bbnum 1+T\times A+\text{Int}\times(T\rightarrow T)+\text{String}\times A\quad. +\] -, etc.). - So, we will only need sequents involving such -\begin_inset Formula ${\cal CH}$ \end_inset --propositions. - For brevity, we denote -\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ -\end_inset -, -\begin_inset Formula $\beta\triangleq{\cal CH}(B)$ -\end_inset +\end_layout -, etc. - We will use the letter -\begin_inset Formula $\Gamma$ -\end_inset +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-type-notation-2" - to stand for a set of premises and write a shorter formula -\begin_inset Formula $\Gamma\vdash\alpha$ \end_inset - instead of the sequent -\begin_inset space ~ -\end_inset -( \begin_inset CommandInset ref LatexCommand ref -reference "eq:ch-example-sequent" +reference "subsec:Exercise-type-notation-2" plural "false" caps "false" noprefix "false" \end_inset -). -\end_layout - -\begin_layout Standard -With these notations, we list the rules for proving -\begin_inset Formula ${\cal CH}$ -\end_inset - --propositions and the corresponding code: -\end_layout -\begin_layout Paragraph -1) Use the -\family typewriter -Unit -\family default - value \end_layout \begin_layout Standard -At any place in the code, we may write the expression +Convert the type \begin_inset listings inline true status open \begin_layout Plain Layout -() +Either[(A, Int), Either[(A, Char), (A, Float)]] \end_layout \end_inset - of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Unit + from Scala syntax to the type notation. + \end_layout -\end_inset - -. - This expression corresponds to a proof of the proposition -\begin_inset Formula ${\cal CH}(\bbnum 1)$ -\end_inset - - with any set -\begin_inset Formula $\Gamma$ -\end_inset +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-type-notation-3" - of premises (even with an empty set of premises). - So, the sequent -\begin_inset Formula $\Gamma\vdash{\cal CH}(\bbnum 1)$ \end_inset - is always true. - The code corresponding to the proof of this sequent is an expression that - creates a value of the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -Unit -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-type-notation-3" +plural "false" +caps "false" +noprefix "false" \end_inset - type: -\begin_inset Formula -\[ -\text{Proof}\,\big(\Gamma\vdash{\cal CH}(\bbnum 1)\big)=1\quad, -\] - -\end_inset -where we denoted by -\begin_inset Formula $1$ -\end_inset +\end_layout - the value +\begin_layout Standard +Define a Scala type \begin_inset listings inline true status open \begin_layout Plain Layout -() +Opt2[A, B] \end_layout +\end_inset + + written in the type notation as +\begin_inset Formula $\bbnum 1+A+B$ \end_inset . \end_layout -\begin_layout Standard -In formal logic, a sequent that is always true, such as our -\begin_inset Formula $\Gamma\vdash{\cal CH}(\bbnum 1)$ -\end_inset +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-type-notation-4" -, is called an -\series bold -axiom -\series default +\end_inset -\begin_inset Index idx -status open -\begin_layout Plain Layout -logical axiom -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-type-notation-4" +plural "false" +caps "false" +noprefix "false" \end_inset - and is written in the following notation: + +\end_layout + +\begin_layout Standard +Write a Scala type signature for this fully parametric function: \begin_inset Formula \[ -\frac{}{\Gamma\vdash{\cal CH}(\bbnum 1)}\quad(\text{create unit})\quad\quad. +f^{A,B,C}:\bbnum 1+A+B+C\rightarrow\left(A\rightarrow\bbnum 1+B\right)\rightarrow\bbnum 1+B+C\quad. \] \end_inset -The -\begin_inset Quotes eld -\end_inset - -fraction with a label -\begin_inset Quotes erd -\end_inset - - represents a proof rule. - The denominator of the fraction is the target sequent that we need to prove. - The numerator of the fraction can have zero or more other sequents that - need to be proved before the target sequent can be proved. - In this case, the set of previous sequents is empty: the target sequent - is an axiom and so requires no previous sequents for its proof. - The label -\begin_inset Quotes eld -\end_inset - +Implement this function, preserving information as much as possible. +\end_layout -\begin_inset Formula $\text{create unit}$ +\begin_layout Section +The logic of +\begin_inset Formula ${\cal CH}$ \end_inset +-propositions +\begin_inset CommandInset label +LatexCommand label +name "sec:The-logic-of-ch-propositions" -\begin_inset Quotes erd \end_inset - is an arbitrary name used to refer to the rule. -\end_layout -\begin_layout Paragraph -2) Use a given value \end_layout \begin_layout Standard -At any place within the code of a fully parametric function, we may use - one of the function's arguments, say -\begin_inset Formula $x^{:A}$ +So far, we were able to convert statements such as +\begin_inset Quotes eld \end_inset -. - If some argument has type -\begin_inset Formula $A$ -\end_inset -, it means that we already have a value of type +\emph on +a fully parametric function can compute values of type +\emph default + \begin_inset Formula $A$ \end_inset -. - So, the corresponding proposition, -\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ -\end_inset -, belongs to the set of premises of the sequent we are trying to prove. - To indicate this, we write the set of premises as -\begin_inset Quotes eld +\begin_inset Quotes erd \end_inset + into logical propositions that we called +\begin_inset Formula ${\cal CH}$ +\end_inset -\begin_inset Formula $\Gamma,\alpha$ +-propositions. + The next step is to determine the proof rules suitable for rigorous reasoning + about +\begin_inset Formula ${\cal CH}$ \end_inset +-propositions. + Those rules will be rules of a formal logic. +\end_layout -\begin_inset Quotes erd +\begin_layout Standard +This section is an extended voyage into certain aspects of formal logic + that are needed for obtaining proofs of +\begin_inset Formula ${\cal CH}$ \end_inset -. - The code construct -\begin_inset listings -inline true +-propositions and deriving program code from those proofs. + While that theory (known as the +\begin_inset Index idx status open \begin_layout Plain Layout - -x: A +Curry-Howard correspondence \end_layout \end_inset - computes a value of type -\begin_inset Formula $A$ +Curry-Howard correspondence) is important as a technique of reasoning about + types in functional programs, the material of Section +\begin_inset space ~ \end_inset -, i.e., shows that -\begin_inset Formula $\alpha$ + +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:The-logic-of-ch-propositions" +plural "false" +caps "false" +noprefix "false" + \end_inset - is true with premises -\begin_inset Formula $\Gamma,\alpha$ + is used only for the discussions in Section +\begin_inset space ~ \end_inset -. - This is expressed by the sequent -\begin_inset Formula $\Gamma,\alpha\vdash\alpha$ + +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Discussion-curry-howard" +plural "false" +caps "false" +noprefix "false" + \end_inset . - The proof code for this sequent is an expression that just returns the - given value (which we denoted by -\begin_inset Formula $x^{:A}$ + An exception is Section +\begin_inset space ~ \end_inset -): -\begin_inset Formula -\[ -\text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }x^{:A}}=x\quad. -\] -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Short-notation-for-eight-code-constructions" +plural "false" +caps "false" +noprefix "false" -This sequent is an axiom since its proof requires no previous sequents; - a value of type -\begin_inset Formula $A$ \end_inset - is already given in the premises. - We denote this axiom by: -\begin_inset Formula -\[ -\frac{~}{\Gamma,\alpha\vdash\alpha}\quad(\text{use value})\quad\quad. -\] + that introduces the short notation for fully parametric code. + That notation will be further developed and used throughout the book. + Other than that, the rest of the book does not depend on the Curry-Howard + correspondence. +\end_layout -\end_inset +\begin_layout Subsection +Motivation and first examples +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Motivation-and-first-examples" +\end_inset -\end_layout -\begin_layout Paragraph -3) Create a function \end_layout \begin_layout Standard -At any place in the code, we may compute a nameless function of type, say, - -\begin_inset Formula $A\rightarrow B$ -\end_inset - -, by writing -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -(x:A) => expr -\end_layout - -\end_inset - - as long as a value -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -expr -\end_layout - +Formal logic uses axioms and derivation rules for proving that certain formulas + are true or false. + We will use Greek letters ( +\begin_inset Formula $\alpha$ \end_inset - of type -\begin_inset Formula $B$ +, +\begin_inset Formula $\beta$ \end_inset - can be computed in the inner scope of the function. - The code for -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -expr +, etc.) to denote propositions. \end_layout -\end_inset +\begin_layout Standard +We will often need logical formulas that talk about properties of +\emph on +arbitrary +\emph default + propositions. + This is denoted by the +\series bold +universal quantifier +\series default - is also required to be fully parametric; it may use -\begin_inset listings -inline true +\begin_inset Index idx status open \begin_layout Plain Layout +universal quantifier ( +\begin_inset Formula $\forall$ +\end_inset -x +) \end_layout \end_inset - and/or other values visible in that scope. - So, we now need to answer the question of whether a fully parametric function - can compute a value of type -\begin_inset Formula $B$ -\end_inset - -, given an argument of type -\begin_inset Formula $A$ + symbol ( +\begin_inset Formula $\forall$ \end_inset - as well as all other arguments previously given to the parent function. - This question is answered by a sequent whose premises contain one more - proposition, -\begin_inset Formula ${\cal CH}(A)$ +), which means +\begin_inset Quotes eld \end_inset -, in addition to all previously available premises. - Translating this into the language of -\begin_inset Formula ${\cal CH}$ +for all +\begin_inset Quotes erd \end_inset --propositions, we find that we will prove the sequent: +. + The universal quantifier will be usually located in front of the formula, + e.g.: \begin_inset Formula \[ -\Gamma\vdash{\cal CH}(A\rightarrow B)\quad=\quad\Gamma\vdash{\cal CH}(A)\Rightarrow{\cal CH}(B)\quad=\quad\Gamma\vdash\alpha\Rightarrow\beta +\forall(\alpha,\beta).\,\left(\alpha\Rightarrow\beta\right)\Rightarrow\alpha\Rightarrow\alpha\quad. \] \end_inset -if we can prove the sequent -\begin_inset Formula $\Gamma,{\cal CH}(A)\vdash{\cal CH}(B)=\Gamma,\alpha\vdash\beta$ +The symbol +\begin_inset Formula $\Rightarrow$ \end_inset -. - In the notation of formal logic, this is a -\series bold -derivation rule -\series default - + denotes \begin_inset Index idx status open \begin_layout Plain Layout -derivation rule +implication (in logic) \end_layout \end_inset - (rather than an axiom) and is written as: -\begin_inset Formula -\[ -\frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function})\quad\quad. -\] - -\end_inset - -The -\series bold -turnstile -\series default \begin_inset Index idx status open \begin_layout Plain Layout -0@ -\begin_inset Formula $\vdash$ -\end_inset - - (turnstile) symbol +logical implication \end_layout \end_inset -\begin_inset Index idx -status open - -\begin_layout Plain Layout -turnstile ( -\begin_inset Formula $\vdash$ -\end_inset - -) symbol -\end_layout - -\end_inset - - symbol ( -\begin_inset Formula $\vdash$ +\series bold +implication +\series default +: +\begin_inset Formula $\alpha\Rightarrow\beta$ \end_inset -) groups weaker than other operators. - So, we can write sequents such as -\begin_inset Formula $(\Gamma,\alpha)\vdash(\beta\Rightarrow\gamma)$ + means that +\emph on +if +\emph default + +\begin_inset Formula $\alpha$ \end_inset - with fewer parentheses: -\begin_inset Formula $\Gamma,\alpha\vdash\beta\Rightarrow\gamma$ + is proved true +\emph on +then +\emph default + +\begin_inset Formula $\beta$ \end_inset -. + will be proved true. \end_layout \begin_layout Standard -What code corresponds to the -\begin_inset Quotes eld -\end_inset - - -\begin_inset Formula $\text{create function}$ -\end_inset - - -\begin_inset Quotes erd -\end_inset - - rule? The proof of -\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ -\end_inset - - depends on a proof of another sequent. - So, the corresponding code must be a -\emph on -function -\emph default - that takes a proof of the previous sequent as an argument and returns a - proof of the new sequent. - We call that function a -\begin_inset Index idx +Formulas whose propositions are all universally quantified correspond to + type signatures that are made entirely from type parameters. + For instance, the formula shown above corresponds to the following type + signature: +\begin_inset listings +inline false 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 +def f[A, B]: (A => B) => A => A \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. - So, a proof of the sequent -\begin_inset Formula $\Gamma,\alpha\vdash\beta$ +The universal quantifier +\begin_inset Formula $\forall(\alpha,\beta)$ \end_inset - is an expression + corresponds to the fact that the function \begin_inset listings inline true status open \begin_layout Plain Layout -exprB +f \end_layout \end_inset - of type -\begin_inset Formula $B$ -\end_inset - - that may use a given value of type -\begin_inset Formula $A$ -\end_inset - - as well as any other arguments given previously. - Then we can write the proof code for the sequent -\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ -\end_inset - - as the nameless function + works with any choice of types \begin_inset listings inline true status open \begin_layout Plain Layout -(x: A) => exprB +A \end_layout \end_inset -. - This function has type -\begin_inset Formula $A\rightarrow B$ -\end_inset - - and requires us to already have a suitable expression + and \begin_inset listings inline true status open \begin_layout Plain Layout -exprB +B \end_layout \end_inset . - This exactly corresponds to the proof rule +\end_layout + +\begin_layout Standard +A simple example of a true logical formula is \begin_inset Quotes eld \end_inset - -\begin_inset Formula $\text{create function}$ +if +\begin_inset Formula $\alpha$ \end_inset + is true then +\begin_inset Formula $\alpha$ +\end_inset + is true \begin_inset Quotes erd \end_inset -. - That rule's proof transformer is: -\begin_inset Formula -\[ -\text{Proof}\,\big(\Gamma\vdash\alpha\Rightarrow\beta\big)=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,\alpha\vdash\beta\big)_{\text{given }x^{:A}}\quad. -\] - + (any proposition +\begin_inset Formula $\alpha$ \end_inset -Here, the subscript -\begin_inset Quotes eld -\end_inset + follows from itself): +\begin_inset Formula +\begin{equation} +\forall\alpha.\,\alpha\Rightarrow\alpha\quad.\label{eq:ch-type-sig-1a} +\end{equation} -given -\begin_inset Formula $x^{:A}$ \end_inset - -\begin_inset Quotes erd +If the proposition +\begin_inset Formula $\alpha$ \end_inset - indicates that the value -\begin_inset Formula $x^{:A}$ + is a +\begin_inset Formula ${\cal CH}$ \end_inset - must come from the premises. - (In this case, the set of premises is -\begin_inset Formula $\Gamma,\alpha$ +-proposition, that is, if +\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ \end_inset - and so the proposition -\begin_inset Formula $\alpha$ + for some type +\begin_inset Formula $A$ \end_inset - must have been already proved. - The proof of -\begin_inset Formula $\alpha$ +, we obtain from Eq. +\begin_inset space ~ \end_inset - will give a value -\begin_inset Formula $x^{:A}$ +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-type-sig-1a" +plural "false" +caps "false" +noprefix "false" + \end_inset -.) -\end_layout +) the formula: +\begin_inset Formula +\begin{equation} +\forall A.\,{\cal CH}(A)\Rightarrow{\cal CH}(A)\quad.\label{eq:ch-type-sig-1} +\end{equation} -\begin_layout Paragraph -4) Use a function -\end_layout +\end_inset -\begin_layout Standard -At any place in the code, we may apply an already defined function of type - -\begin_inset Formula $A\rightarrow B$ +We expect true +\begin_inset Formula ${\cal CH}$ \end_inset - to an already computed value of type -\begin_inset Formula $A$ +-propositions to correspond to types that +\emph on +can +\emph default + be computed in a fully parametric function. + Let us see if this example fits our expectations. + We can rewrite Eq. +\begin_inset space ~ \end_inset -. - The result will be a value of type -\begin_inset Formula $B$ +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-type-sig-1" +plural "false" +caps "false" +noprefix "false" + \end_inset -. - This corresponds to assuming -\begin_inset Formula ${\cal CH}(A\rightarrow B)$ +) as: +\begin_inset Formula +\begin{align*} + & \forall A.\,\gunderline{{\cal CH}(A)\Rightarrow{\cal CH}(A)}\\ +\text{rule for function types}:\quad & =\gunderline{\forall A}.\,{\cal CH}\left(A\rightarrow A\right)\\ +\text{rule for parameterized types}:\quad & ={\cal CH}\left(\forall A.\,A\rightarrow A\right)\quad. +\end{align*} + \end_inset - and -\begin_inset Formula ${\cal CH}(A)$ +The last line shows a +\begin_inset Formula ${\cal CH}$ \end_inset -, and then deriving -\begin_inset Formula ${\cal CH}(B)$ +-proposition that corresponds to the type +\begin_inset Formula $\forall A.\,A\rightarrow A$ \end_inset . - The notation for this proof rule is: -\begin_inset Formula -\[ -\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\alpha\Rightarrow\beta}{\Gamma\vdash\beta}\quad(\text{use function})\quad\quad. -\] + Translating this type notation into a Scala type signature, we get: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def f[A]: A => A +\end_layout \end_inset -The code corresponding to this proof rule takes previously computed values - +This type signature can be implemented by an identity function: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -x:A +def f[A]: A => A = { x => x } \end_layout \end_inset - and +This example shows a true +\begin_inset Formula ${\cal CH}$ +\end_inset + +-proposition that corresponds to a type signature of a function \begin_inset listings inline true status open \begin_layout Plain Layout -f:A => B +f \end_layout \end_inset -, and writes the expression +, and we see that \begin_inset listings inline true status open \begin_layout Plain Layout -f(x) +f \end_layout \end_inset -. - This can be written as a function application: -\begin_inset Formula -\[ -\text{Proof}\,(\Gamma\vdash\beta)=\text{Proof}\left(\Gamma\vdash\alpha\Rightarrow\beta\right)(\text{Proof}\,(\Gamma\vdash\alpha))\quad. -\] + +\emph on +can +\emph default + be implemented in code. +\end_layout +\begin_layout Standard +While the correctness of the formula +\begin_inset Formula $\forall\alpha.\,\alpha\Rightarrow\alpha$ \end_inset + may be self-evident, the point of using formal logic is to have a set of + axioms and proof rules that allow us to verify +\emph on +all +\emph default + true formulas systematically, without guessing or testing. + What axioms and proof rules are suitable for proving +\begin_inset Formula ${\cal CH}$ +\end_inset -\end_layout - -\begin_layout Paragraph -5) Create a tuple +-propositions? \end_layout \begin_layout Standard -If we have already computed some values -\begin_inset listings -inline true +A set of axioms and proof rules defines a +\series bold +formal logic +\series default + +\begin_inset Index idx status open \begin_layout Plain Layout - -a: A +formal logic \end_layout \end_inset - and -\begin_inset listings -inline true +. + Mathematicians have studied many different logics that are useful for solving + different problems. + We are now looking for a specific formal logic that gives correct answers + when reasoning about +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions. +\begin_inset Foot status open \begin_layout Plain Layout - -b: B -\end_layout +\begin_inset CommandInset label +LatexCommand label +name "fn:Bornat-proof-book" \end_inset -, we may write the expression -\begin_inset listings -inline true + +\begin_inset Index idx status open \begin_layout Plain Layout - -(a, b) +Richard Bornat \end_layout \end_inset - and so compute a value of the tuple type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout +For an overview and more details about that logic and the necessary proof + techniques, see the book by R. +\begin_inset space ~ +\end_inset -(A, B) -\end_layout +Bornat, +\begin_inset Quotes eld +\end_inset +Proof and disproof in formal logic: an introduction for programmers +\begin_inset Quotes erd \end_inset . - The proof rule is: -\begin_inset Formula -\[ -\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple})\quad\quad. -\] + An early draft version of that book is available at +\family typewriter -\end_inset +\begin_inset CommandInset href +LatexCommand href +target "https://homepages.phonecoop.coop/randj/richard/books/ProofandDisproof.pdf" +literal "false" -Writing -\begin_inset Formula $a\times b$ \end_inset - to mean the pair -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -(a, b) \end_layout \end_inset -, we can write the corresponding code expression as: -\begin_inset Formula -\[ -\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)=\text{Proof}\left(\Gamma\vdash\alpha\right)\times\text{Proof}\left(\Gamma\vdash\beta\right)\quad. -\] + +\end_layout + +\begin_layout Subsection +Short notation for fully parametric code +\begin_inset CommandInset label +LatexCommand label +name "subsec:Short-notation-for-eight-code-constructions" \end_inset @@ -7186,1097 +6617,3514 @@ status open \end_layout \begin_layout Standard -This rule describes creating a tuple of -\begin_inset Formula $2$ +To derive the suitable logical axioms and proof rules systematically, we + need to examine what could make a sequent with +\begin_inset Formula ${\cal CH}$ \end_inset - values. - A larger tuple, such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -(w, x, y, z) +-propositions true. \end_layout +\begin_layout Standard +A sequent +\begin_inset Formula ${\cal CH}(A)\vdash{\cal CH}(X)$ \end_inset -, can be expressed via nested pairs, e.g., as + is true when a value of type +\begin_inset Formula $X$ +\end_inset + + can be computed by fully parametric code that may only use a given value + of type +\begin_inset Formula $A$ +\end_inset + +. + To describe all possible ways of computing a value of type +\begin_inset Formula $X$ +\end_inset + +, we need to enumerate all possible ways of +\emph on +writing code +\emph default + in a fully parametric function. + The requirement of full parametricity means that we are not allowed to + use any specific types such as \begin_inset listings inline true status open \begin_layout Plain Layout -(w, (x, (y, z))) +Int \end_layout \end_inset -. - So, it suffices to have a derivation rule for creating pairs. - That rule allows us to express the rules for creating all larger tuples, - and so we do not need to define separate rules for, say, -\begin_inset Formula $\Gamma\vdash\alpha\wedge\beta\wedge\gamma$ -\end_inset - -. -\end_layout - -\begin_layout Paragraph -6) Use a tuple -\end_layout - -\begin_layout Standard -If we already have a value + or \begin_inset listings inline true status open \begin_layout Plain Layout -t:(A,B) +String \end_layout \end_inset - of a tuple type -\begin_inset Formula $A\times B$ -\end_inset - -, we can extract one of the parts of the tuple and obtain a value of type - +, any concrete values such as \begin_inset listings inline true status open \begin_layout Plain Layout -A +123 \end_layout \end_inset - or a value of type + or \begin_inset listings inline true status open \begin_layout Plain Layout -B +\begin_inset Quotes eld +\end_inset + +hello +\begin_inset Quotes erd +\end_inset + + \end_layout \end_inset -. - The code is +, or any library functions that work with specific (non-parametric) types. + We are only allowed to work with values of unknown types described by the + given type parameters. + However, we are permitted to use fully parametric types such as \begin_inset listings inline true status open \begin_layout Plain Layout -t._1 +Either[A, B] \end_layout \end_inset - and + or \begin_inset listings inline true status open \begin_layout Plain Layout -t._2 +Option[A] \end_layout \end_inset - 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. -\] +. + +\end_layout -\end_inset +\begin_layout Standard +In fact, we can enumerate all the allowed constructions that may be used + by fully parametric code. + There are +\emph on +eight +\emph default + code constructions +\begin_inset Index idx +status open -The proof code can be written as: -\begin_inset Formula -\[ -\text{Proof}\left(\Gamma\vdash\alpha\right)=\pi_{1}\left(\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)\right)\quad,\quad\text{Proof}\left(\Gamma\vdash\beta\right)=\pi_{2}\left(\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)\right)\quad, -\] +\begin_layout Plain Layout +eight code constructions +\end_layout \end_inset -where we introduced the notation -\begin_inset Formula $\pi_{1}$ -\end_inset - and -\begin_inset Formula $\pi_{2}$ +\begin_inset Index idx +status open + +\begin_layout Plain Layout +fully parametric!code constructions +\end_layout + \end_inset - to mean the Scala code + as illustrated here: \begin_inset listings -inline true +lstparams "mathescape=true" +inline false status open \begin_layout Plain Layout -_._1 +def f[A, B, ...](a: A, b: B): X = { // Any given type signature. \end_layout -\end_inset +\begin_layout Plain Layout - and -\begin_inset listings -inline true -status open + val x1: Unit = () // 1) Use a value of type Unit. +\end_layout \begin_layout Plain Layout -_._2 + val x2: A = a // 2) Use a given argument. \end_layout -\end_inset +\begin_layout Plain Layout -. + val x3 = { (x: A) => b } // 3) Create a function. \end_layout -\begin_layout Standard -Since all tuples can be expressed through pairs, it is sufficient to have - proof rules for pairs. +\begin_layout Plain Layout + + val x4: D = x3(x2) // 4) Use a function. \end_layout -\begin_layout Paragraph -7) Create a disjunctive value +\begin_layout Plain Layout + + val x5: (A, B) = (a, b) // 5) Create a tuple. \end_layout -\begin_layout Standard -The type -\begin_inset listings -inline true -status open +\begin_layout Plain Layout + + val x6: B = x5._2 // 6) Use a tuple. +\end_layout \begin_layout Plain Layout -Either[A, B] + val x7: Either[A, B] = Right(x6) // 7) Create values of a disjunctive + type. +\end_layout + +\begin_layout Plain Layout + + val x8 = x7 match { ... + } // 8) Use values of a disjunctive type. +\end_layout + +\begin_layout Plain Layout + +} // 9) Call f itself recursively. + Not included here because recursion is not supported by $ +\backslash +color{dkgreen} +\backslash +cal{CH}$-propositions. \end_layout \end_inset - corresponding to the disjunction -\begin_inset Formula $\alpha\vee\beta$ +The proposition +\begin_inset Formula ${\cal CH}(X)$ \end_inset - can be used to define any other disjunctive type; e.g., a disjunctive type - with three parts can be expressed as + is true if we can create a sequence of computed values such as \begin_inset listings inline true status open \begin_layout Plain Layout -Either[A, Either[B, C]] +x1 \end_layout \end_inset -. - So, it suffices to have proof rules for a disjunction of -\emph on -two -\emph default - propositions. -\end_layout - -\begin_layout Standard -There are two ways of creating a value of the type +, \begin_inset listings inline true status open \begin_layout Plain Layout -Either[A, B] +x2 \end_layout \end_inset -: the code expressions are +, ..., \begin_inset listings inline true status open \begin_layout Plain Layout -Left(x: A) +xN \end_layout \end_inset - and +, each using one of these eight code constructs, with \begin_inset listings inline true status open \begin_layout Plain Layout -Right(y: B) +xN \end_layout \end_inset -. - The values -\begin_inset listings -inline true -status open + having type +\begin_inset Formula $X$ +\end_inset -\begin_layout Plain Layout +. + +\end_layout -x: A +\begin_layout Standard +So, each of the eight code constructs will give a proof rule in the logic. \end_layout +\begin_layout Standard +It is important that there are only a finite number of allowed code construction +s. + This defines rigorously the concept of +\begin_inset Quotes eld \end_inset - or -\begin_inset listings -inline true +fully parametric code +\begin_inset Quotes erd +\end_inset + + +\begin_inset Index idx status open \begin_layout Plain Layout +fully parametric!code|textit +\end_layout -y: B +\end_inset + + and allows us to +\emph on +prove +\emph default + +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions. \end_layout +\begin_layout Standard +The ninth code construction (the recursive call) is also a valid construction + in fully parametric code. + We will be using that construction in later chapters of this book. + However, that construction is not supported by propositional logic, so + we cannot map recursive code to a proof rule for +\begin_inset Formula ${\cal CH}$ \end_inset - must have been computed previously (and correspond to previously proved - sequents). - So, the sequent proof rules are: -\begin_inset Formula -\[ -\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. -\] +-propositions. +\end_layout + +\begin_layout Standard +When writing code and reasoning symbolically about code, the syntax of Scala + is too verbose. + We have started introducing a shorter code notation in Chapter +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "chap:Higher-order-functions" +plural "false" +caps "false" +noprefix "false" \end_inset -The corresponding proof transformers can be written using the case class - names +, and we will develop it in more detail in this chapter. + This code notation will be used systematically in later chapters of this + book. + +\end_layout + +\begin_layout Standard +In the code notation, we denote values of the \begin_inset listings inline true status open \begin_layout Plain Layout -Left +Unit \end_layout \end_inset - and -\begin_inset listings -inline true -status open + type by the symbol +\begin_inset Formula $1$ +\end_inset -\begin_layout Plain Layout +. + There will be no confusion with the integer value +\begin_inset Formula $1$ +\end_inset -Right + because the latter is rarely used in symbolic reasoning. \end_layout +\begin_layout Standard +We denote functions by expressions of the form +\begin_inset Formula $x^{:A}\rightarrow f(x)$ \end_inset - as: -\begin_inset Formula -\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. -\end{align*} +. + We will use two equivalent notations for applying a function to an argument: + +\begin_inset Formula $f(x)$ +\end_inset + and +\begin_inset Formula $x\triangleright f$ \end_inset + (the +\begin_inset Index idx +status open +\begin_layout Plain Layout +pipe notation \end_layout -\begin_layout Paragraph -8) Use a disjunctive value +\end_inset + + +\series bold +pipe notation +\series default +). \end_layout \begin_layout Standard -Pattern matching is the basic way of using a value of type +Tuples are denoted using the product symbol ( +\begin_inset Formula $\times$ +\end_inset + +). + For example, a pair \begin_inset listings inline true status open \begin_layout Plain Layout -Either[A, B] +(a, b) \end_layout \end_inset -: + is written in the code notation as +\begin_inset Formula $a\times b$ +\end_inset + +. + A tuple \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -val result: C = (e: Either[A, B]) match { +(a, b, c) \end_layout -\begin_layout Plain Layout +\end_inset - case Left(x: A) => expr1(x) + is written as +\begin_inset Formula $a\times b\times c$ +\end_inset + +, etc. \end_layout -\begin_layout Plain Layout +\begin_layout Standard +In this book, all type parameters are capitalized and all values are written + in lowercase. + This makes it clear that, say, +\begin_inset Formula $A\rightarrow A$ +\end_inset - case Right(y: B) => expr2(y) -\end_layout + and +\begin_inset Formula $A\times B$ +\end_inset -\begin_layout Plain Layout + are +\emph on +type +\emph default + expressions while +\begin_inset Formula $x\rightarrow x$ +\end_inset -} + and +\begin_inset Formula $a\times b$ +\end_inset + + are values. \end_layout +\begin_layout Standard +Functions that pattern-match on a tuple are denoted by +\begin_inset Formula $a\times b\rightarrow...$ \end_inset -Here, + (that is, the argument is written in a tuple form). + For example, the function denoted in Scala by \begin_inset listings inline true status open \begin_layout Plain Layout -expr1(x) +_._1 \end_layout \end_inset - is an expression of type + is written as +\begin_inset Formula $a\times b\rightarrow a$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Disjunctive types are treated specially in the code notation. + As a motivating example, consider the standard type \begin_inset listings inline true status open \begin_layout Plain Layout -\noindent -C +Either[A, B] \end_layout \end_inset - computed using +. + In the type notation, it is written as +\begin_inset Formula $A+B$ +\end_inset + +. + Values of that type can be of the form \begin_inset listings inline true status open \begin_layout Plain Layout -x: A +Left(x) \end_layout \end_inset - and any previously computed values. - Similarly, + or \begin_inset listings inline true status open \begin_layout Plain Layout -expr2(y) +Right(y) \end_layout \end_inset - is computed using +. + Those values are written as +\begin_inset Formula $x+\bbnum 0$ +\end_inset + + and +\begin_inset Formula $\bbnum 0+y$ +\end_inset + + in the code notation. + +\end_layout + +\begin_layout Standard +To motivate this unconventional notation, consider the type inferred by + Scala for a value \begin_inset listings inline true status open \begin_layout Plain Layout -y: B +Left(123) \end_layout \end_inset - and previous values. - The values used in computation correspond to the premises of a sequent. - So, +: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -expr1(x) +scala> Left(123) +\end_layout + +\begin_layout Plain Layout + +res0: Left[Int, Nothing] = Left(123) \end_layout \end_inset - represents a proof of a sequent with an additional premise of type +The inferred type is \begin_inset listings inline true status open \begin_layout Plain Layout -A +Left[Int, Nothing] \end_layout \end_inset -. - Denoting -\begin_inset Formula $\gamma\triangleq{\cal CH}(C)$ +, which is written as +\begin_inset Formula $\text{Int}+\bbnum 0$ \end_inset -, we write that sequent as: -\begin_inset Formula $\Gamma,\alpha\vdash\gamma$ + in the type notation. + As the void type ( +\begin_inset Formula $\bbnum 0$ \end_inset -. - Similarly, +) has no values, it makes sense that any value of type +\begin_inset Formula $\text{Int}+\bbnum 0$ +\end_inset + + +\emph on +must +\emph default + be of the form \begin_inset listings inline true status open \begin_layout Plain Layout -expr2(y) +Left(x) \end_layout \end_inset - is a proof of the sequent -\begin_inset Formula $\Gamma,\beta\vdash\gamma$ + with an integer +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x +\end_layout + \end_inset . - We can compute + More generally, a value of type +\begin_inset Formula $A+\bbnum 0$ +\end_inset + + is always of the form \begin_inset listings inline true status open \begin_layout Plain Layout -\noindent -result +Left(x) \end_layout \end_inset - only if we can compute + with some \begin_inset listings inline true status open \begin_layout Plain Layout -\noindent -e +x: A \end_layout \end_inset -, +, and a value of type +\begin_inset Formula $\bbnum 0+B$ +\end_inset + + must be of the form \begin_inset listings inline true status open \begin_layout Plain Layout -\noindent -expr1 +Right(y) \end_layout \end_inset -, and + with some \begin_inset listings inline true status open \begin_layout Plain Layout -\noindent -expr2 +y: B \end_layout \end_inset . - So, the proof rule is: -\begin_inset Formula -\[ -\frac{\Gamma\vdash\alpha\vee\beta\quad\quad\Gamma,\alpha\vdash\gamma\quad\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use Either})\quad\quad. -\] - + So, the code notation writes +\begin_inset Formula $x^{:A}+\bbnum 0$ \end_inset -The corresponding code can be written as: -\begin_inset Formula -\[ -\text{Proof}\left(\Gamma\vdash\gamma\right)=\text{Proof}\left(\Gamma\vdash\alpha\vee\beta\right)\text{ match }\begin{cases} -\text{case }a^{:A}\rightarrow & \text{Proof}\left(\Gamma,\alpha\vdash\gamma\right)_{\text{given }a}\\ -\text{case }b^{:B}\rightarrow & \text{Proof}\left(\Gamma,\beta\vdash\gamma\right)_{\text{given }b} -\end{cases}\quad. -\] + for values of type +\begin_inset Formula $A+\bbnum 0$ +\end_inset + and +\begin_inset Formula $\bbnum 0+y^{:B}$ \end_inset + for values of type +\begin_inset Formula $\bbnum 0+B$ +\end_inset +. + \end_layout \begin_layout Standard -We found eight proof rules shown in Table -\begin_inset space ~ +The type notation +\begin_inset Formula $A+\bbnum 0$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:Proof-rules-for-constructive-logic" -plural "false" -caps "false" -noprefix "false" - + and +\begin_inset Formula $\bbnum 0+B$ \end_inset -. - These rules define the -\series bold - -\begin_inset Index idx + for the +\begin_inset listings +inline true status open \begin_layout Plain Layout -intuitionistic propositional logic + +Left \end_layout \end_inset -intuitionistic propositional logic -\series default -, also called -\series bold - -\begin_inset Index idx + and the +\begin_inset listings +inline true status open \begin_layout Plain Layout -constructive logic + +Right \end_layout \end_inset -constructive propositional logic -\series default -. - We will call this logic -\begin_inset Quotes eld -\end_inset + parts of the disjunctive type +\begin_inset listings +inline true +status open -constructive -\begin_inset Quotes erd -\end_inset +\begin_layout Plain Layout - for short. +Either[A, B] \end_layout -\begin_layout Standard -\begin_inset Float table -wide false -sideways false -status open - -\begin_layout Plain Layout -\align center +\end_inset -\size small -\begin_inset Box Boxed -position "t" -hor_pos "c" -has_inner_box 1 -inner_pos "t" -use_parbox 0 -use_makebox 0 -width "75col%" -special "none" -height "1in" -height_special "totalheight" -thickness "0.4pt" -separation "3pt" -shadowsize "4pt" -framecolor "black" -backgroundcolor "none" + agrees with the behavior of the Scala compiler, which will infer the types + +\begin_inset listings +inline true status open \begin_layout Plain Layout -\size small -\begin_inset Formula -\begin{align*} -\text{axioms}:\quad & \frac{~}{\Gamma\vdash{\cal CH}(\bbnum 1)}\quad(\text{use unit})\quad\quad\quad\quad\frac{~}{\Gamma,\alpha\vdash\alpha}\quad(\text{use value})\\ -\text{derivation rules}:\quad & \frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function})\\ - & \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\alpha\Rightarrow\beta}{\Gamma\vdash\beta}\quad(\text{use function})\\ - & \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple})\\ - & \frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\\ - & \frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Left}})\quad\quad\quad\frac{\Gamma\vdash\beta}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Right}})\\ - & \frac{\Gamma\vdash\alpha\vee\beta\quad\quad\Gamma,\alpha\vdash\gamma\quad\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use \texttt{Either}}) -\end{align*} +Either[A, Nothing] +\end_layout \end_inset + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +Either[Nothing, B] \end_layout \end_inset + for the corresponding code: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout +def toLeft[A, B]: A => Either[A, B] = x => Left(x) \end_layout \begin_layout Plain Layout -\begin_inset Caption Standard + +def toRight[A, B]: B => Either[A, B] = y => Right(y) +\end_layout \begin_layout Plain Layout -Proof rules for the constructive logic. -\begin_inset CommandInset label -LatexCommand label -name "tab:Proof-rules-for-constructive-logic" -\end_inset +\end_layout +\begin_layout Plain Layout +scala> toLeft(123) \end_layout -\end_inset +\begin_layout Plain Layout + +res0: Either[Int, Nothing] = Left(123) +\end_layout +\begin_layout Plain Layout \end_layout +\begin_layout Plain Layout + +scala> toRight( +\begin_inset Quotes eld \end_inset +abc +\begin_inset Quotes erd +\end_inset +) \end_layout -\begin_layout Subsection -Examples: Deriving code from proofs of -\begin_inset Formula ${\cal CH}$ -\end_inset +\begin_layout Plain Layout --propositions -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example:-Proving-a-ch-proposition" +res1: Either[Nothing, String] = Right("abc") +\end_layout \end_inset +We can write the functions +\begin_inset listings +inline true +status open +\begin_layout Plain Layout + +toLeft \end_layout -\begin_layout Standard -Using the proof rules of Table -\begin_inset space ~ \end_inset + and +\begin_inset listings +inline true +status open -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:Proof-rules-for-constructive-logic" -plural "false" -caps "false" -noprefix "false" - -\end_inset +\begin_layout Plain Layout -, we can (in principle) derive code from type signatures of fully parametric - functions. - We will now show two simple examples and we perform such derivations step - by step. +toRight \end_layout -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:Example-derive-code-1" - \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Example-derive-code-1" -plural "false" -caps "false" -noprefix "false" + in the code notation as: +\begin_inset Formula +\[ +\text{toLeft}^{A,B}\triangleq x^{:A}\rightarrow x+\bbnum 0^{:B}\quad,\quad\quad\text{toRight}^{A,B}\triangleq y^{:B}\rightarrow\bbnum 0^{:A}+y\quad. +\] \end_inset +The code notation shows values of disjunctive types without using Scala + class names such as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +Either \end_layout -\begin_layout Standard -Derive the code for the type signature: +\end_inset + +, \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def d[X]: X => (X, X) +Right \end_layout \end_inset +, and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +Left \end_layout -\begin_layout Subparagraph -Solution +\end_inset + +. + This shortens the writing and speeds up reasoning about code. + \end_layout \begin_layout Standard -First, we formulate the task as proving the proposition -\begin_inset Quotes eld +In the notation +\begin_inset Formula $\bbnum 0^{:A}+y$ \end_inset -For any type -\begin_inset Formula $X$ +, we use the symbol +\begin_inset Formula $\bbnum 0$ \end_inset -, we can have a value of type -\begin_inset Formula $X\rightarrow X\times X$ + rather than an ordinary zero ( +\begin_inset Formula $0$ \end_inset - -\begin_inset Quotes erd +), to avoid suggesting that +\begin_inset Formula $0$ \end_inset -. - This corresponds to the proposition -\begin_inset Formula ${\cal CH}(\forall X.\,X\rightarrow X\times X)$ + is a value of type +\begin_inset Formula $\bbnum 0$ \end_inset . - That proposition will be the goal of a sequent. - The function has no arguments, so there are no premises for the sequent. - We denote an empty set of premises by the symbol -\begin_inset Formula $\emptyset$ + The void type +\begin_inset Formula $\bbnum 0$ \end_inset - -\begin_inset Index idx + has +\emph on +no +\emph default + values, unlike the +\begin_inset listings +inline true status open \begin_layout Plain Layout -0@ -\begin_inset Formula $\emptyset$ -\end_inset - (empty set) +Unit \end_layout \end_inset -. - So, the sequent is written as: -\begin_inset Formula -\[ -\emptyset\vdash{\cal CH}(\forall X.\,X\rightarrow X\times X)\quad. -\] - -\end_inset - -We denote -\begin_inset Formula $\chi\triangleq{\cal CH}(X)$ + type, +\begin_inset Formula $\bbnum 1$ \end_inset - and rewrite this sequent using the rules of Table -\begin_inset space ~ +, which has a value denoted by +\begin_inset Formula $1$ \end_inset + in the code notation. +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:ch-correspondence-type-notation-CH-propositions" -plural "false" -caps "false" -noprefix "false" - +\begin_layout Standard +Type annotations such as +\begin_inset Formula $\bbnum 0^{:A}$ \end_inset -. - The result is a sequent involving just -\begin_inset Formula $\chi$ + are helpful to remind ourselves about the type parameter +\begin_inset Formula $A$ \end_inset -: -\begin_inset Formula -\[ -\forall\chi.\,\emptyset\vdash\chi\Rightarrow\chi\wedge\chi\quad. -\] - + used, e.g., by the disjunctive value +\begin_inset Formula $\bbnum 0^{:A}+y^{:B}$ \end_inset + in the body of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +toRight[A, B] \end_layout -\begin_layout Standard -Next, we look for a proof of this sequent. - For brevity, we will omit the quantifier -\begin_inset Formula $\forall\chi$ \end_inset - since it will be present in front of every sequent. -\end_layout - -\begin_layout Standard -We search through the proof rules in Table -\begin_inset space ~ +. + Without that type annotation, +\begin_inset Formula $\bbnum 0+y^{:B}$ \end_inset + needs to be interpreted as a value of type +\begin_inset listings +inline true +status open -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:Proof-rules-for-constructive-logic" -plural "false" -caps "false" -noprefix "false" +\begin_layout Plain Layout -\end_inset +Either[A, B] +\end_layout -, looking for -\begin_inset Quotes eld \end_inset -denominators -\begin_inset Quotes erd +, where the type parameter +\begin_inset Formula $A$ \end_inset - that match our current sequent. - If we find such a rule, we will apply that rule to our sequent. - Then we will need to prove the sequents in the rule's -\begin_inset Quotes eld + must be determined by matching with the types of other expressions. + When it is clear what types are being used, we may omit type annotations + and write simply +\begin_inset Formula $\bbnum 0+y$ \end_inset -numerator -\begin_inset Quotes erd + instead of +\begin_inset Formula $\bbnum 0^{:A}+y^{:B}$ \end_inset . \end_layout \begin_layout Standard -Beginning with -\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ -\end_inset - -, we find a match with the rule +The type notation for pattern matching is also unconventional because it + uses \begin_inset Quotes eld \end_inset -create function +function matrices \begin_inset Quotes erd \end_inset -: -\begin_inset Formula -\[ -\frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function}) -\] + (matrices whose elements are functions). + To motivate that, we view a +\begin_inset listings +inline true +status open -\end_inset +\begin_layout Plain Layout -The denominator of that rule is -\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ -\end_inset +match +\end_layout -. - This pattern will match our sequent ( -\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ \end_inset -) if we set -\begin_inset Formula $\Gamma=\emptyset$ -\end_inset +/ +\begin_inset listings +inline true +status open -, -\begin_inset Formula $\alpha=\chi$ -\end_inset +\begin_layout Plain Layout + +case +\end_layout -, and -\begin_inset Formula $\beta=\chi\wedge\chi$ \end_inset -. - So, we are allowed to apply the rule + expression as a set of functions that map parts of a disjunctive type into + parts of another disjunctive type. + Consider this example code: +\begin_inset listings +lstparams "numbers=left" +inline false +status open + +\begin_layout Plain Layout + +def f: Either[Int, String] => Either[String, Int] = { +\end_layout + +\begin_layout Plain Layout + + case Left(x) => Right(10 * x) +\end_layout + +\begin_layout Plain Layout + + case Right(y) => Left( \begin_inset Quotes eld \end_inset -create function +a \begin_inset Quotes erd \end_inset - with these assignments. -\end_layout - -\begin_layout Standard -After these assignments, the rule + + y + \begin_inset Quotes eld \end_inset -create function +b \begin_inset Quotes erd \end_inset - becomes: -\begin_inset Formula -\[ -\frac{\emptyset,\chi\vdash\chi\wedge\chi}{\emptyset\vdash\chi\Rightarrow\chi\wedge\chi}\quad. -\] +) +\end_layout -\end_inset +\begin_layout Plain Layout -Now the rule says: we will prove the denominator ( -\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ -\end_inset +} +\end_layout -) if we first prove the numerator ( -\begin_inset Formula $\emptyset,\chi\vdash\chi\wedge\chi$ \end_inset -). +If we ignore the type names ( +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Left \end_layout -\begin_layout Standard -The set of premises -\begin_inset Formula $\emptyset,\chi$ \end_inset - is the union of an empty set and the set having a single premise -\begin_inset Formula $\chi$ -\end_inset + and +\begin_inset listings +inline true +status open -. - So, we can write the last sequent also as -\begin_inset Formula $\chi\vdash\chi\wedge\chi$ -\end_inset +\begin_layout Plain Layout - if we like. +Right \end_layout -\begin_layout Standard -To prove that sequent, we again look for a rule whose denominator matches - our sequent. - That rule is -\begin_inset Quotes eld \end_inset -create tuple -\begin_inset Quotes erd +), we will see that line +\begin_inset space ~ \end_inset -: -\begin_inset Formula -\[ -\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple}) -\] +2 is similar to the function +\begin_inset listings +inline true +status open -\end_inset +\begin_layout Plain Layout -The denominator ( -\begin_inset Formula $\Gamma\vdash\alpha\wedge\beta$ -\end_inset +x => 10 * x +\end_layout -) will match our sequent ( -\begin_inset Formula $\chi\vdash\chi\wedge\chi$ \end_inset -) if we assign -\begin_inset Formula $\Gamma=\chi$ -\end_inset + of type +\begin_inset listings +inline true +status open -, -\begin_inset Formula $\alpha=\chi$ -\end_inset +\begin_layout Plain Layout -, -\begin_inset Formula $\beta=\chi$ -\end_inset +Int => Int +\end_layout -. - With these assignments, the rule says that we need to prove two sequents - ( -\begin_inset Formula $\Gamma\vdash\alpha$ \end_inset - and -\begin_inset Formula $\Gamma\vdash\beta$ +, while line +\begin_inset space ~ \end_inset -), which are in fact the same sequent ( -\begin_inset Formula $\chi\vdash\chi$ -\end_inset +3 is similar to the function +\begin_inset listings +inline true +status open -). -\end_layout +\begin_layout Plain Layout -\begin_layout Standard -To prove that sequent, we apply the axiom +y => \begin_inset Quotes eld \end_inset -use value +a \begin_inset Quotes erd \end_inset -: -\begin_inset Formula -\[ -\frac{}{\Gamma,\alpha\vdash\alpha}\quad. -\] - + + y + +\begin_inset Quotes eld \end_inset -The denominator of that axiom matches -\begin_inset Formula $\emptyset,\chi\vdash\chi$ +b +\begin_inset Quotes erd \end_inset - if we set -\begin_inset Formula $\Gamma=\emptyset$ + +\end_layout + \end_inset - and -\begin_inset Formula $\alpha=\chi$ + of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +String => String +\end_layout + \end_inset . - Then the axiom + These functions become matrix elements in the \begin_inset Quotes eld \end_inset -use value +function matrix \begin_inset Quotes erd \end_inset - becomes: -\begin_inset Formula -\[ -\frac{}{\emptyset,\chi\vdash\chi}\quad. -\] - -\end_inset + for +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f +\end_layout + +\end_inset + +: +\begin_inset Formula +\[ +f^{:\text{Int}+\text{String}\rightarrow\text{String}+\text{Int}}\triangleq\,\begin{array}{|c||cc|} + & \text{String} & \text{Int}\\ +\hline \text{Int} & \bbnum 0 & x\rightarrow10*x\\ +\text{String} & y\rightarrow\text{"a"}+y+\text{"b"} & \bbnum 0 +\end{array}\quad. +\] + +\end_inset + +The rows of the matrix correspond to the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +case +\end_layout + +\end_inset + + rows in the Scala code. + There is one row for each part of the disjunctive type of the input argument. + The columns of the matrix correspond to the parts of the disjunctive type + of the output. +\begin_inset Index idx +status open + +\begin_layout Plain Layout +pattern matching!in matrix notation +\end_layout + +\end_inset + + The matrix element in the first row and second column is the function +\begin_inset Formula $x\rightarrow10*x$ +\end_inset + + that corresponds to line +\begin_inset space ~ +\end_inset + +2 in the Scala code. + The result type for that case is +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Right[Nothing, Int] +\end_layout + +\end_inset + +, which is written as +\begin_inset Formula $\bbnum 0+\text{Int}$ +\end_inset + + in the type notation. + The function +\begin_inset Formula $x\rightarrow10*x$ +\end_inset + + is written in the second column to indicate that the result type is +\begin_inset Formula $\bbnum 0+\text{Int}$ +\end_inset + +. + The matrix element in the first row and the first column is written as + +\begin_inset Formula $\bbnum 0$ +\end_inset + + because no value of the type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Left +\end_layout + +\end_inset + + is returned in that case. +\end_layout + +\begin_layout Standard +The matrix element in the second row and first column is the function +\begin_inset Formula $y\rightarrow\text{"a"}+y+\text{"b"}$ +\end_inset + + that corresponds to line +\begin_inset space ~ +\end_inset + +3 in the Scala code. + The result type for that case is +\begin_inset Formula $\text{String}+\bbnum 0$ +\end_inset + +. + The other matrix element in the second row is written as +\begin_inset Formula $\bbnum 0$ +\end_inset + +, according to the return type +\begin_inset Formula $\text{String}+\bbnum 0$ +\end_inset + +. + +\end_layout + +\begin_layout Standard +In this way, we translate all lines of the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +match +\end_layout + +\end_inset + +/ +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +case +\end_layout + +\end_inset + + expression into a code matrix. + In each row of the matrix, there can be only one element that is not +\begin_inset Formula $\bbnum 0$ +\end_inset + +. +\end_layout + +\begin_layout Standard +It turns out that the matrix notation is well adapted to computing +\emph on + forward compositions +\emph default + of functions that operate on disjunctive types. + We will see many examples of such computations later in this book. + In this chapter, we will use code matrices in Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-A+B" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-type-identity-5" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, and some others. +\end_layout + +\begin_layout Subsection +The rules of proof for +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions +\begin_inset CommandInset label +LatexCommand label +name "subsec:The-rules-of-proof" + +\end_inset + + +\end_layout + +\begin_layout Standard +Reasoning about proof rules begins by translating the eight standard code + constructs into sequents. + A proof of a sequent, e.g., +\begin_inset Formula $\mathcal{CH}(A)\vdash\mathcal{CH}(X)$ +\end_inset + +, will consist of applying some of those proof rules. + We will then combine the code constructs corresponding to each rule and + obtain some code that computes a value of type +\begin_inset Formula $X$ +\end_inset + + using an argument of type +\begin_inset Formula $A$ +\end_inset + +. + +\end_layout + +\begin_layout Standard +Conversely, any fully parametric (and non-recursive) code computing a value + of type +\begin_inset Formula $X$ +\end_inset + + must be a combination of some of the eight code constructs +\begin_inset Index idx +status open + +\begin_layout Plain Layout +eight code constructions +\end_layout + +\end_inset + +. + That code combination can be translated into a combination of logic rules, + which will produce a proof of the proposition +\begin_inset Formula ${\cal CH}(X)$ +\end_inset + +. +\end_layout + +\begin_layout Standard +In this way, we will get a correspondence between fully parametric programs + and proofs of sequents. + This is the second part of the +\series bold +Curry-Howard correspondence +\series default + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +Curry-Howard correspondence +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Standard +In the following text, we will need to write +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions such as Eq. +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-CH-proposition-def" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) as sequents such as Eq. +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-example-sequent" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +). + As we have seen, +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions involving complicated type expressions can be always rewritten + via +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions for individual type parameters ( +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + +, +\begin_inset Formula ${\cal CH}(B)$ +\end_inset + +, etc.). + So, we will only need sequents involving such +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions. + For brevity, we denote +\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ +\end_inset + +, +\begin_inset Formula $\beta\triangleq{\cal CH}(B)$ +\end_inset + +, etc. + We will use the letter +\begin_inset Formula $\Gamma$ +\end_inset + + to stand for a set of premises and write a shorter formula +\begin_inset Formula $\Gamma\vdash\alpha$ +\end_inset + + instead of the sequent +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-example-sequent" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +). +\end_layout + +\begin_layout Standard +With these notations, we list the rules for proving +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions and the corresponding code: +\end_layout + +\begin_layout Paragraph +1) The +\family typewriter +Unit +\family default + value +\end_layout + +\begin_layout Standard +At any place in the code, we may write the expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +() +\end_layout + +\end_inset + + of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Unit +\end_layout + +\end_inset + +. + This expression corresponds to a proof of the proposition +\begin_inset Formula ${\cal CH}(\bbnum 1)$ +\end_inset + + with any set +\begin_inset Formula $\Gamma$ +\end_inset + + of premises (even with an empty set of premises). + So, the sequent +\begin_inset Formula $\Gamma\vdash{\cal CH}(\bbnum 1)$ +\end_inset + + is always true. + The code corresponding to the proof of this sequent is an expression that + creates a value of the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Unit +\end_layout + +\end_inset + + type: +\begin_inset Formula +\[ +\text{Proof}\,\big(\Gamma\vdash{\cal CH}(\bbnum 1)\big)=1\quad, +\] + +\end_inset + +where we denoted by +\begin_inset Formula $1$ +\end_inset + + the value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +() +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Standard +In formal logic, a sequent that is always true, such as our +\begin_inset Formula $\Gamma\vdash{\cal CH}(\bbnum 1)$ +\end_inset + +, is called an +\series bold +axiom +\series default + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +logical axiom +\end_layout + +\end_inset + + and is written in the following notation: +\begin_inset Formula +\[ +\frac{}{\Gamma\vdash{\cal CH}(\bbnum 1)}\quad(\text{create unit})\quad\quad. +\] + +\end_inset + +The +\begin_inset Quotes eld +\end_inset + +fraction with a label +\begin_inset Quotes erd +\end_inset + + represents a proof rule. + The denominator of the fraction is the target sequent that we need to prove. + The numerator of the fraction can have zero or more other sequents that + need to be proved before the target sequent can be proved. + In this case, the set of previous sequents is empty: the target sequent + is an axiom and so requires no previous sequents for its proof. + The label +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\text{create unit}$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + is an arbitrary name used to refer to the rule. +\end_layout + +\begin_layout Paragraph +2) Use a given value +\end_layout + +\begin_layout Standard +At any place within the code of a fully parametric function, we may use + one of the function's arguments, say +\begin_inset Formula $x^{:A}$ +\end_inset + +. + If some argument has type +\begin_inset Formula $A$ +\end_inset + +, it means that we already have a value of type +\begin_inset Formula $A$ +\end_inset + +. + So, the corresponding proposition, +\begin_inset Formula $\alpha\triangleq{\cal CH}(A)$ +\end_inset + +, belongs to the set of premises of the sequent we are trying to prove. + To indicate this, we write the set of premises as +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\Gamma,\alpha$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + +. + The code construct +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x +\end_layout + +\end_inset + + computes a value of type +\begin_inset Formula $A$ +\end_inset + +, i.e., shows that +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\alpha$ +\end_inset + + is true with premises +\begin_inset Formula $\Gamma,\alpha$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + +. + That proposition is the meaning of the sequent +\begin_inset Formula $\Gamma,\alpha\vdash\alpha$ +\end_inset + +. + The proof code for that sequent is an expression that just returns the + value +\begin_inset Formula $x$ +\end_inset + +: +\begin_inset Formula +\[ +\text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }x^{:A}}=x\quad. +\] + +\end_inset + +Here, the subscript +\begin_inset Quotes eld +\end_inset + +given +\begin_inset Formula $x^{:A}$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + indicates that the value +\begin_inset Formula $x^{:A}$ +\end_inset + + must come from the premises. + In this case, the set of premises is +\begin_inset Formula $\Gamma,\alpha$ +\end_inset + + and so the proposition +\begin_inset Formula $\alpha$ +\end_inset + + must have been already proved. + The proof of +\begin_inset Formula $\alpha$ +\end_inset + + will give a value +\begin_inset Formula $x^{:A}$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Actually, the premises for the sequent +\begin_inset Formula $\Gamma,\alpha\vdash\alpha$ +\end_inset + + may give us not only a value +\begin_inset Formula $x^{:A}$ +\end_inset + + but also some other values of other types. + We may collectively denote those values by +\begin_inset Formula $p^{:\Gamma}$ +\end_inset + +. + But the proof of the sequent +\begin_inset Formula $\Gamma,\alpha\vdash\alpha$ +\end_inset + + does not need to use +\begin_inset Formula $p$ +\end_inset + +. + To show that explicitly, we may write: +\begin_inset Formula +\[ +\text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }p^{:\Gamma},\,x^{:A}}=x\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +The sequent +\begin_inset Formula $\Gamma,\alpha\vdash\alpha$ +\end_inset + + is an axiom since its proof requires no previous sequents; a value of type + +\begin_inset Formula $A$ +\end_inset + + is already given in the premises. + We denote this axiom by: +\begin_inset Formula +\[ +\frac{~}{\Gamma,\alpha\vdash\alpha}\quad(\text{use value})\quad\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Paragraph +3) Create a function +\end_layout + +\begin_layout Standard +At any place in the code, we may compute a nameless function of type, say, + +\begin_inset Formula $A\rightarrow B$ +\end_inset + +, by writing +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(x: A) => expr +\end_layout + +\end_inset + + as long as a value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr +\end_layout + +\end_inset + + of type +\begin_inset Formula $B$ +\end_inset + + can be computed in the inner scope of the function. + The code for +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr +\end_layout + +\end_inset + + is also required to be fully parametric; it may use +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x +\end_layout + +\end_inset + + and/or other values visible in that scope. + So, we now need to answer the question of whether a fully parametric function + can compute a value of type +\begin_inset Formula $B$ +\end_inset + +, given an argument of type +\begin_inset Formula $A$ +\end_inset + + as well as all other arguments previously given to the parent function. + This question is answered by a sequent whose premises contain one more + proposition, +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + +, in addition to all previously available premises. + Translating this into the language of +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions, we find that we will prove the sequent: +\begin_inset Formula +\[ +\Gamma\vdash{\cal CH}(A\rightarrow B)\quad=\quad\Gamma\vdash{\cal CH}(A)\Rightarrow{\cal CH}(B)\quad=\quad\Gamma\vdash\alpha\Rightarrow\beta +\] + +\end_inset + +if we can prove the sequent +\begin_inset Formula $\Gamma,{\cal CH}(A)\vdash{\cal CH}(B)=\Gamma,\alpha\vdash\beta$ +\end_inset + +. + In the notation of formal logic, this is a +\series bold +derivation rule +\series default + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +derivation rule +\end_layout + +\end_inset + + (rather than an axiom) and is written as: +\begin_inset Formula +\[ +\frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function})\quad\quad. +\] + +\end_inset + +The +\series bold +turnstile +\series default + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +0@ +\begin_inset Formula $\vdash$ +\end_inset + + (turnstile) symbol +\end_layout + +\end_inset + + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +turnstile ( +\begin_inset Formula $\vdash$ +\end_inset + +) symbol +\end_layout + +\end_inset + + symbol ( +\begin_inset Formula $\vdash$ +\end_inset + +) groups weaker than other operators. + So, we can write sequents such as +\begin_inset Formula $(\Gamma,\alpha)\vdash(\beta\Rightarrow\gamma)$ +\end_inset + + with fewer parentheses: +\begin_inset Formula $\Gamma,\alpha\vdash\beta\Rightarrow\gamma$ +\end_inset + +. +\end_layout + +\begin_layout Standard +What code corresponds to the +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\text{create function}$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + rule? The proof of +\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ +\end_inset + + depends on a proof of another sequent. + So, the corresponding code must be a +\emph on +function +\emph default + that takes a proof of the previous sequent as an argument and returns a + proof of the new sequent. + 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. + So, a proof of the sequent +\begin_inset Formula $\Gamma,\alpha\vdash\beta$ +\end_inset + + is an expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +exprB +\end_layout + +\end_inset + + of type +\begin_inset Formula $B$ +\end_inset + + that may use a given value of type +\begin_inset Formula $A$ +\end_inset + + as well as any other arguments given previously. + Then we can write the proof code for the sequent +\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ +\end_inset + + as the nameless function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(x: A) => exprB +\end_layout + +\end_inset + +. + This function has type +\begin_inset Formula $A\rightarrow B$ +\end_inset + + and requires us to already have a suitable expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +exprB +\end_layout + +\end_inset + +. + This exactly corresponds to the proof rule +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\text{create function}$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + +. + That rule's proof transformer is: +\begin_inset Formula +\[ +\text{Proof}\,\big(\Gamma\vdash\alpha\Rightarrow\beta\big)_{\text{given }p^{:\Gamma}}=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,\alpha\vdash\beta\big)_{\text{given }p^{:\Gamma},\,x^{:A}}\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Paragraph +4) Use a function +\end_layout + +\begin_layout Standard +At any place in the code, we may apply an already defined function of type + +\begin_inset Formula $A\rightarrow B$ +\end_inset + + to an already computed value of type +\begin_inset Formula $A$ +\end_inset + +. + The result will be a value of type +\begin_inset Formula $B$ +\end_inset + +. + This corresponds to assuming +\begin_inset Formula ${\cal CH}(A\rightarrow B)$ +\end_inset + + and +\begin_inset Formula ${\cal CH}(A)$ +\end_inset + +, and then deriving +\begin_inset Formula ${\cal CH}(B)$ +\end_inset + +. + The notation for this proof rule is: +\begin_inset Formula +\[ +\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\alpha\Rightarrow\beta}{\Gamma\vdash\beta}\quad(\text{use function})\quad\quad. +\] + +\end_inset + +The code corresponding to this proof rule takes previously computed values + +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x: A +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f: A => B +\end_layout + +\end_inset + +, and writes the expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f(x) +\end_layout + +\end_inset + +. + This can be written as a function application: +\begin_inset Formula +\[ +\text{Proof}\,(\Gamma\vdash\beta)=\text{Proof}\left(\Gamma\vdash\alpha\Rightarrow\beta\right)(\text{Proof}\,(\Gamma\vdash\alpha))\quad. +\] + +\end_inset + +Here we omitted the subscripts +\begin_inset Quotes eld +\end_inset + + +\begin_inset Formula $\text{given }p^{:\Gamma}$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + + for brevity, since all sequents have the same premises +\begin_inset Formula $\Gamma$ +\end_inset + +. +\end_layout + +\begin_layout Paragraph +5) Create a tuple +\end_layout + +\begin_layout Standard +If we have already computed some values +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +a: A +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +b: B +\end_layout + +\end_inset + +, we may write the expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(a, b) +\end_layout + +\end_inset + + and so compute a value of the tuple type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(A, B) +\end_layout + +\end_inset + +. + The proof rule is: +\begin_inset Formula +\[ +\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple})\quad\quad. +\] + +\end_inset + +In the code notation, +\begin_inset Formula $a\times b$ +\end_inset + + means the pair +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(a, b) +\end_layout + +\end_inset + +, so we can write the code as: +\begin_inset Formula +\[ +\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)=\text{Proof}\left(\Gamma\vdash\alpha\right)\times\text{Proof}\left(\Gamma\vdash\beta\right)\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +This rule describes creating a tuple of +\begin_inset Formula $2$ +\end_inset + + values. + A larger tuple, such as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(w, x, y, z) +\end_layout + +\end_inset + +, can be expressed via nested pairs, e.g., as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(w, (x, (y, z))) +\end_layout + +\end_inset + +. + So, it suffices to have a derivation rule for creating pairs. + That rule allows us to derive the rules for creating all larger tuples, + without having to define separate rules for, say, +\begin_inset Formula $\Gamma\vdash\alpha\wedge\beta\wedge\gamma$ +\end_inset + +. +\end_layout + +\begin_layout Paragraph +6) Use a tuple +\end_layout + +\begin_layout Standard +If we already have a value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +t: (A, B) +\end_layout + +\end_inset + + of a tuple type +\begin_inset Formula $A\times B$ +\end_inset + +, we can extract one of the parts of the tuple and obtain a value of type + +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A +\end_layout + +\end_inset + + or a value of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +B +\end_layout + +\end_inset + +. + The code is +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +t._1 +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +t._2 +\end_layout + +\end_inset + + respectively, and the corresponding 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. +\] + +\end_inset + +The proof code can be written as: +\begin_inset Formula +\[ +\text{Proof}\left(\Gamma\vdash\alpha\right)=\pi_{1}\left(\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)\right)\quad,\quad\text{Proof}\left(\Gamma\vdash\beta\right)=\pi_{2}\left(\text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)\right)\quad, +\] + +\end_inset + +where we introduced the notation +\begin_inset Formula $\pi_{1}$ +\end_inset + + and +\begin_inset Formula $\pi_{2}$ +\end_inset + + to mean the Scala code +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +_._1 +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +_._2 +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Standard +Since all tuples can be expressed through pairs, it is sufficient to have + proof rules for pairs. +\end_layout + +\begin_layout Paragraph +7) Create a disjunctive value +\end_layout + +\begin_layout Standard +The type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either[A, B] +\end_layout + +\end_inset + + corresponding to the disjunction +\begin_inset Formula $\alpha\vee\beta$ +\end_inset + + can be used to define any other disjunctive type; e.g., a disjunctive type + with three parts can be expressed as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either[A, Either[B, C]] +\end_layout + +\end_inset + +. + So, it suffices to have proof rules for a disjunction of +\emph on +two +\emph default + propositions. +\end_layout + +\begin_layout Standard +There are two ways of creating a value of the type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either[A, B] +\end_layout + +\end_inset + +: the code expressions are +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Left(x: A) +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Right(y: B) +\end_layout + +\end_inset + +. + The values +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x: A +\end_layout + +\end_inset + + or +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +y: B +\end_layout + +\end_inset + + must have been computed previously (and correspond to previously proved + sequents). + So, the sequent proof rules are: +\begin_inset Formula +\[ +\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. +\] + +\end_inset + +The corresponding proof transformers can be written using the case class + names +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Left +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Right +\end_layout + +\end_inset + + as: +\begin_inset Formula +\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. +\end{align*} + +\end_inset + + +\end_layout + +\begin_layout Paragraph +8) Use a disjunctive value +\end_layout + +\begin_layout Standard +Pattern matching is the basic way of using a value of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either[A, B] +\end_layout + +\end_inset + +: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +val result: C = (e: Either[A, B]) match { +\end_layout + +\begin_layout Plain Layout + + case Left(x: A) => expr1(x) +\end_layout + +\begin_layout Plain Layout + + case Right(y: B) => expr2(y) +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + +Here, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr1(x) +\end_layout + +\end_inset + + is an expression of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +C +\end_layout + +\end_inset + + computed using +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +x: A +\end_layout + +\end_inset + + and any previously computed values. + Similarly, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr2(y) +\end_layout + +\end_inset + + is computed using +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +y: B +\end_layout + +\end_inset + + and previous values. + The values used in computation correspond to the premises of a sequent. + So, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr1(x) +\end_layout + +\end_inset + + represents a proof of a sequent with an additional premise of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +A +\end_layout + +\end_inset + +. + Denoting +\begin_inset Formula $\gamma\triangleq{\cal CH}(C)$ +\end_inset + +, we write that sequent as: +\begin_inset Formula $\Gamma,\alpha\vdash\gamma$ +\end_inset + +. + Similarly, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +expr2(y) +\end_layout + +\end_inset + + is a proof of the sequent +\begin_inset Formula $\Gamma,\beta\vdash\gamma$ +\end_inset + +. + We can compute +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +result +\end_layout + +\end_inset + + only if we can compute +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +e +\end_layout + +\end_inset + +, +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +expr1 +\end_layout + +\end_inset + +, and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout +\noindent + +expr2 +\end_layout + +\end_inset + +. + So, the proof rule is: +\begin_inset Formula +\[ +\frac{\Gamma\vdash\alpha\vee\beta\quad\quad\Gamma,\alpha\vdash\gamma\quad\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use Either})\quad\quad. +\] + +\end_inset + +The corresponding code can be written as: +\begin_inset Formula +\[ +\text{Proof}\left(\Gamma\vdash\gamma\right)=\text{Proof}\left(\Gamma\vdash\alpha\vee\beta\right)\text{ match }\begin{cases} +\text{case }a^{:A}\rightarrow & \text{Proof}\left(\Gamma,\alpha\vdash\gamma\right)_{\text{given }a}\\ +\text{case }b^{:B}\rightarrow & \text{Proof}\left(\Gamma,\beta\vdash\gamma\right)_{\text{given }b} +\end{cases}\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +We found eight proof rules shown in Table +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Proof-rules-for-constructive-logic" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + These rules define the +\series bold + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +intuitionistic propositional logic +\end_layout + +\end_inset + +intuitionistic propositional logic +\series default +, also called +\series bold + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +constructive logic +\end_layout + +\end_inset + +constructive propositional logic +\series default +. + We will call this logic +\begin_inset Quotes eld +\end_inset + +constructive +\begin_inset Quotes erd +\end_inset + + for short. +\end_layout + +\begin_layout Standard +\begin_inset Float table +wide false +sideways false +status open + +\begin_layout Plain Layout +\align center + +\size small +\begin_inset Box Boxed +position "t" +hor_pos "c" +has_inner_box 1 +inner_pos "t" +use_parbox 0 +use_makebox 0 +width "75col%" +special "none" +height "1in" +height_special "totalheight" +thickness "0.4pt" +separation "3pt" +shadowsize "4pt" +framecolor "black" +backgroundcolor "none" +status open + +\begin_layout Plain Layout + +\size small +\begin_inset Formula +\begin{align*} +\text{axioms}:\quad & \frac{~}{\Gamma\vdash{\cal CH}(\bbnum 1)}\quad(\text{use unit})\quad\quad\quad\quad\frac{~}{\Gamma,\alpha\vdash\alpha}\quad(\text{use value})\\ +\text{derivation rules}:\quad & \frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function})\\ + & \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\alpha\Rightarrow\beta}{\Gamma\vdash\beta}\quad(\text{use function})\\ + & \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple})\\ + & \frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\alpha}\quad(\text{use tuple-}1)\quad\quad\quad\frac{\Gamma\vdash\alpha\wedge\beta}{\Gamma\vdash\beta}\quad(\text{use tuple-}2)\\ + & \frac{\Gamma\vdash\alpha}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Left}})\quad\quad\quad\frac{\Gamma\vdash\beta}{\Gamma\vdash\alpha\vee\beta}\quad(\text{create \texttt{Right}})\\ + & \frac{\Gamma\vdash\alpha\vee\beta\quad\quad\Gamma,\alpha\vdash\gamma\quad\quad\Gamma,\beta\vdash\gamma}{\Gamma\vdash\gamma}\quad(\text{use \texttt{Either}}) +\end{align*} + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Proof rules for the constructive logic. +\begin_inset CommandInset label +LatexCommand label +name "tab:Proof-rules-for-constructive-logic" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsection +Examples: Deriving code from proofs of +\begin_inset Formula ${\cal CH}$ +\end_inset + +-propositions +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example:-Proving-a-ch-proposition" + +\end_inset + + +\end_layout + +\begin_layout Standard +Using the proof rules of Table +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Proof-rules-for-constructive-logic" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, we can (in principle) derive code from type signatures of fully parametric + functions. + We will now show two simple examples and we perform such derivations step + by step. +\end_layout + +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-derive-code-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-derive-code-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Derive the code for the type signature: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def d[X]: X => (X, X) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subparagraph +Solution +\end_layout + +\begin_layout Standard +First, we formulate the task as proving the proposition +\begin_inset Quotes eld +\end_inset + +For any type +\begin_inset Formula $X$ +\end_inset + +, we can have a value of type +\begin_inset Formula $X\rightarrow X\times X$ +\end_inset + + +\begin_inset Quotes erd +\end_inset + +. + This corresponds to the proposition +\begin_inset Formula ${\cal CH}(\forall X.\,X\rightarrow X\times X)$ +\end_inset + +. + That proposition will be the goal of a sequent. + The function has no arguments, so there are no premises for the sequent. + We denote an empty set of premises by the symbol +\begin_inset Formula $\emptyset$ +\end_inset + + +\begin_inset Index idx +status open + +\begin_layout Plain Layout +0@ +\begin_inset Formula $\emptyset$ +\end_inset + + (empty set) +\end_layout + +\end_inset + +. + So, the sequent is written as: +\begin_inset Formula +\[ +\emptyset\vdash{\cal CH}(\forall X.\,X\rightarrow X\times X)\quad. +\] + +\end_inset + +We denote +\begin_inset Formula $\chi\triangleq{\cal CH}(X)$ +\end_inset + + and rewrite this sequent using the rules of Table +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:ch-correspondence-type-notation-CH-propositions" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + The result is a sequent involving just +\begin_inset Formula $\chi$ +\end_inset + +: +\begin_inset Formula +\[ +\forall\chi.\,\emptyset\vdash\chi\Rightarrow\chi\wedge\chi\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +Next, we look for a proof of this sequent. + For brevity, we will omit the quantifier +\begin_inset Formula $\forall\chi$ +\end_inset + + since it will be present in front of every sequent. +\end_layout + +\begin_layout Standard +We search through the proof rules in Table +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Proof-rules-for-constructive-logic" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, looking for +\begin_inset Quotes eld +\end_inset + +denominators +\begin_inset Quotes erd +\end_inset + + that match our current sequent. + If we find such a rule, we will apply that rule to our sequent. + Then we will need to prove the sequents in the rule's +\begin_inset Quotes eld +\end_inset + +numerator +\begin_inset Quotes erd +\end_inset + +. +\end_layout + +\begin_layout Standard +Beginning with +\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ +\end_inset + +, we find a match with the rule +\begin_inset Quotes eld +\end_inset + +create function +\begin_inset Quotes erd +\end_inset + +: +\begin_inset Formula +\[ +\frac{\Gamma,\alpha\vdash\beta}{\Gamma\vdash\alpha\Rightarrow\beta}\quad(\text{create function}) +\] + +\end_inset + +The denominator of that rule is +\begin_inset Formula $\Gamma\vdash\alpha\Rightarrow\beta$ +\end_inset + +. + This pattern will match our sequent ( +\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ +\end_inset + +) if we set +\begin_inset Formula $\Gamma=\emptyset$ +\end_inset + +, +\begin_inset Formula $\alpha=\chi$ +\end_inset + +, and +\begin_inset Formula $\beta=\chi\wedge\chi$ +\end_inset + +. + So, we are allowed to apply the rule +\begin_inset Quotes eld +\end_inset + +create function +\begin_inset Quotes erd +\end_inset + + with these assignments. +\end_layout + +\begin_layout Standard +After these assignments, the rule +\begin_inset Quotes eld +\end_inset + +create function +\begin_inset Quotes erd +\end_inset + + becomes: +\begin_inset Formula +\[ +\frac{\emptyset,\chi\vdash\chi\wedge\chi}{\emptyset\vdash\chi\Rightarrow\chi\wedge\chi}\quad. +\] + +\end_inset + +Now the rule says: we will prove the denominator ( +\begin_inset Formula $\emptyset\vdash\chi\Rightarrow\chi\wedge\chi$ +\end_inset + +) if we first prove the numerator ( +\begin_inset Formula $\emptyset,\chi\vdash\chi\wedge\chi$ +\end_inset + +). +\end_layout + +\begin_layout Standard +The set of premises +\begin_inset Formula $\emptyset,\chi$ +\end_inset + + is the union of an empty set and the set having a single premise +\begin_inset Formula $\chi$ +\end_inset + +. + So, we can write the last sequent also as +\begin_inset Formula $\chi\vdash\chi\wedge\chi$ +\end_inset + + if we like. +\end_layout + +\begin_layout Standard +To prove that sequent, we again look for a rule whose denominator matches + our sequent. + That rule is +\begin_inset Quotes eld +\end_inset + +create tuple +\begin_inset Quotes erd +\end_inset + +: +\begin_inset Formula +\[ +\frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple}) +\] + +\end_inset + +The denominator ( +\begin_inset Formula $\Gamma\vdash\alpha\wedge\beta$ +\end_inset + +) will match our sequent ( +\begin_inset Formula $\chi\vdash\chi\wedge\chi$ +\end_inset + +) if we assign +\begin_inset Formula $\Gamma=\chi$ +\end_inset + +, +\begin_inset Formula $\alpha=\chi$ +\end_inset + +, +\begin_inset Formula $\beta=\chi$ +\end_inset + +. + With these assignments, the rule says that we need to prove two sequents + ( +\begin_inset Formula $\Gamma\vdash\alpha$ +\end_inset + + and +\begin_inset Formula $\Gamma\vdash\beta$ +\end_inset + +), which are in fact the same sequent ( +\begin_inset Formula $\chi\vdash\chi$ +\end_inset + +). +\end_layout + +\begin_layout Standard +To prove that sequent, we apply the axiom +\begin_inset Quotes eld +\end_inset + +use value +\begin_inset Quotes erd +\end_inset + +: +\begin_inset Formula +\[ +\frac{}{\Gamma,\alpha\vdash\alpha}\quad. +\] + +\end_inset + +The denominator of that axiom matches +\begin_inset Formula $\emptyset,\chi\vdash\chi$ +\end_inset + + if we set +\begin_inset Formula $\Gamma=\emptyset$ +\end_inset + + and +\begin_inset Formula $\alpha=\chi$ +\end_inset + +. + Then the axiom +\begin_inset Quotes eld +\end_inset + +use value +\begin_inset Quotes erd +\end_inset + + becomes: +\begin_inset Formula +\[ +\frac{}{\emptyset,\chi\vdash\chi}\quad. +\] + +\end_inset This axiom says that the sequent \begin_inset Formula $\emptyset,\chi\vdash\chi$ @@ -8447,9 +10295,12 @@ name "fig:Proof-of-the-sequent-example-1" \begin_layout Standard Now we need to extract code from the proof. - We begin with the leaves of the tree and trace back the proof towards the - top. - The axiom + We begin with the leaves of the tree and go back towards the top of the + proof. +\end_layout + +\begin_layout Standard +The axiom \begin_inset Quotes eld \end_inset @@ -8473,7 +10324,7 @@ use value \end_inset -The proof used this axiom twice with +The proof uses this axiom twice with \begin_inset Formula $\alpha=\chi$ \end_inset @@ -8604,10 +10455,6 @@ def d[X]: X => (X, X) = (x: X) => (x, x) \end_inset -\begin_inset Formula $\square$ -\end_inset - - \end_layout \begin_layout Subsubsection @@ -8774,10 +10621,11 @@ denominator \end_inset of the form -\begin_inset Formula $\Gamma\vdash(p\Rightarrow q$ +\begin_inset Formula $\Gamma\vdash p\Rightarrow q$ \end_inset -); this is the rule +. + That rule is \begin_inset Quotes eld \end_inset @@ -8789,7 +10637,7 @@ denominator \begin_inset Quotes erd \end_inset -, which we will rewrite as: +, which we will rewrite for clarity as: \begin_inset Formula \[ \frac{\Gamma,p\vdash q}{\Gamma\vdash p\Rightarrow q}\quad(\text{create function}) @@ -9118,9 +10966,17 @@ Rightarrow \backslash alpha$ [ .{rule ``$ \backslash -text{create function}$''} [ .$ +text{create function}$''} [ .$( +\backslash +alpha +\backslash +Rightarrow \backslash -gamma, +alpha) +\backslash +Rightarrow +\backslash +beta, \backslash alpha \backslash @@ -9332,7 +11188,7 @@ s[A, B] \begin_inset Formula $\alpha$ \end_inset - added to the set of premises only for this step of the proof. + added to the set of premises at this step of the proof. Once we are finished with this step, we again will not have any values of type \begin_inset Formula $A$ @@ -9994,10 +11850,10 @@ curryhoward \end_inset - library tries to select the code that has the least information loss, according - to several heuristics. - In many cases, the heuristics select the implementation that is most useful - to the programmer. + library uses heuristics to try finding the code that has the least information + loss. + In many cases, the heuristics will select the implementation that is most + useful to the programmer. \end_layout \begin_layout Standard @@ -10390,7 +12246,11 @@ Either require us to choose new unknown propositions and to prove sequents more complicated than the ones we had before. - For instance, the rule + +\end_layout + +\begin_layout Standard +For instance, the rule \begin_inset Quotes eld \end_inset @@ -10556,7 +12416,7 @@ literal "false" \end_layout \begin_layout Standard -We will first present the LJ algorithm. +We will begin with the LJ algorithm. Although that algorithm does not guarantee termination, it is simpler to understand and to apply by hand. Then we will show how to modify the LJ algorithm in order to obtain the @@ -10614,7 +12474,7 @@ right \end_inset ). - Those sub-expressions are shown in blue in Figure + Those sub-expressions are shown in red in Figure \begin_inset space ~ \end_inset @@ -10630,7 +12490,7 @@ noprefix "false" to help us look for a proof. To find out which rules apply, we match some part of the sequent with a - blue sub-expression. + red sub-expression. \end_layout \begin_layout Standard @@ -10662,10 +12522,10 @@ status open \begin_layout Plain Layout \begin_inset Formula \begin{align*} -\frac{}{\Gamma,X\vdash{\color{blue}X}}~(\text{Id})\qquad & \qquad\frac{}{\Gamma\vdash{\color{blue}\top}}~(\text{True})\\ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\qquad & \qquad\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{blue}A\Rightarrow B}}~(\text{Right}\Rightarrow)\\ -\frac{\Gamma,A_{i}\vdash C}{\Gamma,{\color{blue}A_{1}\wedge A_{2}}\vdash C}~(\text{Left}\wedge_{i})\qquad & \qquad\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{blue}A\wedge B}}~(\text{Right}\wedge)\\ -\frac{\Gamma,A\vdash C\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\vee B}\vdash C}~(\text{Left}\vee)\qquad & \qquad\frac{\Gamma\vdash A_{i}}{\Gamma\vdash{\color{blue}A_{1}\vee A_{2}}}~(\text{Right}\vee_{i}) +\frac{}{\Gamma,X\vdash{\color{red}X}}~(\text{Id})\qquad & \qquad\frac{}{\Gamma\vdash{\color{red}\top}}~(\text{True})\\ +\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\qquad & \qquad\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{red}A\Rightarrow B}}~(\text{Right}\Rightarrow)\\ +\frac{\Gamma,A_{i}\vdash C}{\Gamma,{\color{red}A_{1}\wedge A_{2}}\vdash C}~(\text{Left}\wedge_{i})\qquad & \qquad\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{red}A\wedge B}}~(\text{Right}\wedge)\\ +\frac{\Gamma,A\vdash C\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\vee B}\vdash C}~(\text{Left}\vee)\qquad & \qquad\frac{\Gamma\vdash A_{i}}{\Gamma\vdash{\color{red}A_{1}\vee A_{2}}}~(\text{Right}\vee_{i}) \end{align*} \end_inset @@ -11038,11 +12898,11 @@ Extracting code from proofs \end_layout \begin_layout Standard -According to the Curry-Howard correspondence, a sequent (such as -\begin_inset Formula $A,B,...,C\vdash X$ +According to the Curry-Howard correspondence, a sequent of the form +\begin_inset Formula ${\cal CH}(A),{\cal CH}(B),...,{\cal CH}(C)\vdash{\cal CH}(X)$ \end_inset -) represents the task of writing a fully parametric code expression of type + represents the task of writing a fully parametric code expression of type \begin_inset Formula $X$ \end_inset @@ -11106,28 +12966,28 @@ status open \size small \begin_inset Formula \begin{align*} -\frac{}{\Gamma,A\vdash{\color{blue}A}}~(\text{Id})\quad & \quad\text{Proof}\,(\Gamma,A\vdash A)_{\text{given }p^{:\Gamma},x^{:A}}=x\\ -\frac{}{\Gamma\vdash{\color{blue}\top}}~(\text{True})\quad & \quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\\ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma,A\Rightarrow B\vdash C)_{\text{given }p^{:\Gamma},q^{:A\rightarrow B}}\\ +\frac{}{\Gamma,A\vdash{\color{red}A}}~(\text{Id})\quad & \quad\text{Proof}\,(\Gamma,A\vdash A)_{\text{given }p^{:\Gamma},x^{:A}}=x\\ +\frac{}{\Gamma\vdash{\color{red}\top}}~(\text{True})\quad & \quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\\ +\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma,A\Rightarrow B\vdash C)_{\text{given }p^{:\Gamma},q^{:A\rightarrow B}}\\ & \quad\quad=\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p,b^{:B}}\\ \text{where} & \quad b^{:B}\triangleq q\big(\text{Proof}\,(\Gamma,A\Rightarrow B\vdash A)_{\text{given }p,q}\big)\\ -\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{blue}A\Rightarrow B}}~(\text{Right}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma\vdash A\Rightarrow B)_{\text{given }p^{:\Gamma}}\\ +\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{red}A\Rightarrow B}}~(\text{Right}\Rightarrow)\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}}\\ -\frac{\Gamma,A\vdash C}{\Gamma,{\color{blue}A\wedge B}\vdash C}~(\text{Left}\wedge_{1})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ +\frac{\Gamma,A\vdash C}{\Gamma,{\color{red}A\wedge B}\vdash C}~(\text{Left}\wedge_{1})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ & \quad\quad=\text{Proof}\,(\Gamma,A\vdash C)_{\text{given }p^{:\Gamma},a^{:A}}\\ -\frac{\Gamma,B\vdash C}{\Gamma,{\color{blue}A\wedge B}\vdash C}~(\text{Left}\wedge_{2})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ +\frac{\Gamma,B\vdash C}{\Gamma,{\color{red}A\wedge B}\vdash C}~(\text{Left}\wedge_{2})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ & \quad\quad=\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p^{:\Gamma},b^{:B}}\\ -\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{blue}A\wedge B}}~(\text{Right}\wedge)\quad & \quad\text{Proof}\,(\Gamma\vdash A\wedge B)_{\text{given }p^{:\Gamma}}\\ +\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{red}A\wedge B}}~(\text{Right}\wedge)\quad & \quad\text{Proof}\,(\Gamma\vdash A\wedge B)_{\text{given }p^{:\Gamma}}\\ & \quad\quad=\text{Proof}\,(\Gamma\vdash A)_{\text{given }p^{:\Gamma}}\\ & \quad\quad\quad\times\text{Proof}\,(\Gamma\vdash B)_{\text{given }p^{:\Gamma}}\\ -\frac{\Gamma,A\vdash C\quad\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\vee B}\vdash C}~(\text{Left}\vee)\quad & \quad\text{Proof}\,(\Gamma,A\vee B\vdash C)_{\text{given }p^{:\Gamma},q^{:A+B}}\\ +\frac{\Gamma,A\vdash C\quad\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\vee B}\vdash C}~(\text{Left}\vee)\quad & \quad\text{Proof}\,(\Gamma,A\vee B\vdash C)_{\text{given }p^{:\Gamma},q^{:A+B}}\\ & \quad\quad=q\triangleright\begin{array}{|c||c|} & C\\ \hline A & x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash C)_{\text{given }p,x}\\ B & y^{:B}\rightarrow\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p,y} \end{array}\\ -\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) +\frac{\Gamma\vdash A}{\Gamma\vdash{\color{red}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{red}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*} \end_inset @@ -11698,8 +13558,8 @@ four : \begin_inset Formula \begin{align*} -\text{(}A\text{ is atomic)\,}\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{blue}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\qquad & \quad\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\\ -\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\quad\Gamma,C\vdash D}{\Gamma,{\color{blue}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\qquad & \quad\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee}) +\text{(}A\text{ is atomic)\,}\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{red}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\qquad & \quad\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\\ +\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\quad\Gamma,C\vdash D}{\Gamma,{\color{red}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\qquad & \quad\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee}) \end{align*} \end_inset @@ -11855,7 +13715,7 @@ target "https://github.com/Chymyst/curryhoward" \family default - implements these proof transformers. + implements those proof transformers. \end_layout \begin_layout Standard @@ -12076,16 +13936,16 @@ status open \size small \begin_inset Formula \begin{align*} -\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{blue}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\quad & \quad\text{Proof}\,(\Gamma,A,A\Rightarrow B\vdash D)_{\text{given }p^{:\Gamma},x^{:A},q^{:A\rightarrow B}}\\ +\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{red}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\quad & \quad\text{Proof}\,(\Gamma,A,A\Rightarrow B\vdash D)_{\text{given }p^{:\Gamma},x^{:A},q^{:A\rightarrow B}}\\ & \quad\quad=\text{Proof}\,(\Gamma,A,B\vdash D)_{\text{given }p,x,q(x)}\\ -\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\quad & \quad\text{Proof}\,(\Gamma,(A\wedge B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A\times B\rightarrow C}}\\ +\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\quad & \quad\text{Proof}\,(\Gamma,(A\wedge B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A\times B\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,\\ & \quad\quad\quad A\Rightarrow B\Rightarrow C\vdash D)_{\text{given }p,(a^{:A}\rightarrow b^{:B}\rightarrow q(a\times b))}\\ -\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee})\quad & \quad\text{Proof}\,(\Gamma,(A\vee B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A+B\rightarrow C}}\\ +\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee})\quad & \quad\text{Proof}\,(\Gamma,(A\vee B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A+B\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D)_{\text{given }p,r,s}\\ & \quad\quad\text{where}~r\triangleq a^{:A}\rightarrow q(a+\bbnum 0)\\ & \quad\quad\text{ and }s\triangleq b^{:B}\rightarrow q(\bbnum 0+b)\\ -\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\Gamma,C\vdash D}{\Gamma,{\color{blue}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\quad & \quad\text{Proof}\,(\Gamma,(A\Rightarrow B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:\left(A\rightarrow B\right)\rightarrow C}}\\ +\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\Gamma,C\vdash D}{\Gamma,{\color{red}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\quad & \quad\text{Proof}\,(\Gamma,(A\Rightarrow B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:\left(A\rightarrow B\right)\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,C\vdash D)_{\text{given }p,c}\\ & \quad\quad\text{ where}~c^{:C}\triangleq q\big(\text{Proof}\,(\Gamma,\\ & \quad\quad\quad\quad\quad\quad\quad\quad B\Rightarrow C\vdash A\Rightarrow B)_{\text{given }p,r}\big)\\ @@ -12159,7 +14019,7 @@ literal "false" \family default shows that the LJT algorithm terminates by giving an explicit decreasing - measure on proof trees. + measure on sequents. \end_layout \end_inset @@ -12278,7 +14138,7 @@ proof transformer Examples of proof transformer functions: \begin_inset Formula \begin{align*} -\frac{\Gamma,A\vdash C\quad\;\Gamma,B\vdash C}{\Gamma,{\color{blue}A+B}\vdash C}\,L+\\ +\frac{\Gamma,A\vdash C\quad\;\Gamma,B\vdash C}{\Gamma,{\color{red}A+B}\vdash C}\,L+\\ PT_{L+}(t_{1}^{A\rightarrow C},t_{2}^{B\rightarrow C})=x^{A+B}\rightarrow & \ x\ \text{match}\begin{cases} a^{A}\rightarrow t_{1}(a)\\ b^{B}\rightarrow t_{2}(b) @@ -12290,7 +14150,7 @@ b^{B}\rightarrow t_{2}(b) \begin_inset Formula \begin{align*} -\frac{\Gamma,A\rightarrow B\rightarrow C\vdash D}{\Gamma,{\color{blue}(A\times B)\rightarrow C}\vdash D}\,L\rightarrow_{2}\\ +\frac{\Gamma,A\rightarrow B\rightarrow C\vdash D}{\Gamma,{\color{red}(A\times B)\rightarrow C}\vdash D}\,L\rightarrow_{2}\\ PT_{L\rightarrow_{2}}(f^{\left(A\rightarrow B\rightarrow C\right)\rightarrow D})=g^{A\times B\rightarrow C}\rightarrow & f\,(x^{A}\rightarrow y^{B}\rightarrow g(x,y)) \end{align*} @@ -12591,8 +14451,8 @@ truth table. \end_layout \begin_layout Standard -Disjunction, conjunction, negation, and implication operations have the - following truth table: +Disjunction, conjunction, negation, and implication operations are described + by this truth table: \end_layout \begin_layout Standard @@ -13708,7 +15568,7 @@ status open \begin_layout Plain Layout -def f[A, B](x: A): Either[A, B] = Left(x) +def f[A,B](x: A): Either[A,B] = Left(x) \end_layout \end_inset @@ -14167,443 +16027,99 @@ name "tab:Logical-formulas-not-Boolean-theorems" \end_layout \begin_layout Standard -At first sight, it may appear from these examples that whenever a logical - formula is true in Boolean logic, the corresponding type signature can - be implemented in code, and vice versa. +At first sight, it may appear from these examples that whenever a formula + is true in Boolean logic, the corresponding type signature can be implemented + in code, and vice versa. However, this is \emph on incorrect \emph default : the rules of Boolean logic are not fully suitable for reasoning about types in a functional language. - We will now show some examples of formulas that are true in Boolean logic - but correspond to unimplementable type signatures. -\end_layout - -\begin_layout Standard -The first example is given by the following type: -\begin_inset Formula -\begin{equation} -\forall(A,B,C).\,\left(A\rightarrow B+C\right)\rightarrow\left(A\rightarrow B\right)+\left(A\rightarrow C\right)\quad,\label{eq:ch-example-boolean-bad-type} -\end{equation} - -\end_inset - -which corresponds to the Scala type signature (shown in Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Motivation-and-outlook" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -): -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def bad2[A, B, C](g: A => Either[B, C]): Either[A => B, A => C] = ??? -\end_layout - -\end_inset - -The function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -bad2 -\end_layout - -\end_inset - - + False Boolean formulas do correspond to unimplementable type signatures. + But \emph on -cannot +not all \emph default - be implemented via fully parametric code. - To see why, consider that the only available data is a function -\begin_inset Formula $g^{:A\rightarrow B+C}$ -\end_inset - -, which returns values of type -\begin_inset Formula $B$ -\end_inset - - or -\begin_inset Formula $C$ -\end_inset - - depending (in some unknown way) on the input value of type -\begin_inset Formula $A$ -\end_inset - -. - The function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -bad2 -\end_layout - -\end_inset - - must return either a function of type -\begin_inset Formula $A\rightarrow B$ -\end_inset - - or a function of type -\begin_inset Formula $A\rightarrow C$ -\end_inset - -. - How can the code of + true Boolean formulas correspond to implementable function types. + An example is the function \begin_inset listings inline true status open \begin_layout Plain Layout -bad2 -\end_layout - -\end_inset - - make that decision? The only input data is the function -\begin_inset Formula $g$ -\end_inset - - that takes an argument of type -\begin_inset Formula $A$ -\end_inset - -. - We could imagine applying -\begin_inset Formula $g$ -\end_inset - - to various arguments of type -\begin_inset Formula $A$ -\end_inset - - and to see whether -\begin_inset Formula $g$ -\end_inset - - returns a -\begin_inset Formula $B$ -\end_inset - - or a -\begin_inset Formula $C$ -\end_inset - -. - However, the type -\begin_inset Formula $A$ -\end_inset - - is arbitrary, and a fully parametric function cannot produce a value of - type -\begin_inset Formula $A$ -\end_inset - - in order to apply -\begin_inset Formula $g$ -\end_inset - - to it. - So, the decision about whether to return -\begin_inset Formula $A\rightarrow B$ -\end_inset - - or -\begin_inset Formula $A\rightarrow C$ -\end_inset - - must be independent of -\begin_inset Formula $g$ -\end_inset - -. - That decision must be hard-coded in the function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -bad2 -\end_layout - -\end_inset - -. -\end_layout - -\begin_layout Standard -Suppose we hard-coded the decision to return a function of type -\begin_inset Formula $A\rightarrow B$ -\end_inset - -. - How would we create a function of type -\begin_inset Formula $A\rightarrow B$ -\end_inset - - in the body of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -bad2 +bad3 \end_layout \end_inset -? Given a value -\begin_inset Formula $x^{:A}$ -\end_inset - - of type -\begin_inset Formula $A$ -\end_inset - -, we would need to compute some value of type -\begin_inset Formula $B$ -\end_inset - -. - Since the type -\begin_inset Formula $B$ -\end_inset - - is arbitrary (it is a type parameter), we cannot produce a value of type - -\begin_inset Formula $B$ -\end_inset - - from scratch. - The only potential source of values of type -\begin_inset Formula $B$ -\end_inset - - is the given function -\begin_inset Formula $g$ -\end_inset - -. - The only way of using -\begin_inset Formula $g$ -\end_inset - - is to apply it to -\begin_inset Formula $x^{:A}$ -\end_inset - -. - However, for some -\begin_inset Formula $x$ -\end_inset - -, the value -\begin_inset Formula $g(x)$ + shown in Section +\begin_inset space ~ \end_inset - may be of the form -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout -Right(c) -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Motivation-and-outlook" +plural "false" +caps "false" +noprefix "false" \end_inset -, where +: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -c +def bad3[A, B, C](g: A => Either[B, C]): Either[A => B, A => C] = ??? \end_layout \end_inset - is of type -\begin_inset Formula $C$ -\end_inset - -. - In that case, we will have a value of type -\begin_inset Formula $C$ -\end_inset - -, not -\begin_inset Formula $B$ -\end_inset - -. - So, in general, we cannot guarantee that we can always obtain a value of - type -\begin_inset Formula $B$ -\end_inset - - from a given value -\begin_inset Formula $x^{:A}$ -\end_inset - -. - This means we cannot build a function of type -\begin_inset Formula $A\rightarrow B$ -\end_inset - - out of the function -\begin_inset Formula $g$ -\end_inset - -. - Similarly, we cannot build a function of type -\begin_inset Formula $A\rightarrow C$ -\end_inset - - out of -\begin_inset Formula $g$ -\end_inset -. - -\end_layout - -\begin_layout Standard -Whether we decide to return -\begin_inset Formula $A\rightarrow B$ -\end_inset +\begin_inset Formula +\begin{equation} +\forall(A,B,C).\,\left(A\rightarrow B+C\right)\rightarrow\left(A\rightarrow B\right)+\left(A\rightarrow C\right)\quad,\label{eq:ch-example-boolean-bad-type} +\end{equation} - or -\begin_inset Formula $A\rightarrow C$ \end_inset -, we will not be able to return a value of the required type, as we just - saw. - We must conclude that we cannot implement +The function \begin_inset listings inline true status open \begin_layout Plain Layout -bad -\end_layout - -\end_inset - - as a fully parametric function. +bad3 \end_layout -\begin_layout Standard -We could try to switch between -\begin_inset Formula $A\rightarrow B$ -\end_inset - - and -\begin_inset Formula $A\rightarrow C$ \end_inset - depending on a given value of type -\begin_inset Formula $A$ -\end_inset - -. - This idea, however, means that we are working with a different type signature: -\begin_inset Formula -\[ -\forall(A,B,C).\,\left(A\rightarrow B+C\right)\rightarrow A\rightarrow\left(A\rightarrow B\right)+\left(A\rightarrow C\right)\quad. -\] - -\end_inset - -This type signature \emph on -can +cannot \emph default - be implemented, for instance, by this Scala code: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def q[A, B, C](g: A => Either[B, C]): A => Either[A => B, A => C] = { a - => -\end_layout - -\begin_layout Plain Layout - - g(a) match { -\end_layout - -\begin_layout Plain Layout - - case Left(b) => Left(_ => b) -\end_layout - -\begin_layout Plain Layout - - case Right(c) => Right(_ => c) -\end_layout - -\begin_layout Plain Layout - - } -\end_layout - -\begin_layout Plain Layout - -} -\end_layout - -\end_inset - -But this is not the required type signature + be implemented via fully parametric code, as we already discussed in Section \begin_inset space ~ \end_inset -( + \begin_inset CommandInset ref LatexCommand ref -reference "eq:ch-example-boolean-bad-type" +reference "subsec:Motivation-and-outlook" plural "false" caps "false" noprefix "false" \end_inset -). -\end_layout - -\begin_layout Standard -Now let us convert the type signature +. + Now, the type signature \begin_inset space ~ \end_inset @@ -14617,7 +16133,7 @@ noprefix "false" \end_inset -) into a +) gives this \begin_inset Formula ${\cal CH}$ \end_inset @@ -14676,33 +16192,19 @@ noprefix "false" \end_inset -) using the rules of Boolean logic, such as Eq. -\begin_inset space ~ -\end_inset - -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-definition-of-implication-in-Boolean-logic" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -): +) using the rules of Boolean logic: \begin_inset Formula \begin{align*} & \gunderline{\alpha\Rightarrow}\left(\beta\vee\gamma\right)\\ \text{definition of }\Rightarrow\text{ via Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad,\\ & \gunderline{\left(\alpha\Rightarrow\beta\right)}\vee\gunderline{\left(\alpha\Rightarrow\gamma\right)}\\ \text{definition of }\Rightarrow\text{ via Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:\quad & \quad=\gunderline{(\neg\alpha)}\vee\beta\vee\gunderline{(\neg\alpha)}\vee\gamma\\ -\text{property }x\vee x=x\text{ in Boolean logic}:\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad, +\text{property }x\vee x=x\text{ in Boolean logic}:\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad. \end{align*} \end_inset -showing that +So, \begin_inset Formula $\alpha\Rightarrow(\beta\vee\gamma)$ \end_inset @@ -14763,8 +16265,8 @@ noprefix "false" \end_inset . - A disjunction can be false only when both parts are false; so we must have - both + A disjunction can be false only when both parts are false. + So, we must have both \begin_inset Formula $\left(\alpha\Rightarrow\beta\right)=False$ \end_inset @@ -15632,7 +17134,7 @@ f1 andThen f2 \end_inset . - This is the same as to say that the data types + In other words, the data types \begin_inset Formula $P$ \end_inset @@ -15640,15 +17142,7 @@ f1 andThen f2 \begin_inset Formula $Q$ \end_inset - -\begin_inset Quotes eld -\end_inset - -carry equivalent information -\begin_inset Quotes erd -\end_inset - -. + carry equivalent information. \end_layout \begin_layout Standard @@ -16651,7 +18145,7 @@ noprefix "false" ) into the type equation: \begin_inset Formula \begin{equation} -\forall(A,B,C).\,\left(A\times B\right)+C=\left(A+C\right)\times\left(B+C\right)\quad.\label{eq:ch-example-incorrect-identity-2} +\forall(A,B,C).\,\left(A\times B\right)+C\overset{?}{=}\left(A+C\right)\times\left(B+C\right)\quad.\label{eq:ch-example-incorrect-identity-2} \end{equation} \end_inset @@ -17079,9 +18573,9 @@ noprefix "false" \end_layout \begin_layout Standard -Because we chose the type notation to be similar to the ordinary arithmetic - notation, it is easy to translate a possible type equivalence into an arithmeti -c equation. +Because the type notation is similar to the ordinary arithmetic notation, + it is easy to translate a possible type equivalence into an arithmetic + equation. In all cases, valid arithmetic identities correspond to type equivalences, and failures to obtain a type equivalence correspond to incorrect arithmetic identities. @@ -17765,759 +19259,387 @@ status open \end_inset (denoted by -\begin_inset Formula $\bbnum 0\times A$ -\end_inset - -) and -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Nothing -\end_layout - -\end_inset - - (denoted by -\begin_inset Formula $\bbnum 0$ -\end_inset - -) are both void and therefore equivalent. -\end_layout - -\begin_layout Subsubsection -Example -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Example-0-plus-A" - -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Example-0-plus-A" -plural "false" -caps "false" -noprefix "false" - -\end_inset - - -\end_layout - -\begin_layout Standard -Verify the type equivalence -\begin_inset Formula $\bbnum 0+A\cong A$ -\end_inset - -. -\end_layout - -\begin_layout Subparagraph -Solution -\end_layout - -\begin_layout Standard -The type notation -\begin_inset Formula $\bbnum 0+A$ -\end_inset - - corresponds to the Scala type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Either[Nothing, A] -\end_layout - -\end_inset - -. - We need to show that any value of that type can be mapped without loss - of information to a value of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A -\end_layout - -\end_inset - -, and vice versa. - This means implementing functions -\begin_inset Formula $f_{1}:\bbnum 0+A\rightarrow A$ -\end_inset - - and -\begin_inset Formula $f_{2}:A\rightarrow\bbnum 0+A$ -\end_inset - - such that -\begin_inset Formula $f_{1}\bef f_{2}=\text{id}$ -\end_inset - - and -\begin_inset Formula $f_{2}\bef f_{1}=\text{id}$ -\end_inset - -. -\end_layout - -\begin_layout Standard -The argument of -\begin_inset Formula $f_{1}$ -\end_inset - - is of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Either[Nothing, A] -\end_layout - -\end_inset - -. - How can we create a value of that type? Our only choices are to create - a -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Left(x) -\end_layout - -\end_inset - - with -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -x:Nothing -\end_layout - -\end_inset - -, or to create a -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Right(y) -\end_layout - -\end_inset - - with -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -y:A -\end_layout - -\end_inset - -. - However, we cannot create a value -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -x -\end_layout - -\end_inset - - of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Nothing -\end_layout - -\end_inset - - because the type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Nothing -\end_layout - -\end_inset - - has -\emph on -no -\emph default - values. - We cannot create a -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Left(x) -\end_layout - -\end_inset - -. - The only remaining possibility is to create a -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Right(y) -\end_layout - -\end_inset - - with some value -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -y -\end_layout - -\end_inset - - of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A -\end_layout - -\end_inset - -. - So, any values of type -\begin_inset Formula $\bbnum 0+A$ -\end_inset - - must be of the form -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -Right(y) -\end_layout - -\end_inset - -, and we can extract that -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -y -\end_layout - -\end_inset - - to obtain a value of type -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -A -\end_layout - -\end_inset - -: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -def f1[A]: Either[Nothing, A] => A = { -\end_layout - -\begin_layout Plain Layout - - case Right(y) => y -\end_layout - -\begin_layout Plain Layout - - // No need for `case Left(x) => ...` since no `x` can ever be given as `Left(x)`. -\end_layout - -\begin_layout Plain Layout - -} -\end_layout - -\end_inset - -For the same reason, there is only one implementation of the function -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -f2 -\end_layout - +\begin_inset Formula $\bbnum 0\times A$ \end_inset -: +) and \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def f2[A]: A => Either[Nothing, A] = { y => Right(y) } +Nothing \end_layout \end_inset -It is clear from the code that the functions -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout + (denoted by +\begin_inset Formula $\bbnum 0$ +\end_inset -f1 +) are both void and therefore equivalent. \end_layout +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Example-0-plus-A" + \end_inset - and -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-0-plus-A" +plural "false" +caps "false" +noprefix "false" + +\end_inset + -f2 \end_layout +\begin_layout Standard +Verify the type equivalence +\begin_inset Formula $\bbnum 0+A\cong A$ \end_inset - are inverses of each other. +. +\end_layout + +\begin_layout Subparagraph +Solution \end_layout \begin_layout Standard -We have just seen that a value of type +The type notation \begin_inset Formula $\bbnum 0+A$ \end_inset - is a + corresponds to the Scala type \begin_inset listings inline true status open \begin_layout Plain Layout -Right(y) +Either[Nothing, A] \end_layout \end_inset - with some +. + We need to show that any value of that type can be mapped without loss + of information to a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -y: A +A \end_layout \end_inset -. - Similarly, a value of type -\begin_inset Formula $A+\bbnum 0$ +, and vice versa. + This means implementing functions +\begin_inset Formula $f_{1}:\bbnum 0+A\rightarrow A$ \end_inset - is always a -\begin_inset listings -inline true -status open + and +\begin_inset Formula $f_{2}:A\rightarrow\bbnum 0+A$ +\end_inset -\begin_layout Plain Layout + such that +\begin_inset Formula $f_{1}\bef f_{2}=\text{id}$ +\end_inset -Left(x) + and +\begin_inset Formula $f_{2}\bef f_{1}=\text{id}$ +\end_inset + +. \end_layout +\begin_layout Standard +The argument of +\begin_inset Formula $f_{1}$ \end_inset - with some + is of type \begin_inset listings inline true status open \begin_layout Plain Layout -x: A +Either[Nothing, A] \end_layout \end_inset . - So, we will use the notation -\begin_inset Formula $A+\bbnum 0$ -\end_inset - - and -\begin_inset Formula $\bbnum 0+A$ -\end_inset - - to -\emph on -denote -\emph default - the + How can we create a value of that type? Our only choices are to create + a \begin_inset listings inline true status open \begin_layout Plain Layout -Left +Left(x) \end_layout \end_inset - and the + with \begin_inset listings inline true status open \begin_layout Plain Layout -Right +x: Nothing \end_layout \end_inset - parts of the disjunctive type +, or to create a \begin_inset listings inline true status open \begin_layout Plain Layout -Either +Right(y) \end_layout \end_inset -. - This notation agrees with the behavior of the Scala compiler, which will - infer the types + with \begin_inset listings inline true status open \begin_layout Plain Layout -Either[A, Nothing] +y: A \end_layout \end_inset -or +. + However, we cannot create a value \begin_inset listings inline true status open \begin_layout Plain Layout -Either[Nothing, A] +x \end_layout \end_inset - for these parts: + of type \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def toLeft[A, B]: A => Either[A, B] = x => Left(x) -\end_layout - -\begin_layout Plain Layout - -def toRight[A, B]: B => Either[A, B] = y => Right(y) +Nothing \end_layout -\begin_layout Plain Layout +\end_inset -\end_layout + because the type +\begin_inset listings +inline true +status open \begin_layout Plain Layout -scala> toLeft(123) +Nothing \end_layout -\begin_layout Plain Layout +\end_inset -res0: Either[Int, Nothing] = Left(123) -\end_layout + has +\emph on +no +\emph default + values. + We cannot create a +\begin_inset listings +inline true +status open \begin_layout Plain Layout +Left(x) \end_layout -\begin_layout Plain Layout - -scala> toRight( -\begin_inset Quotes eld -\end_inset - -abc -\begin_inset Quotes erd \end_inset -) -\end_layout +. + The only remaining possibility is to create a +\begin_inset listings +inline true +status open \begin_layout Plain Layout -res1: Either[Nothing, String] = Right("abc") +Right(y) \end_layout \end_inset -We can write the functions + with some value \begin_inset listings inline true status open \begin_layout Plain Layout -toLeft +y \end_layout \end_inset - and + of type \begin_inset listings inline true status open \begin_layout Plain Layout -toRight +A \end_layout \end_inset - in a code notation as: -\begin_inset Formula -\[ -\text{toLeft}^{A,B}\triangleq x^{:A}\rightarrow x+\bbnum 0^{:B}\quad,\quad\quad\text{toRight}^{A,B}\triangleq y^{:B}\rightarrow\bbnum 0^{:A}+y\quad. -\] - +. + So, any values of type +\begin_inset Formula $\bbnum 0+A$ \end_inset -In this notation, a value of the disjunctive type is shown without using - Scala class names such as + must be of the form \begin_inset listings inline true status open \begin_layout Plain Layout -Either +Right(y) \end_layout \end_inset -, +, and we can extract that \begin_inset listings inline true status open \begin_layout Plain Layout -Right +y \end_layout \end_inset -, and + to obtain a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -Left +A \end_layout \end_inset -. - This shortens the writing and speeds up code reasoning. - -\end_layout +: +\begin_inset listings +inline false +status open -\begin_layout Standard -The type annotation -\begin_inset Formula $\bbnum 0^{:A}$ -\end_inset +\begin_layout Plain Layout - is helpful to remind ourselves about the type parameter -\begin_inset Formula $A$ -\end_inset +def f1[A]: Either[Nothing, A] => A = { +\end_layout - used, e.g., by the disjunctive value -\begin_inset Formula $\bbnum 0^{:A}+y^{:B}$ -\end_inset +\begin_layout Plain Layout - in the body of -\begin_inset listings -inline true -status open + case Right(y) => y +\end_layout \begin_layout Plain Layout -toRight[A, B] + // No need for `case Left(x) => ...` since no `x` can ever be given as `Left(x)`. \end_layout -\end_inset +\begin_layout Plain Layout + +} +\end_layout -. - Without this type annotation, -\begin_inset Formula $\bbnum 0+y^{:B}$ \end_inset - means a value of type +For the same reason, there is only one implementation of the function \begin_inset listings inline true status open \begin_layout Plain Layout -Either[A, B] +f2 \end_layout \end_inset - where the parameter -\begin_inset Formula $A$ -\end_inset - - should be determined by matching the types of other expressions. - When it is clear what types are being used, we may omit type annotations - and write simply -\begin_inset Formula $\bbnum 0+y$ -\end_inset +: +\begin_inset listings +inline false +status open - instead of -\begin_inset Formula $\bbnum 0^{:A}+y^{:B}$ -\end_inset +\begin_layout Plain Layout -. +def f2[A]: A => Either[Nothing, A] = { y => Right(y) } \end_layout -\begin_layout Standard -In the notation -\begin_inset Formula $\bbnum 0+y^{:B}$ -\end_inset - -, we use the symbol -\begin_inset Formula $\bbnum 0$ \end_inset - rather than an ordinary zero ( -\begin_inset Formula $0$ -\end_inset +It is clear from the code that the functions +\begin_inset listings +inline true +status open -), to avoid suggesting that -\begin_inset Formula $0$ -\end_inset +\begin_layout Plain Layout - is a value of type -\begin_inset Formula $\bbnum 0$ -\end_inset +f1 +\end_layout -. - The void type -\begin_inset Formula $\bbnum 0$ \end_inset - has -\emph on -no -\emph default - values, unlike the + and \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +f2 \end_layout \end_inset - type, -\begin_inset Formula $\bbnum 1$ -\end_inset - -, which has a value denoted by -\begin_inset Formula $1$ -\end_inset - - in the code notation. + are inverses of each other. \end_layout \begin_layout Subsubsection @@ -18844,7 +19966,7 @@ status open \begin_layout Plain Layout -a:A +a: A \end_layout \end_inset @@ -19146,7 +20268,7 @@ Since both the argument and the result of \begin_inset Formula $2$ \end_inset - parts each, it is convenient to write the code of + parts each, the code notation represents \begin_inset Formula $f_{1}$ \end_inset @@ -19163,7 +20285,7 @@ matrix status open \begin_layout Plain Layout -disjunctive type!in matrix notation +disjunctive type!matrix notation \end_layout \end_inset @@ -19217,22 +20339,7 @@ B & b^{:B}\rightarrow b & \bbnum 0 \end_inset -The rows of the matrix correspond to the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -case -\end_layout - -\end_inset - rows in the Scala code. - There is one row for each part of the disjunctive type of the argument. - The columns of the matrix correspond to the parts of the disjunctive type - of the result. \begin_inset Index idx status open @@ -19250,7 +20357,11 @@ pattern matching!in matrix notation \begin_inset Formula $A$ \end_inset - is a function of type + is a function +\begin_inset Formula $a^{:A}\rightarrow a$ +\end_inset + + of type \begin_inset Formula $A\rightarrow A$ \end_inset @@ -19280,31 +20391,28 @@ case Left(a) => Right(a) \end_inset because no value of that type is returned. - In this way, we translate all lines of the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -match -\end_layout + The matrix row +\begin_inset Formula $B$ +\end_inset + contains just the function +\begin_inset Formula $b^{:B}\rightarrow b$ \end_inset -/ -\begin_inset listings -inline true -status open + in the first column. + In the second column, row +\begin_inset space ~ +\end_inset -\begin_layout Plain Layout -case -\end_layout +\begin_inset Formula $B$ +\end_inset + contains a +\begin_inset Formula $\bbnum 0$ \end_inset - expression into a code matrix. +. \end_layout \begin_layout Standard @@ -19314,10 +20422,6 @@ The code of is written similarly. Let us rename arguments for clarity: -\begin_inset space \hfill{} -\end_inset - - \begin_inset listings inline false status open @@ -19475,7 +20579,7 @@ x^{:A}\rightarrow x & \bbnum 0 \end_inset -The identity function is represented by the diagonal matrix: +The identity function is represented by this diagonal matrix: \begin_inset Formula $\,\begin{array}{||cc|} \text{id} & \bbnum 0\\ \bbnum 0 & \text{id} @@ -19668,9 +20772,87 @@ To understand why type equivalences are related to arithmetic identities, consider the question of how many different values a given type can have. \end_layout +\begin_layout Standard +For a given type +\begin_inset Formula $A$ +\end_inset + +, let us denote by +\begin_inset Formula $\left|A\right|$ +\end_inset + + the number of distinct values of type +\begin_inset Formula $A$ +\end_inset + +. + The number +\begin_inset Formula $\left|A\right|$ +\end_inset + + is called the +\begin_inset Index idx +status open + +\begin_layout Plain Layout +cardinality +\end_layout + +\end_inset + + +\series bold +cardinality +\series default + of type +\begin_inset Formula $A$ +\end_inset + +. + This is the same as the number of elements in the set of all values of + type +\begin_inset Formula $A$ +\end_inset + +. + +\begin_inset Note Note +status collapsed + +\begin_layout Plain Layout +Since any computer's memory is finite, there will be +\emph on +finitely +\emph default + many different values of a given type +\begin_inset Formula $A$ +\end_inset + + that can exist in the computer. + So, we may assume that +\begin_inset Formula $\left|A\right|$ +\end_inset + + is always a finite integer value. + This assumption will simplify our reasoning. + We will not actually need to compute the precise number of, say, all the + different possible strings. + It is sufficient to know that the set of all strings is finite, so that + we can denote its cardinality by +\begin_inset Formula $|\text{String}|$ +\end_inset + +. +\end_layout + +\end_inset + + +\end_layout + \begin_layout Standard Begin by counting the number of distinct values for simple types. - For example, the + We find that the \begin_inset listings inline true status open @@ -19776,7 +20958,7 @@ List[Char] \end_inset . - However, each computer's memory is limited, so there will exist a maximum + In practice, each computer's memory is limited, so there will exist a maximum length for values of type \begin_inset listings inline true @@ -19790,76 +20972,70 @@ String \end_inset . - So, the total number of possible different strings will be finite (but - will depend on the computer). -\end_layout + So, the total number of possible different strings will be finite, depending + on the computer. + Similarly, the set of all possible values of type +\begin_inset listings +inline true +status open -\begin_layout Standard -For a given type -\begin_inset Formula $A$ -\end_inset +\begin_layout Plain Layout -, let us denote by -\begin_inset Formula $\left|A\right|$ -\end_inset +List[Int] +\end_layout - the number of distinct values of type -\begin_inset Formula $A$ \end_inset -. - The number -\begin_inset Formula $\left|A\right|$ -\end_inset + will be a finite set. +\end_layout - is called the -\begin_inset Index idx +\begin_layout Standard +But this introduces an arbitrary limit on the total size of data, which + is inconvenient for reasoning about programs. + For instance, string concatenation and list concatenation will become partial + functions; those operations will fail when the total size of the result + is larger than the memory limit. + It is more convenient to imagine a computer with an infinite array of memory + locations. + On that computer, each program is still only allowed to use a finite amount + of memory, but that amount is not limited in advance. + Then all basic operations on data types become total functions; for example, + the concatenation of any two strings is always well-defined. +\end_layout + +\begin_layout Standard +In the model of an infinite computer, the set of all possible strings will + be a countably infinite set consisting of all possible character sequences + (where characters come from a finite set). + Similarly, the set of all possible values of type +\begin_inset listings +inline true status open \begin_layout Plain Layout -cardinality + +List[Int] \end_layout \end_inset - -\series bold -cardinality -\series default - of type + will be a countably infinite set. + This makes it difficult to reason about the total number of values of a + given type. + So, for the purposes of this section, we will limit our consideration to + types \begin_inset Formula $A$ \end_inset -. - This is the same as the number of elements in the set of all values of - type -\begin_inset Formula $A$ +, +\begin_inset Formula $B$ \end_inset -. - Since any computer's memory is finite, there will be +, ..., that have \emph on -finitely +finite \emph default - many different values of a given type -\begin_inset Formula $A$ -\end_inset - - that can exist in the computer. - So, we may assume that -\begin_inset Formula $\left|A\right|$ -\end_inset - - is always a finite integer value. - This assumption will simplify our reasoning. - We will not actually need to compute the precise number of, say, all the - different possible strings. - It is sufficient to know that the set of all strings is finite, so that - we can denote its cardinality by -\begin_inset Formula $|\text{String}|$ -\end_inset - -. + cardinalities. \end_layout \begin_layout Standard @@ -20867,7 +22043,7 @@ Type equivalence involving function types \begin_layout Standard Until now, we have looked at product types and disjunctive types. - We now turn to type constructions involving function types. + We now turn to type expressions involving function types. \end_layout \begin_layout Standard @@ -21030,9 +22206,9 @@ literal "false" \end_inset . - Since the code of a function is a string of bytes that needs to fit into + Since the code of a function is a list of bytes that needs to fit into the computer's memory, the number of implementable functions is no larger - than the number of possible byte strings. + than the number of possible byte lists. \end_layout \begin_layout Standard @@ -21041,7 +22217,24 @@ Nevertheless, the formula \end_inset is useful since it shows the number of distinct functions that are possible - in principle. + in principle, on an imaginary computer with infinite memory (although we + still need to limit our consideration to types +\begin_inset Formula $A$ +\end_inset + +, +\begin_inset Formula $B$ +\end_inset + + with finite cardinalities +\begin_inset Formula $\left|A\right|$ +\end_inset + +, +\begin_inset Formula $\left|B\right|$ +\end_inset + +). When types \begin_inset Formula $A$ \end_inset @@ -21830,13 +23023,13 @@ status open \begin_layout Plain Layout -x:A +x: A \end_layout \end_inset . - Using the code of + Use the code of \begin_inset listings inline true status open @@ -21860,7 +23053,7 @@ f2 \end_inset -, we get: + and get: \begin_inset listings inline false status open @@ -21896,7 +23089,7 @@ h: Unit => A \end_inset - in Scala code: +. \begin_inset listings inline false status open @@ -22516,7 +23709,7 @@ Show that \begin_inset Formula $A$ \end_inset - is an arbitrary type. + is an arbitrary unknown type. \end_layout \begin_layout Subparagraph @@ -22529,15 +23722,15 @@ To prove that two types are not \emph default equivalent, it is sufficient to show that their cardinalities are different. - Let us determine the cardinality of the type + Let us determine how the cardinality of the type \begin_inset Formula $A\rightarrow\bbnum 0$ \end_inset -, assuming that the cardinality of + depends on the cardinality of \begin_inset Formula $A$ \end_inset - is known. +. We note that a function of type, say, \begin_inset Formula $\text{Int}\rightarrow\bbnum 0$ \end_inset @@ -22563,8 +23756,7 @@ not \begin_inset Formula $\bbnum 0$ \end_inset -. - It follows that +.) It follows that \begin_inset Formula $\left|\text{Int}\rightarrow\bbnum 0\right|=0$ \end_inset @@ -23106,7 +24298,7 @@ status open \begin_layout Plain Layout -a:A +a: A \end_layout \end_inset @@ -23766,15 +24958,25 @@ match \end_layout \begin_layout Standard -Note that the function arrow ( +The function arrow ( \begin_inset Formula $\rightarrow$ \end_inset -) binds weaker than the pipe operation ( +) binds weaker than the pipe +\begin_inset Index idx +status open + +\begin_layout Plain Layout +pipe notation!operator precedence +\end_layout + +\end_inset + + operation ( \begin_inset Formula $\triangleright$ \end_inset -), so the code notation +), so the formula \begin_inset Formula $x\rightarrow y\triangleright z$ \end_inset @@ -23783,7 +24985,7 @@ Note that the function arrow ( \end_inset . - We will review the code notation more systematically in Chapter + We will review the pipe notation more systematically in Chapter \begin_inset space ~ \end_inset @@ -23886,7 +25088,7 @@ We denote by \begin_inset Formula $\left(a\times b\right)^{:A\times B}$ \end_inset - the argument of type + an argument of type \begin_inset listings inline true status open @@ -23899,8 +25101,8 @@ status open \end_inset with pattern matching implied. - This notation allows us to write shorter code formulas involving tupled - arguments. + This notation allows us to write shorter code formulas where tuples are + destructured. \end_layout \begin_layout Standard @@ -24038,7 +25240,7 @@ recursive \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" @@ -25301,7 +26503,15 @@ f_{1}\bef f_{2} & =\left(a_{1}\times a_{2}\rightarrow a_{1}\right)\bef\left(a\ri We have implemented all four type signatures as fully parametric functions, which shows that the corresponding logical formulas are all true (i.e., can be derived using the proof rules). - However, the functions cannot be inverses of each other. + However, the functions +\begin_inset Formula $f_{1}$ +\end_inset + + and +\begin_inset Formula $f_{2}$ +\end_inset + + are not inverses of each other. So, the type equivalences do not hold. \end_layout @@ -28228,31 +29438,395 @@ def flatMap[S, A, B]: State[S, A] => (A => State[S, B]) => State[S, B] = would lose information. \end_layout -\begin_layout Plain Layout +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + +In order to preserve information, we choose not to discard the computed + value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +s2 +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Standard +The code notation for this +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +flatMap +\end_layout + +\end_inset + + can be simplified to: +\begin_inset Formula +\[ +\text{flatMap}\triangleq t^{:S\rightarrow A\times S}\rightarrow f^{:A\rightarrow S\rightarrow B\times S}\rightarrow t\bef\left(a\times s\rightarrow f(a)(s)\right)\quad. +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Exercises +\begin_inset Index idx +status open + +\begin_layout Plain Layout +exercises +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-0" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-0" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Find the cardinality of the following Scala type: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +type P = Option[Boolean => Option[Boolean]] +\end_layout + +\end_inset + +Show that +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +P +\end_layout + +\end_inset + + is equivalent to +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Option[Boolean] => Boolean +\end_layout + +\end_inset + +, but the equivalence is accidental +\begin_inset Index idx +status open + +\begin_layout Plain Layout +type equivalence!accidental +\end_layout + +\end_inset + + and not +\begin_inset Quotes eld +\end_inset + +natural +\begin_inset Quotes erd +\end_inset + +. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-1-a" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-1-a" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Verify the type equivalences +\begin_inset Formula $A+A\cong\bbnum 2\times A$ +\end_inset + + and +\begin_inset Formula $A\times A\cong\bbnum 2\rightarrow A$ +\end_inset + +, where +\begin_inset Formula $\bbnum 2$ +\end_inset + + denotes the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Boolean +\end_layout + +\end_inset + + type. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Show that +\begin_inset Formula $\alpha\Rightarrow(\beta\vee\gamma)\neq(\alpha\Rightarrow\beta)\wedge(\alpha\Rightarrow\gamma)$ +\end_inset + + in constructive and Boolean logic. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-solvedExample-5-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-solvedExample-5-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Verify the type equivalence +\begin_inset Formula $\left(A\rightarrow B\times C\right)\cong\left(A\rightarrow B\right)\times\left(A\rightarrow C\right)$ +\end_inset + + with full proofs. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-type-identity-4" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-type-identity-4" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Use known rules to verify the type equivalences without need for proofs: +\end_layout + +\begin_layout Standard + +\series bold +(a) +\series default + +\begin_inset Formula $\left(A+B\right)\times\left(A\rightarrow B\right)\cong A\times\left(A\rightarrow B\right)+\left(\bbnum 1+A\rightarrow B\right)\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(b) +\series default + +\begin_inset Formula $\left(A\times(\bbnum 1+A)\rightarrow B\right)\cong\left(A\rightarrow B\right)\times\left(A\rightarrow A\rightarrow B\right)\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(c) +\series default + +\begin_inset Formula $A\rightarrow\left(\bbnum 1+B\right)\rightarrow C\times D\cong\left(A\rightarrow C\right)\times\left(A\rightarrow D\right)\times\left(A\times B\rightarrow C\right)\times\left(A\times B\rightarrow D\right)\quad.$ +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-2" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-2" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Write the type notation for +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Either[(A, Int), Either[(A, Char), (A, Float)]] +\end_layout + +\end_inset + +. + Transform this type into an equivalent type of the form +\begin_inset Formula $A\times(...)$ +\end_inset + +. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-3" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-3" +plural "false" +caps "false" +noprefix "false" + +\end_inset + -} \end_layout +\begin_layout Standard +Define a type +\begin_inset Formula $\text{OptE}^{T,A}\triangleq\bbnum 1+T+A$ \end_inset -In order to preserve information, we choose not to discard the computed - value + and implement information-preserving \begin_inset listings inline true status open \begin_layout Plain Layout -s2 +map \end_layout \end_inset -. -\end_layout - -\begin_layout Standard -The code notation for this + and \begin_inset listings inline true status open @@ -28264,28 +29838,37 @@ flatMap \end_inset - can be simplified to: -\begin_inset Formula -\[ -\text{flatMap}\triangleq t^{:S\rightarrow A\times S}\rightarrow f^{:A\rightarrow S\rightarrow B\times S}\rightarrow t\bef\left(a\times s\rightarrow f(a)(s)\right)\quad. -\] - + for it, applied to the type parameter +\begin_inset Formula $A$ \end_inset +. + Get the same result using the equivalent type +\begin_inset Formula $(\bbnum 1+A)+T$ +\end_inset -\end_layout - -\begin_layout Subsection -Exercises -\begin_inset Index idx +, i.e., +\begin_inset listings +inline true status open \begin_layout Plain Layout -exercises + +Either[Option[A], T] \end_layout \end_inset +. + The required type signatures are: +\begin_inset Formula +\begin{align*} +\text{map}^{A,B,T} & :\text{OptE}^{T,A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{OptE}^{T,B}\quad,\\ +\text{flatMap}^{A,B,T} & :\text{OptE}^{T,A}\rightarrow(A\rightarrow\text{OptE}^{T,B})\rightarrow\text{OptE}^{T,B}\quad. +\end{align*} + +\end_inset + \end_layout @@ -28293,14 +29876,14 @@ exercises Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:ch-Exercise-0" +name "subsec:ch-Exercise-4" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-Exercise-0" +reference "subsec:ch-Exercise-4" plural "false" caps "false" noprefix "false" @@ -28311,75 +29894,128 @@ noprefix "false" \end_layout \begin_layout Standard -Find the cardinality of the following Scala type: +Implement the \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -type P = Option[Boolean => Option[Boolean]] +map \end_layout \end_inset -Show that + function for the type constructor \begin_inset listings inline true status open \begin_layout Plain Layout -P +P[A] \end_layout \end_inset - is equivalent to -\begin_inset listings -inline true -status open + from Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-solvedExample-2" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + The required type signature is +\begin_inset Formula $P^{A}\rightarrow\left(A\rightarrow B\right)\rightarrow P^{B}$ +\end_inset + +. + Preserve information as much as possible. +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:ch-Exercise-4-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Exercise-4-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset -\begin_layout Plain Layout -Option[Boolean] => Boolean \end_layout +\begin_layout Standard +For the type constructor +\begin_inset Formula $Q^{T,A}$ \end_inset -, but the equivalence is accidental -\begin_inset Index idx + defined in Exercise +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-type-notation-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +, define the +\begin_inset listings +inline true status open \begin_layout Plain Layout -type equivalence!accidental + +map \end_layout \end_inset - and not -\begin_inset Quotes eld -\end_inset + function, preserving information as much as possible: +\begin_inset Formula +\[ +\text{map}^{T,A,B}:Q^{T,A}\rightarrow\left(A\rightarrow B\right)\rightarrow Q^{T,B}\quad. +\] -natural -\begin_inset Quotes erd \end_inset -. + \end_layout \begin_layout Subsubsection Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:ch-Exercise-1-a" +name "subsec:Exercise-disjunctive-6" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-Exercise-1-a" +reference "subsec:Exercise-disjunctive-6" plural "false" caps "false" noprefix "false" @@ -28390,45 +30026,45 @@ noprefix "false" \end_layout \begin_layout Standard -Verify the type equivalences -\begin_inset Formula $A+A\cong\bbnum 2\times A$ -\end_inset - - and -\begin_inset Formula $A\times A\cong\bbnum 2\rightarrow A$ +Define a recursive type constructor +\begin_inset Formula $\text{Tr}_{3}$ \end_inset -, where -\begin_inset Formula $\bbnum 2$ + as +\begin_inset Formula $\text{Tr}_{3}{}^{A}\triangleq\bbnum 1+A\times A\times A\times\text{Tr}_{3}{}^{A}$ \end_inset - denotes the + and implement the \begin_inset listings inline true status open \begin_layout Plain Layout -Boolean +map \end_layout \end_inset - type. + function for it, with the standard type signature: +\begin_inset Formula $\text{map}^{A,B}:\text{Tr}_{3}{}^{A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{Tr}_{3}{}^{B}\quad.$ +\end_inset + + \end_layout \begin_layout Subsubsection Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:ch-Exercise-1" +name "subsec:ch-Exercise-5" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-Exercise-1" +reference "subsec:ch-Exercise-5" plural "false" caps "false" noprefix "false" @@ -28439,25 +30075,178 @@ noprefix "false" \end_layout \begin_layout Standard -Show that -\begin_inset Formula $A\Rightarrow(B\vee C)\neq(A\Rightarrow B)\wedge(A\Rightarrow C)$ +Implement fully parametric, information-preserving functions with the following + type signatures: +\end_layout + +\begin_layout Standard + +\series bold +(a) +\series default + +\begin_inset Formula $\left(A\rightarrow B\rightarrow C\right)\rightarrow A\rightarrow B\rightarrow C\quad.$ \end_inset - in constructive and Boolean logic. + +\end_layout + +\begin_layout Standard + +\series bold +(b) +\series default + +\begin_inset Formula $\left(A\rightarrow C\right)\rightarrow\left(B\rightarrow D\right)\rightarrow A+B\rightarrow C+D\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(c) +\series default + +\begin_inset Formula $\left(A\rightarrow C\right)\rightarrow\left(B\rightarrow D\right)\rightarrow A\times B\rightarrow C\times D\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(d) +\series default + +\begin_inset Formula $((A\rightarrow A)\rightarrow A)\rightarrow A\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(e) +\series default + +\begin_inset Formula $\left(\left(A\rightarrow B\right)\rightarrow C\right)\rightarrow B\rightarrow C\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(f) +\series default + +\begin_inset Formula $((A\rightarrow B)\rightarrow A)\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(g) +\series default + +\begin_inset Formula $(A\rightarrow B+C)\rightarrow(B\rightarrow C)\rightarrow A\rightarrow C\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(h) +\series default + +\begin_inset Formula $(A+B\rightarrow C)\rightarrow(B\rightarrow C)\rightarrow A\rightarrow C\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(i) +\series default + +\begin_inset Formula $\text{Reader}^{E,A}\rightarrow(A\rightarrow\text{Reader}^{E,B})\rightarrow\text{Reader}^{E,B}\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(j) +\series default + +\begin_inset Formula $\text{Reader}^{E,A}\times\text{Reader}^{E,B}\rightarrow(A\times B\rightarrow C)\rightarrow\text{Reader}^{E,C}\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(k) +\series default + +\begin_inset Formula $\text{State}^{S,A}\rightarrow\left(S\times A\rightarrow B\right)\rightarrow\text{State}^{S,B}\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(l) +\series default + +\begin_inset Formula $A+Z\rightarrow B+Z\rightarrow(A\rightarrow B\rightarrow C)\rightarrow C+Z\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(m) +\series default + +\begin_inset Formula $P+A\times A\rightarrow(A\rightarrow B)\rightarrow(P\rightarrow A+Q)\rightarrow Q+B\times B\quad.$ +\end_inset + + \end_layout \begin_layout Subsubsection Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:ch-solvedExample-5-1" +name "subsec:ch-Exercise-7" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-solvedExample-5-1" +reference "subsec:ch-Exercise-7" plural "false" caps "false" noprefix "false" @@ -28468,25 +30257,49 @@ noprefix "false" \end_layout \begin_layout Standard -Verify the type equivalence -\begin_inset Formula $\left(A\rightarrow B\times C\right)\cong\left(A\rightarrow B\right)\times\left(A\rightarrow C\right)$ +Denote +\begin_inset Formula $\text{Cont}^{R,T}\triangleq\left(T\rightarrow R\right)\rightarrow R$ \end_inset - with full proofs. + and implement the functions: +\end_layout + +\begin_layout Standard + +\series bold +(a) +\series default + +\begin_inset Formula $\text{map}^{R,T,U}:\text{Cont}^{R,T}\rightarrow(T\rightarrow U)\rightarrow\text{Cont}^{R,U}\quad.$ +\end_inset + + +\end_layout + +\begin_layout Standard + +\series bold +(b) +\series default + +\begin_inset Formula $\text{flatMap}^{R,T,U}:\text{Cont}^{R,T}\rightarrow(T\rightarrow\text{Cont}^{R,U})\rightarrow\text{Cont}^{R,U}\quad.$ +\end_inset + + \end_layout \begin_layout Subsubsection Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:ch-Exercise-type-identity-4" +name "subsec:ch-Exercise-8" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-Exercise-type-identity-4" +reference "subsec:ch-Exercise-8" plural "false" caps "false" noprefix "false" @@ -28497,7 +30310,11 @@ noprefix "false" \end_layout \begin_layout Standard -Use known rules to verify the type equivalences without need for proofs: +Denote +\begin_inset Formula $\text{Sel}^{Z,T}\triangleq\left(T\rightarrow Z\right)\rightarrow T$ +\end_inset + + and implement the functions: \end_layout \begin_layout Standard @@ -28506,7 +30323,7 @@ Use known rules to verify the type equivalences without need for proofs: (a) \series default -\begin_inset Formula $\left(A+B\right)\times\left(A\rightarrow B\right)\cong A\times\left(A\rightarrow B\right)+\left(\bbnum 1+A\rightarrow B\right)\quad.$ +\begin_inset Formula $\text{map}^{Z,A,B}:\text{Sel}^{Z,A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{Sel}^{Z,B}\quad.$ \end_inset @@ -28518,1667 +30335,1658 @@ Use known rules to verify the type equivalences without need for proofs: (b) \series default -\begin_inset Formula $\left(A\times(\bbnum 1+A)\rightarrow B\right)\cong\left(A\rightarrow B\right)\times\left(A\rightarrow A\rightarrow B\right)\quad.$ +\begin_inset Formula $\text{flatMap}^{Z,A,B}:\text{Sel}^{Z,A}\rightarrow(A\rightarrow\text{Sel}^{Z,B})\rightarrow\text{Sel}^{Z,B}\quad.$ +\end_inset + + +\end_layout + +\begin_layout Section +Discussion and further developments +\begin_inset CommandInset label +LatexCommand label +name "sec:Discussion-curry-howard" + +\end_inset + + +\end_layout + +\begin_layout Subsection +Using the Curry-Howard correspondence for writing code +\end_layout + +\begin_layout Standard +This chapter focuses on two practically important reasoning tasks: checking + if a type signature can be implemented as a fully parametric function, + and determining whether two types are equivalent. + For the first task, we use the CH correspondence to map type expressions + into formulas in the constructive logic and then apply the proof rules + of that logic. + For the second task, we map type expressions into +\emph on +arithmetic +\emph default + formulas and apply the ordinary rules of arithmetic. +\end_layout + +\begin_layout Standard +Although tools such as the +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +curryhoward +\end_layout + +\end_inset + + library can sometimes derive code from types, it is beneficial if a programmer + is able to derive an implementation by hand or to determine that an implementat +ion is impossible. + For instance, the programmer should recognize that the type signature: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def f[A, B]: A => (A => B) => B +\end_layout + +\end_inset + +has only one fully parametric implementation, while the following two type + signatures have none: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def g[A, B]: A => (B => A) => B +\end_layout + +\begin_layout Plain Layout + +def h[A, B]: ((A => B) => A) => B +\end_layout + +\end_inset + +Exercises in this chapter help to build up the required technique and intuition. + The two main guidelines for code derivation are: +\begin_inset Quotes eld +\end_inset + +values of parametric types cannot be constructed from scratch +\begin_inset Quotes erd +\end_inset + + and +\begin_inset Quotes eld +\end_inset + +one must hard-code the decision to return a chosen part of a disjunctive + type when no other disjunctive value is given +\begin_inset Quotes erd +\end_inset + +. + These guidelines can be justified by referring to the rules of proof in + Table +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "tab:Proof-rules-for-constructive-logic" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + Sequents producing a value of type +\begin_inset Formula $A$ +\end_inset + + can be proved only if there is a premise containing +\begin_inset Formula $A$ +\end_inset + + or a function that returns a value of type +\begin_inset Formula $A$ +\end_inset + +. +\begin_inset Foot +status open + +\begin_layout Plain Layout +This is proved rigorously by R. +\begin_inset space ~ \end_inset +Dyckhoff +\begin_inset Index idx +status collapsed +\begin_layout Plain Layout +Roy Dyckhoff \end_layout -\begin_layout Standard - -\series bold -(c) -\series default - -\begin_inset Formula $A\rightarrow\left(\bbnum 1+B\right)\rightarrow C\times D\cong\left(A\rightarrow C\right)\times\left(A\rightarrow D\right)\times\left(A\times B\rightarrow C\right)\times\left(A\times B\rightarrow D\right)\quad.$ \end_inset + as the +\begin_inset Quotes eld +\end_inset -\end_layout +Theorem +\begin_inset Quotes erd +\end_inset -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-2" + in section 6 ( +\begin_inset Quotes eld +\end_inset +Goal-directed pruning +\begin_inset Quotes erd \end_inset +), see +\family typewriter -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-2" -plural "false" -caps "false" -noprefix "false" +\begin_inset CommandInset href +LatexCommand href +target "https://research-repository.st-andrews.ac.uk/handle/10023/8824" +literal "false" \end_inset \end_layout -\begin_layout Standard -Write the type notation for +\end_inset + + One can derive a disjunction without hard-coding only if one already has + a disjunction in the premises (and then the rule +\begin_inset Quotes eld +\end_inset + +use \begin_inset listings inline true status open \begin_layout Plain Layout -Either[(A, Int), Either[(A, Char), (A, Float)]] -\end_layout - -\end_inset - -. - Transform this type into an equivalent type of the form -\begin_inset Formula $A\times(...)$ -\end_inset - -. +Either \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-3" - \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-3" -plural "false" -caps "false" -noprefix "false" - +\begin_inset Quotes erd \end_inset - + could apply). \end_layout \begin_layout Standard -Define a type -\begin_inset Formula $\text{OptE}^{T,A}\triangleq\bbnum 1+T+A$ -\end_inset - - and implement information-preserving +Throughout this chapter, we require all code to be fully parametric. + This is because the CH correspondence gives useful, non-trivial results + only for parameterized types and fully parametric code. + For concrete, non-parameterized types ( \begin_inset listings inline true status open \begin_layout Plain Layout -map +Int \end_layout \end_inset - and +, \begin_inset listings inline true status open \begin_layout Plain Layout -flatMap +String \end_layout \end_inset - for it, applied to the type parameter -\begin_inset Formula $A$ +, etc.), one can always produce +\emph on +some +\emph default + values even with no previous data. + So, the propositions +\begin_inset Formula $\mathcal{CH}(\text{Int})$ \end_inset -. - Get the same result using the equivalent type -\begin_inset Formula $(\bbnum 1+A)+T$ + or +\begin_inset Formula $\mathcal{CH}(\text{String})$ \end_inset -, i.e., + are always true. +\end_layout + +\begin_layout Standard +Consider the function \begin_inset listings inline true status open \begin_layout Plain Layout -Either[Option[A], T] +(x: Int) => x + 1 \end_layout \end_inset . - The required type signatures are: -\begin_inset Formula -\begin{align*} -\text{map}^{A,B,T} & :\text{OptE}^{T,A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{OptE}^{T,B}\quad,\\ -\text{flatMap}^{A,B,T} & :\text{OptE}^{T,A}\rightarrow(A\rightarrow\text{OptE}^{T,B})\rightarrow\text{OptE}^{T,B}\quad. -\end{align*} - -\end_inset + Its type signature, +\begin_inset listings +inline true +status open +\begin_layout Plain Layout +Int => Int \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-4" - -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-4" -plural "false" -caps "false" -noprefix "false" - \end_inset - -\end_layout - -\begin_layout Standard -Implement the +, may be implemented by many other functions, such as \begin_inset listings inline true status open \begin_layout Plain Layout -map +x => x - 1 \end_layout \end_inset - function for the type constructor +, \begin_inset listings inline true status open \begin_layout Plain Layout -P[A] +x => x * 2 \end_layout \end_inset - from Example -\begin_inset space ~ -\end_inset +, etc. + So, the type signature +\begin_inset listings +inline true +status open +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-solvedExample-2" -plural "false" -caps "false" -noprefix "false" +Int => Int +\end_layout \end_inset -. - The required type signature is -\begin_inset Formula $P^{A}\rightarrow\left(A\rightarrow B\right)\rightarrow P^{B}$ + is insufficient to specify the code of the function, and deriving code + from that type is not a meaningful task. + Only a fully parametric type signature, such as +\begin_inset Formula $A\rightarrow\left(A\rightarrow B\right)\rightarrow B$ \end_inset -. - Preserve information as much as possible. +, could give enough information for deriving the function's code. + Additionally, we must require the code of functions to be fully parametric. + Otherwise we will be unable to reason about code derivation from type signature +s. \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-4-1" - +\begin_layout Standard +Validity of a +\begin_inset Formula ${\cal CH}$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-4-1" -plural "false" -caps "false" -noprefix "false" - +-proposition +\begin_inset Formula ${\cal CH}(T)$ \end_inset + means that we can implement +\emph on +some +\emph default + value of the given type +\begin_inset Formula $T$ +\end_inset +. + But this does not give any information about the properties of that value, + such as whether it satisfies any laws. + This is why type equivalence (which requires the laws of isomorphisms) + is not determined by an equivalence of logical formulas. \end_layout \begin_layout Standard -For the type constructor -\begin_inset Formula $Q^{T,A}$ +It is useful for programmers to be able to transform type expressions to + equivalent simpler types before starting to write code. + The type notation introduced in this book is designed to help programmers + to recognize patterns in type expressions and to reason about them more + easily. + We have shown that a type equivalence corresponds to +\emph on +each +\emph default + standard arithmetic identity such as +\begin_inset Formula $\left(a+b\right)+c=a+\left(b+c\right)$ \end_inset - defined in Exercise -\begin_inset space ~ +, +\begin_inset Formula $\left(a\times b\right)\times c=a\times(b\times c)$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Exercise-type-notation-1" -plural "false" -caps "false" -noprefix "false" - +, +\begin_inset Formula $1\times a=a$ \end_inset -, define the -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -map -\end_layout - +, +\begin_inset Formula $\left(a+b\right)\times c=a\times c+b\times c$ \end_inset - function, preserving information as much as possible: +, and so on. + Because of this, we are allowed to transform and simplify types as if they + were arithmetic expressions, e.g., to rewrite: \begin_inset Formula \[ -\text{map}^{T,A,B}:Q^{T,A}\rightarrow\left(A\rightarrow B\right)\rightarrow Q^{T,B}\quad. +\bbnum 1\times\left(A+B\right)\times C+D\cong D+A\times C+B\times C\quad. \] \end_inset - +The type notation makes this reasoning more intuitive. + \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:Exercise-disjunctive-6" - +\begin_layout Standard +These results apply to all type expressions built up using product types, + disjunctive types (also called +\begin_inset Quotes eld \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Exercise-disjunctive-6" -plural "false" -caps "false" -noprefix "false" - +sum +\begin_inset Quotes erd \end_inset - -\end_layout - -\begin_layout Standard -Define a recursive type constructor -\begin_inset Formula $\text{Tr}_{3}$ + types because they correspond to arithmetic sums), and function types (also + called +\begin_inset Quotes eld \end_inset - as -\begin_inset Formula $\text{Tr}_{3}{}^{A}\triangleq\bbnum 1+A\times A\times A\times\text{Tr}_{3}{}^{A}$ +exponential +\begin_inset Quotes erd \end_inset - and implement the -\begin_inset listings -inline true + types because they correspond to arithmetic exponentials). + Type expressions that contain only products and sum types are called +\series bold +polynomial +\series default + +\begin_inset Index idx status open \begin_layout Plain Layout - -map +polynomial type \end_layout \end_inset - function for it, with the standard type signature: -\begin_inset Formula $\text{map}^{A,B}:\text{Tr}_{3}{}^{A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{Tr}_{3}{}^{B}\quad.$ -\end_inset +\begin_inset Index idx +status open +\begin_layout Plain Layout +types!polynomial types \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-5" - \end_inset +. +\begin_inset Foot +status open -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-5" -plural "false" -caps "false" -noprefix "false" - +\begin_layout Plain Layout +These types are often called +\begin_inset Quotes eld \end_inset +algebraic data types +\begin_inset Index idx +status open +\begin_layout Plain Layout +algebraic data types \end_layout -\begin_layout Standard -Implement fully parametric, information-preserving functions with the following - type signatures: -\end_layout - -\begin_layout Standard - -\series bold -(a) -\series default - -\begin_inset Formula $\left(A\rightarrow B\rightarrow C\right)\rightarrow A\rightarrow B\rightarrow C\quad.$ \end_inset -\end_layout - -\begin_layout Standard +\begin_inset Quotes erd +\end_inset -\series bold -(b) -\series default - -\begin_inset Formula $\left(A\rightarrow C\right)\rightarrow\left(B\rightarrow D\right)\rightarrow A+B\rightarrow C+D\quad.$ + but this book prefers the more precise term +\begin_inset Quotes eld \end_inset +polynomial types +\begin_inset Quotes erd +\end_inset +. \end_layout -\begin_layout Standard +\end_inset + Type expressions that also contain function types are called \series bold -(c) +exponential-polynomial \series default - -\begin_inset Formula $\left(A\rightarrow C\right)\rightarrow\left(B\rightarrow D\right)\rightarrow A\times B\rightarrow C\times D\quad.$ -\end_inset +\begin_inset Index idx +status open +\begin_layout Plain Layout +exponential-polynomial type \end_layout -\begin_layout Standard - -\series bold -(d) -\series default - -\begin_inset Formula $((A\rightarrow A)\rightarrow A)\rightarrow A\quad.$ \end_inset -\end_layout +\begin_inset Index idx +status open -\begin_layout Standard +\begin_layout Plain Layout +types!exponential-polynomial types +\end_layout -\series bold -(e) -\series default - -\begin_inset Formula $\left(\left(A\rightarrow B\right)\rightarrow C\right)\rightarrow B\rightarrow C\quad.$ \end_inset - +. + We focus on exponential-polynomial types because they are sufficient for + almost all design patterns used in functional programming. \end_layout \begin_layout Standard +There are no types corresponding to subtraction or division, so arithmetic + equations such as: +\begin_inset Formula +\begin{align*} +\left(1-t\right)\times\left(1+t\right) & =1-t\times t\quad,\quad\text{ and }\quad\frac{t+t\times t}{t}=1+t\quad, +\end{align*} -\series bold -(f) -\series default - -\begin_inset Formula $((A\rightarrow B)\rightarrow A)\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad.$ \end_inset +do not directly yield any type equivalences. + However, consider this well-known formula: +\begin_inset Formula +\[ +\frac{1}{1-t}=1+t+t^{2}+t^{3}+...+t^{n}+...\quad. +\] -\end_layout +\end_inset -\begin_layout Standard +At first sight, this formula appears to involve subtraction, division, and + an infinite series, and so cannot be directly translated into a type equivalenc +e. + However, the formula can be rewritten as: +\begin_inset Formula +\begin{equation} +\frac{1}{1-t}=L(t)\quad\text{ where }\quad L(t)\triangleq1+t+t^{2}+t^{3}+...+t^{n}\times L(t)\quad.\label{eq:ch-example-type-formula-list} +\end{equation} -\series bold -(g) -\series default - -\begin_inset Formula $(A\rightarrow B+C)\rightarrow(B\rightarrow C)\rightarrow A\rightarrow C\quad.$ \end_inset +The definition of +\begin_inset Formula $L(t)$ +\end_inset -\end_layout + is finite and only contains additions and multiplications. + So, Eq. +\begin_inset space ~ +\end_inset -\begin_layout Standard +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-example-type-formula-list" +plural "false" +caps "false" +noprefix "false" -\series bold -(h) -\series default - -\begin_inset Formula $(A+B\rightarrow C)\rightarrow(B\rightarrow C)\rightarrow A\rightarrow C\quad.$ \end_inset +) can be translated into a type equivalence: +\begin_inset Formula +\begin{equation} +L^{A}\cong1+A+A\times A+A\times A\times A+...+\underbrace{A\times...\times A}_{n\text{ times}}\times\,L^{A}\quad.\label{eq:ch-example-type-expansion-list} +\end{equation} -\end_layout - -\begin_layout Standard +\end_inset -\series bold -(i) -\series default - -\begin_inset Formula $\text{Reader}^{E,A}\rightarrow(A\rightarrow\text{Reader}^{E,B})\rightarrow\text{Reader}^{E,B}\quad.$ +This type formula (with +\begin_inset Formula $n=1$ \end_inset +) is equivalent to a recursive definition of the type constructor +\begin_inset listings +inline true +status open -\end_layout +\begin_layout Plain Layout -\begin_layout Standard +List +\end_layout -\series bold -(j) -\series default - -\begin_inset Formula $\text{Reader}^{E,A}\times\text{Reader}^{E,B}\rightarrow(A\times B\rightarrow C)\rightarrow\text{Reader}^{E,C}\quad.$ \end_inset +: +\begin_inset Formula +\[ +\text{List}^{A}\triangleq1+A\times\text{List}^{A}\quad. +\] -\end_layout +\end_inset -\begin_layout Standard +The type equivalence +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:ch-example-type-expansion-list" +plural "false" +caps "false" +noprefix "false" -\series bold -(k) -\series default - -\begin_inset Formula $\text{State}^{S,A}\rightarrow\left(S\times A\rightarrow B\right)\rightarrow\text{State}^{S,B}\quad.$ \end_inset +) suggests that we may view the recursive type +\begin_inset listings +inline true +status open +\begin_layout Plain Layout + +List \end_layout -\begin_layout Standard +\end_inset -\series bold -(l) -\series default - -\begin_inset Formula $A+Z\rightarrow B+Z\rightarrow(A\rightarrow B\rightarrow C)\rightarrow C+Z\quad.$ + heuristically as an +\begin_inset Quotes eld \end_inset +infinite disjunction +\begin_inset Quotes erd +\end_inset + describing lists of zero, one, two, etc., elements. \end_layout -\begin_layout Standard +\begin_layout Subsection +Implications for designing new programming languages +\end_layout -\series bold -(m) -\series default - -\begin_inset Formula $P+A\times A\rightarrow(A\rightarrow B)\rightarrow(P\rightarrow A+Q)\rightarrow Q+B\times B\quad.$ +\begin_layout Standard +Today's functional programming practice assumes, at the minimum, that programmer +s will use the six standard type constructions (Section +\begin_inset space ~ \end_inset -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Type-notation-and-standard-type-constructions" +plural "false" +caps "false" +noprefix "false" -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-7" +\end_inset +) and the eight standard code constructions (Section +\begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:ch-Exercise-7" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" \end_inset - +). + 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 all of those constructions cannot + be considered a functional programming language. \end_layout \begin_layout Standard -Denote -\begin_inset Formula $\text{Cont}^{R,T}\triangleq\left(T\rightarrow R\right)\rightarrow R$ +A remarkable result of the CH correspondence is that the type system of + any given programming language (functional or not) is mapped into a +\emph on +certain +\emph default + +\emph on +logic +\emph default +, i.e., a system of logical operations and proof rules. + A logical operation will correspond to each of the +\emph on +type +\emph default + constructions available in the programming language. + A proof rule will correspond to each of the available +\emph on +code +\emph default + constructions. + Programming languages that support all the standard type and code constructions + — for instance, OCaml, Haskell, F#, Scala, Swift, Rust, — are mapped into + the constructive logic with all standard logical operations available ( +\begin_inset Formula $True$ \end_inset - and implement the functions: +, +\begin_inset Formula $False$ +\end_inset + +, disjunction, conjunction, and implication). \end_layout \begin_layout Standard +Languages such as C, C++, Java, C#, Go are mapped into logics that do not + have the disjunction operation or the constants +\begin_inset Formula $True$ +\end_inset -\series bold -(a) -\series default + and +\begin_inset Formula $False$ +\end_inset + +. + In other words, these languages are mapped into +\emph on +incomplete +\emph default + logics where some true formulas cannot be proved. + Incompleteness of the logic of types will make a programming language unable + to express certain computations, e.g., directly handle data that belongs + to a disjoint domain. -\begin_inset Formula $\text{map}^{R,T,U}:\text{Cont}^{R,T}\rightarrow(T\rightarrow U)\rightarrow\text{Cont}^{R,U}\quad.$ +\end_layout + +\begin_layout Standard +Languages that do not enforce type checking (e.g., Python or JavaScript) are + mapped to inconsistent logics where any proposition can be proved — even + propositions normally considered +\begin_inset Formula $False$ +\end_inset + +. + The CH correspondence will map such absurd proofs to code that +\emph on +appears +\emph default + to compute a certain value (since the +\begin_inset Formula $\mathcal{CH}$ +\end_inset + +-proposition was proved to be +\begin_inset Formula $True$ \end_inset +) although that value is not actually available. + In practice, such code will crash because of a value that has a wrong type + or is +\begin_inset Quotes eld +\end_inset + +null +\begin_inset Quotes erd +\end_inset + (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. + \end_layout \begin_layout Standard +So, the CH correspondence gives a mathematically justified procedure for + designing new programming languages. + The procedure has the following steps: +\end_layout -\series bold -(b) -\series default - -\begin_inset Formula $\text{flatMap}^{R,T,U}:\text{Cont}^{R,T}\rightarrow(T\rightarrow\text{Cont}^{R,U})\rightarrow\text{Cont}^{R,U}\quad.$ -\end_inset +\begin_layout Itemize +Choose a formal logic that is complete and free of inconsistencies. +\end_layout +\begin_layout Itemize +For each logical operation, provide a type construction in the language. +\end_layout +\begin_layout Itemize +For each axiom and proof rule of the logic, provide a code construction + in the language. \end_layout -\begin_layout Subsubsection -Exercise -\begin_inset CommandInset label -LatexCommand label -name "subsec:ch-Exercise-8" +\begin_layout Standard +Mathematicians have studied different logics, such as modal logic, temporal + logic, or linear logic. + Compared with the constructive logic, those other logics have some additional + type operations. + For instance, modal logic adds the operations +\begin_inset Quotes eld +\end_inset +necessarily +\begin_inset Quotes erd \end_inset + and +\begin_inset Quotes eld +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:ch-Exercise-8" -plural "false" -caps "false" -noprefix "false" +possibly +\begin_inset Quotes erd +\end_inset +, and temporal logic adds the operation +\begin_inset Quotes eld \end_inset +until +\begin_inset Quotes erd +\end_inset -\end_layout +. + For each logic, mathematicians have determined the minimal complete sets + of operations, axioms, and proof rules that do not lead to inconsistency. + Programming language designers can use this mathematical knowledge by choosing + a logic and translating it into a minimal +\begin_inset Quotes eld +\end_inset -\begin_layout Standard -Denote -\begin_inset Formula $\text{Sel}^{Z,T}\triangleq\left(T\rightarrow Z\right)\rightarrow T$ +core +\begin_inset Quotes erd \end_inset - and implement the functions: + of a programming language. + Code in that language will be guaranteed +\emph on +never to crash +\emph default + as long as all types match. + This mathematical guarantee (known as +\begin_inset Index idx +status open + +\begin_layout Plain Layout +type safety \end_layout -\begin_layout Standard +\end_inset + \series bold -(a) +type safety \series default +) is a powerful help for programmers since it automatically prevents a large + number of coding errors. + So, programmers will benefit if they use languages designed using the CH + correspondence. +\end_layout + +\begin_layout Standard +Practically useful programming languages will of course need more features + than the minimal set of mathematically necessary features derived from + a chosen logic. + Language designers need to make sure that all added features are consistent + with the core language. -\begin_inset Formula $\text{map}^{Z,A,B}:\text{Sel}^{Z,A}\rightarrow\left(A\rightarrow B\right)\rightarrow\text{Sel}^{Z,B}\quad.$ -\end_inset +\end_layout +\begin_layout Standard +At present, it is still not fully understood how a practical programming + language could use, say, modal or linear logic as its logic of types. + Experience suggests that, at least, the operations of the plain constructive + logic should be available. + So, it appears that the six type constructions and the eight code constructions + will remain available in all future languages of functional programming. + +\end_layout +\begin_layout Standard +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 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. \end_layout \begin_layout Standard +Some programming languages, such as Haskell and OCaml, were designed specificall +y for advanced use and exploration of the FP paradigm. + Other languages, such as F#, Scala, Swift, and Rust, have different design + goals but still support enough FP features to be considered FP languages. + This book uses Scala, but the same constructions may be implemented in + other FP languages in a similar way. + Differences between OCaml, Haskell, F#, Scala, Swift, Rust, and other FP + languages do not play a significant role at the level of detail needed + in this book. +\end_layout -\series bold -(b) -\series default - -\begin_inset Formula $\text{flatMap}^{Z,A,B}:\text{Sel}^{Z,A}\rightarrow(A\rightarrow\text{Sel}^{Z,B})\rightarrow\text{Sel}^{Z,B}\quad.$ -\end_inset +\begin_layout Subsection +Practical uses of the void type (Scala's +\family typewriter +Nothing +\family default +) +\end_layout +\begin_layout Standard +The +\begin_inset Index idx +status open +\begin_layout Plain Layout +void type \end_layout -\begin_layout Section -Discussion and further developments -\begin_inset CommandInset label -LatexCommand label -name "sec:Discussion-curry-howard" - \end_inset +void type +\begin_inset Foot +status open -\end_layout +\begin_layout Plain Layout +The +\begin_inset Quotes eld +\end_inset -\begin_layout Subsection -Using the Curry-Howard correspondence for writing code -\end_layout +void +\begin_inset Quotes erd +\end_inset -\begin_layout Standard -The CH correspondence is used in two practically important reasoning tasks: - checking whether a type signature can be implemented as a fully parametric - function, and determining whether two types are equivalent. - For the first task, we map type expressions into formulas in the constructive - logic and apply the proof rules of that logic. - For the second task, we map type expressions into + type is a type with no values. + It is \emph on -arithmetic +not \emph default - formulas and apply the ordinary rules of arithmetic. -\end_layout - -\begin_layout Standard -Although tools such as the + the same as the \begin_inset listings inline true status open \begin_layout Plain Layout -curryhoward +void \end_layout \end_inset - library can sometimes derive code from types, it is beneficial if a programmer - is able to derive an implementation by hand or to determine that an implementat -ion is impossible. - For instance, the programmer should recognize that the type signature: + keyword in Java or C that denotes functions returning +\begin_inset Quotes eld +\end_inset + +no value +\begin_inset Quotes erd +\end_inset + +. + Those functions are equivalent to Scala functions returning the (unique) + value of \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def f[A, B]: A => (A => B) => B +Unit \end_layout \end_inset -has only one fully parametric implementation, while the following two type - signatures have none: + type. +\end_layout + +\end_inset + + (Scala's \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def g[A, B]: A => (B => A) => B +Nothing \end_layout -\begin_layout Plain Layout - -def h[A, B]: ((A => B) => A) => A -\end_layout +\end_inset +) corresponds to the logical constant +\begin_inset Formula $False$ \end_inset -Exercises in this chapter help to build up the required technique and intuition. - The two main guidelines for code derivation are: +. + (The proposition \begin_inset Quotes eld \end_inset -values of parametric types cannot be constructed from scratch -\begin_inset Quotes erd -\end_inset - and -\begin_inset Quotes eld -\end_inset +\emph on +the code can compute a value of the void type +\emph default -one must hard-code the decision to return a chosen part of a disjunctive - type when no other disjunctive value is given \begin_inset Quotes erd \end_inset -. - These guidelines can be justified by referring to the rigorous rules of - proof (Table -\begin_inset space ~ -\end_inset + is always false.) The void type is used in some theoretical proofs but has + few practical uses. + One use case is for a branch of a +\begin_inset listings +inline true +status open +\begin_layout Plain Layout -\begin_inset CommandInset ref -LatexCommand ref -reference "tab:Proof-rules-for-constructive-logic" -plural "false" -caps "false" -noprefix "false" +match +\end_layout \end_inset -). - Sequents producing a value of type -\begin_inset Formula $A$ -\end_inset +/ +\begin_inset listings +inline true +status open - can be proved only if there is a premise containing -\begin_inset Formula $A$ -\end_inset +\begin_layout Plain Layout + +case +\end_layout - or a function that returns a value of type -\begin_inset Formula $A$ \end_inset -. -\begin_inset Foot + expression that throws an +\begin_inset Index idx status open \begin_layout Plain Layout -This is proved rigorously by R. -\begin_inset space ~ +exception +\end_layout + \end_inset -Dyckhoff -\begin_inset Index idx -status collapsed +exception instead of returning a value. + In this sense, returning a value of the void type corresponds to a crash + in the program. + So, a +\begin_inset listings +inline true +status open \begin_layout Plain Layout -Roy Dyckhoff + +throw \end_layout \end_inset - as the -\begin_inset Quotes eld -\end_inset + expression is defined as if it returns a value of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Nothing +\end_layout -Theorem -\begin_inset Quotes erd \end_inset - in section 6 ( +. + We can then pretend to convert that \begin_inset Quotes eld \end_inset -Goal-directed pruning +value \begin_inset Quotes erd \end_inset -), see -\family typewriter - -\begin_inset CommandInset href -LatexCommand href -target "https://research-repository.st-andrews.ac.uk/handle/10023/8824" -literal "false" - + (which will never be actually returned) into a value of any other type. + Example +\begin_inset space ~ \end_inset -\end_layout - -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-type-identity-0-to-A" +plural "false" +caps "false" +noprefix "false" - One can derive a disjunction without hard-coding only if one already has - a disjunction in the premises (and then the rule -\begin_inset Quotes eld \end_inset -use + shows how to write a function \begin_inset listings inline true status open \begin_layout Plain Layout -Either +absurd[A] \end_layout \end_inset + of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Nothing => A +\end_layout -\begin_inset Quotes erd \end_inset - could apply). +. \end_layout \begin_layout Standard -Throughout this chapter, we require all code to be fully parametric. - This is because the CH correspondence gives useful, non-trivial results - only for parameterized types and fully parametric code. - For concrete, non-parameterized types ( +To see how this trick is used, consider this code defining a value \begin_inset listings inline true status open \begin_layout Plain Layout -Int +x \end_layout \end_inset -, +: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -String -\end_layout - -\end_inset - -, etc.), one can always produce -\emph on -some -\emph default - values even with no previous data. - So, the propositions -\begin_inset Formula $\mathcal{CH}(\text{Int})$ +val x: Double = if (t >= 0.0) math.sqrt(t) else throw new Exception( +\begin_inset Quotes eld \end_inset - or -\begin_inset Formula $\mathcal{CH}(\text{String})$ +error +\begin_inset Quotes erd \end_inset - are always true. +) \end_layout -\begin_layout Standard -Consider the function +\end_inset + +The \begin_inset listings inline true status open \begin_layout Plain Layout -(x:Int) => x + 1 +else \end_layout \end_inset -. - Its type signature, + branch does not return a value, but \begin_inset listings inline true status open \begin_layout Plain Layout -Int => Int +x \end_layout \end_inset -, may be implemented by many other functions, such as + is declared to have type \begin_inset listings inline true status open \begin_layout Plain Layout -x => x - 1 +Double \end_layout \end_inset -, +. + For this code to type-check, both branches must return values of the same + type. + So, the compiler needs to pretend that the \begin_inset listings inline true status open \begin_layout Plain Layout -x => x * 2 +else \end_layout \end_inset -, etc. - So, the type signature + branch also returns a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -Int => Int -\end_layout - -\end_inset - - is insufficient to specify the code of the function, and deriving code - from that type is not a meaningful task. - Only a fully parametric type signature, such as -\begin_inset Formula $A\rightarrow\left(A\rightarrow B\right)\rightarrow B$ -\end_inset - -, could give enough information for deriving the function's code. - Additionally, we must require the code of functions to be fully parametric. - Otherwise we will be unable to reason about code derivation from type signature -s. +Double \end_layout -\begin_layout Standard -Validity of a -\begin_inset Formula ${\cal CH}$ -\end_inset - --proposition -\begin_inset Formula ${\cal CH}(T)$ -\end_inset - - means that we can implement -\emph on -some -\emph default - value of the given type -\begin_inset Formula $T$ \end_inset . - But this does not give any information about the properties of that value, - such as whether it satisfies any laws. - This is why type equivalence (which requires the laws of isomorphisms) - is not determined by an equivalence of logical formulas. -\end_layout - -\begin_layout Standard -It is useful for programmers to be able to transform type expressions to - equivalent simpler types before starting to write code. - The type notation introduced in this book is designed to help programmers - to recognize patterns in type expressions and to reason about them more - easily. - We have shown that a type equivalence corresponds to -\emph on -each -\emph default - standard arithmetic identity such as -\begin_inset Formula $\left(a+b\right)+c=a+\left(b+c\right)$ -\end_inset + The compiler first assigns the type +\begin_inset listings +inline true +status open -, -\begin_inset Formula $\left(a\times b\right)\times c=a\times(b\times c)$ -\end_inset +\begin_layout Plain Layout -, -\begin_inset Formula $1\times a=a$ -\end_inset +Nothing +\end_layout -, -\begin_inset Formula $\left(a+b\right)\times c=a\times c+b\times c$ \end_inset -, and so on. - Because of this, we are allowed to transform and simplify types as if they - were arithmetic expressions, e.g., to rewrite: -\begin_inset Formula -\[ -\bbnum 1\times\left(A+B\right)\times C+D\cong D+A\times C+B\times C\quad. -\] + to the expression +\begin_inset listings +inline true +status open -\end_inset +\begin_layout Plain Layout -The type notation makes this reasoning more intuitive (for people familiar - with arithmetic). - +throw ... \end_layout -\begin_layout Standard -These results apply to all type expressions built up using product types, - disjunctive types (also called -\begin_inset Quotes eld -\end_inset - -sum -\begin_inset Quotes erd -\end_inset - - types because they correspond to arithmetic sums), and function types (also - called -\begin_inset Quotes eld -\end_inset - -exponential -\begin_inset Quotes erd \end_inset - types because they correspond to arithmetic exponentials). - Type expressions that contain only products and sum types are called -\series bold -polynomial -\series default - -\begin_inset Index idx + and then automatically uses the conversion +\begin_inset listings +inline true status open \begin_layout Plain Layout -polynomial type + +Nothing => Double \end_layout \end_inset - -\begin_inset Index idx + to convert that type to +\begin_inset listings +inline true status open \begin_layout Plain Layout -types!polynomial types + +Double \end_layout \end_inset . -\begin_inset Foot + In this way, types will match in the definition of the value +\begin_inset listings +inline true status open \begin_layout Plain Layout -These types are often called -\begin_inset Quotes eld -\end_inset - -algebraic data types -\begin_inset Index idx -status open -\begin_layout Plain Layout -algebraic data types +x \end_layout \end_inset - -\begin_inset Quotes erd -\end_inset - - but this book prefers the more precise term -\begin_inset Quotes eld -\end_inset - -polynomial types -\begin_inset Quotes erd -\end_inset - . + \end_layout -\end_inset - - Type expressions that also contain function types are called -\series bold -exponential-polynomial -\series default +\begin_layout Standard +This book does not discuss exceptions in much detail. + The functional programming paradigm does not use exceptions because their + presence prevents mathematical reasoning about code. +\end_layout -\begin_inset Index idx +\begin_layout Standard +As another example of using the void type, suppose an external library implement +s a function: +\begin_inset listings +inline false status open \begin_layout Plain Layout -exponential-polynomial type + +def parallel_run[E, A, B](f: A => Either[E, B]): Either[E, B] = ??? \end_layout \end_inset - -\begin_inset Index idx +We may imagine that +\begin_inset listings +inline true status open \begin_layout Plain Layout -types!exponential-polynomial types -\end_layout -\end_inset - -. - We focus on exponential-polynomial types because they are sufficient for - almost all design patterns used in functional programming. +parallel_run(f) \end_layout -\begin_layout Standard -There are no types corresponding to subtraction or division, so arithmetic - equations such as: -\begin_inset Formula -\begin{align*} -\left(1-t\right)\times\left(1+t\right) & =1-t\times t\quad,\quad\text{ and }\quad\frac{t+t\times t}{t}=1+t\quad, -\end{align*} - -\end_inset - -do not directly yield any type equivalences. - However, consider this well-known formula: -\begin_inset Formula -\[ -\frac{1}{1-t}=1+t+t^{2}+t^{3}+...+t^{n}+...\quad. -\] - \end_inset -At first sight, this formula appears to involve subtraction, division, and - an infinite series, and so cannot be directly translated into a type equivalenc -e. - However, the formula can be rewritten as: -\begin_inset Formula -\begin{equation} -\frac{1}{1-t}=L(t)\quad\text{ where }\quad L(t)\triangleq1+t+t^{2}+t^{3}+...+t^{n}\times L(t)\quad.\label{eq:ch-example-type-formula-list} -\end{equation} - + performs some parallel computations using a given function +\begin_inset Formula $f$ \end_inset -The definition of -\begin_inset Formula $L(t)$ +. + In general, functions +\begin_inset Formula $f^{:A\rightarrow E+B}$ \end_inset - is finite and only contains additions and multiplications. - So, Eq. -\begin_inset space ~ + may return an error of type +\begin_inset Formula $E$ \end_inset -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-example-type-formula-list" -plural "false" -caps "false" -noprefix "false" - + or a result of type +\begin_inset Formula $B$ \end_inset -) can be translated into a type equivalence: -\begin_inset Formula -\begin{equation} -L^{A}\cong1+A+A\times A+A\times A\times A+...+\underbrace{A\times...\times A}_{n\text{ times}}\times\,L^{A}\quad.\label{eq:ch-example-type-expansion-list} -\end{equation} - +. + Suppose we know that a particular function +\begin_inset Formula $f$ \end_inset -This type formula (with -\begin_inset Formula $n=1$ + never fails to compute its result. + To express that knowledge in code, we may explicitly set the type parameter + +\begin_inset Formula $E$ \end_inset -) is equivalent to a recursive definition of the type constructor + to the void type \begin_inset listings inline true status open \begin_layout Plain Layout -List +Nothing \end_layout \end_inset -: -\begin_inset Formula -\[ -\text{List}^{A}\triangleq1+A\times\text{List}^{A}\quad. -\] - -\end_inset - -The type equivalence -\begin_inset space ~ -\end_inset - -( -\begin_inset CommandInset ref -LatexCommand ref -reference "eq:ch-example-type-expansion-list" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -) suggests that we may view the recursive type + when applying \begin_inset listings inline true status open \begin_layout Plain Layout -List +parallel_run \end_layout \end_inset - heuristically as an -\begin_inset Quotes eld -\end_inset - -infinite disjunction -\begin_inset Quotes erd -\end_inset +: +\begin_inset listings +inline false +status open - describing lists of zero, one, two, etc., elements. -\end_layout +\begin_layout Plain Layout -\begin_layout Subsection -Implications for designing new programming languages +parallel_run[Nothing, A, B](f) // Types match only when values f(a) are + always of the form Right(b). + \end_layout -\begin_layout Standard -Today's functional programming practice assumes, at the minimum, that programmer -s will use the six standard type constructions (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Type-notation-and-standard-type-constructions" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -) and the eight standard code constructions (Section -\begin_inset space ~ \end_inset +Returning an error is now impossible (the type +\begin_inset listings +inline true +status open -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:The-rules-of-proof" -plural "false" -caps "false" -noprefix "false" - -\end_inset +\begin_layout Plain Layout -). - 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 all of those constructions cannot - be considered a functional programming language. +Nothing \end_layout -\begin_layout Standard -A remarkable result of the CH correspondence is that the type system of - any given programming language (functional or not) is mapped into a -\emph on -certain -\emph default - -\emph on -logic -\emph default -, i.e., a system of logical operations and proof rules. - A logical operation will correspond to each of the -\emph on -type -\emph default - constructions available in the programming language. - A proof rule will correspond to each of the available -\emph on -code -\emph default - constructions. - Programming languages that support all the standard type and code constructions - — for instance, OCaml, Haskell, F#, Scala, Swift, Rust, — are mapped into - the constructive logic with all standard logical operations available ( -\begin_inset Formula $True$ -\end_inset - -, -\begin_inset Formula $False$ \end_inset -, disjunction, conjunction, and implication). -\end_layout - -\begin_layout Standard -Languages such as C, C++, Java, C#, Go are mapped into logics that do not - have the disjunction operation or the constants -\begin_inset Formula $True$ -\end_inset + has no values). + If the function +\begin_inset listings +inline true +status open - and -\begin_inset Formula $False$ -\end_inset +\begin_layout Plain Layout -. - In other words, these languages are mapped into -\emph on -incomplete -\emph default - logics where some true formulas cannot be proved. - Incompleteness of the logic of types will make a programming language unable - to express certain computations, e.g., directly handle data that belongs - to a disjoint domain. - +parallel_run \end_layout -\begin_layout Standard -Languages that do not enforce type checking (e.g., Python or JavaScript) are - mapped to inconsistent logics where any proposition can be proved — even - propositions normally considered -\begin_inset Formula $False$ -\end_inset - -. - The CH correspondence will map such absurd proofs to code that -\emph on -appears -\emph default - to compute a certain value (since the -\begin_inset Formula $\mathcal{CH}$ -\end_inset - --proposition was proved to be -\begin_inset Formula $True$ \end_inset -) although that value is not actually available. - In practice, such code will crash because of a value that has a wrong type - or is -\begin_inset Quotes eld + is fully parametric, it will work in the same way with all types +\begin_inset Formula $E$ \end_inset -null -\begin_inset Quotes erd +, including +\begin_inset Formula $E=\bbnum 0$ \end_inset - (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. - +. + The code implements our intention via type parameters, giving a compile-time + guarantee of correct results. \end_layout \begin_layout Standard -So, the CH correspondence gives a mathematically justified procedure for - designing new programming languages. - The procedure has the following steps: -\end_layout - -\begin_layout Itemize -Choose a formal logic that is complete and free of inconsistencies. -\end_layout +So far, none of our examples involved the logical +\series bold +negation +\series default -\begin_layout Itemize -For each logical operation, provide a type construction in the language. -\end_layout +\begin_inset Index idx +status open -\begin_layout Itemize -For each axiom and proof rule of the logic, provide a code construction - in the language. +\begin_layout Plain Layout +negation (in logic) \end_layout -\begin_layout Standard -Mathematicians have studied different logics, such as modal logic, temporal - logic, or linear logic. - Compared with the constructive logic, those other logics have some additional - type operations. - For instance, modal logic adds the operations -\begin_inset Quotes eld -\end_inset - -necessarily -\begin_inset Quotes erd -\end_inset - - and -\begin_inset Quotes eld \end_inset -possibly -\begin_inset Quotes erd -\end_inset + operation. + It is defined as: +\begin_inset Formula +\[ +\neg\alpha\triangleq(\alpha\Rightarrow False)\quad. +\] -, and temporal logic adds the operation -\begin_inset Quotes eld \end_inset -until -\begin_inset Quotes erd +Its practical use in functional programming is as limited as that of +\begin_inset Formula $False$ \end_inset -. - For each logic, mathematicians have determined the minimal complete sets - of operations, axioms, and proof rules that do not lead to inconsistency. - Programming language designers can use this mathematical knowledge by choosing - a logic and translating it into a minimal -\begin_inset Quotes eld + and the void type. + (The type corresponding to +\begin_inset Formula $\alpha\Rightarrow False$ \end_inset - -core -\begin_inset Quotes erd + + is the function type +\begin_inset Formula $A\rightarrow\bbnum 0$ \end_inset - of a programming language. - Code in that language will be guaranteed -\emph on -never to crash -\emph default - as long as all types match. - This mathematical guarantee (known as -\begin_inset Index idx + or, in Scala, +\begin_inset listings +inline true status open \begin_layout Plain Layout -type safety + +A => Nothing \end_layout \end_inset - -\series bold -type safety -\series default -) is a powerful help for programmers since it automatically prevents a large - number of coding errors. - So, programmers will benefit if they use languages designed using the CH - correspondence. +.) However, logical negation plays an important role in Boolean logic. \end_layout -\begin_layout Standard -Practically useful programming languages will of course need more features - than the minimal set of mathematically necessary features derived from - a chosen logic. - Language designers need to make sure that all added features are consistent - with the core language. - -\end_layout +\begin_layout Subsection +Relationship between Boolean logic and constructive logic +\begin_inset CommandInset label +LatexCommand label +name "subsec:Relationship-between-Boolean" + +\end_inset -\begin_layout Standard -At present, it is still not fully understood how a practical programming - language could use, say, modal or linear logic as its logic of types. - Experience suggests that, at least, the operations of the plain constructive - logic should be available. - So, it appears that the six type constructions and the eight code constructions - will remain available in all future languages of functional programming. \end_layout \begin_layout Standard -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 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. -\end_layout +We have seen that some true theorems of Boolean logic are not true in constructi +ve logic. + Here are some more examples: the Boolean identities +\begin_inset Formula $\neg\left(\neg\alpha\right)=\alpha$ +\end_inset -\begin_layout Standard -Some programming languages, such as Haskell and OCaml, were designed specificall -y for advanced use and exploration of the FP paradigm. - Other languages, such as F#, Scala, Swift, and Rust, have different design - goals but still support enough FP features to be considered FP languages. - This book uses Scala, but the same constructions may be implemented in - other FP languages in a similar way. - Differences between OCaml, Haskell, F#, Scala, Swift, Rust, and other FP - languages do not play a significant role at the level of detail needed - in this book. -\end_layout + and +\begin_inset Formula $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$ +\end_inset -\begin_layout Subsection -Practical uses of the void type (Scala's -\family typewriter -Nothing -\family default -) +. \end_layout -\begin_layout Standard -The -\begin_inset Index idx -status open +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-boolean-implication-not-constructive-1" -\begin_layout Plain Layout -void type -\end_layout +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-boolean-implication-not-constructive-1" +plural "false" +caps "false" +noprefix "false" \end_inset -void type -\begin_inset Foot -status open -\begin_layout Plain Layout -The -\begin_inset Quotes eld +\end_layout + +\begin_layout Standard +Show that the Boolean identity +\begin_inset Formula $\neg\left(\neg\alpha\right)=\alpha$ \end_inset -void -\begin_inset Quotes erd + does not hold in constructive logic by arguing that there is no fully parametri +c function with the type signature +\begin_inset Formula $((A\rightarrow\bbnum 0)\rightarrow\bbnum 0)\rightarrow A$ \end_inset - type is a type with no values. - It is -\emph on -not -\emph default - the same as the +, or in Scala: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -void +def bad4[A](f: (A => Nothing) => Nothing): A \end_layout \end_inset - keyword in Java or C that denotes functions returning -\begin_inset Quotes eld + +\end_layout + +\begin_layout Subparagraph +Solution +\end_layout + +\begin_layout Standard +The negation +\begin_inset Formula $\neg\alpha$ \end_inset -no value -\begin_inset Quotes erd + is translated by the Curry-Howard correspondence to the type +\begin_inset Formula $A\rightarrow\bbnum 0$ \end_inset -. - Those functions are equivalent to Scala functions returning the (unique) - value of + (in Scala, \begin_inset listings inline true status open \begin_layout Plain Layout -Unit +A => Nothing \end_layout \end_inset - type. -\end_layout +). + If the Boolean identity +\begin_inset Formula $\neg\left(\neg\alpha\right)=\alpha$ +\end_inset + were also true in the constructive logic, the formula +\begin_inset Formula $\neg(\neg\alpha)\Rightarrow\alpha$ \end_inset - (Scala's + would be true. + The CH correspondence then says that we would be able to implement a fully + parametric function of type +\begin_inset Formula $((A\rightarrow\bbnum 0)\rightarrow\bbnum 0)\rightarrow A$ +\end_inset + +. + Can we do that? The result type of \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing +bad4 \end_layout \end_inset -) corresponds to the logical constant -\begin_inset Formula $False$ + is an arbitrary, unknown type +\begin_inset Formula $A$ \end_inset -. - (The proposition -\begin_inset Quotes eld +, so we cannot produce values of type +\begin_inset Formula $A$ \end_inset + from scratch. + We also do not have any given arguments of type +\begin_inset Formula $A$ +\end_inset -\emph on -the code can compute a value of the void type -\emph default + or given functions of type +\begin_inset Formula $X\rightarrow A$ +\end_inset -\begin_inset Quotes erd + for some +\begin_inset Formula $X$ \end_inset - is always false.) The void type is used in some theoretical proofs but has - few practical uses. - One use case is for a branch of a +. + The only remaining possibility of implementing \begin_inset listings inline true status open \begin_layout Plain Layout -match +bad4 \end_layout \end_inset -/ + is by applying the argument \begin_inset listings inline true status open \begin_layout Plain Layout -case +f \end_layout \end_inset - expression that throws an -\begin_inset Index idx + to a value of type +\begin_inset listings +inline true status open \begin_layout Plain Layout -exception + +A => Nothing \end_layout \end_inset -exception instead of returning a value. - In this sense, returning a value of the void type corresponds to a crash - in the program. - So, a +. + The resulting value would be of type \begin_inset listings inline true status open \begin_layout Plain Layout -throw +Nothing \end_layout \end_inset - expression is defined as if it returns a value of type +, and we would then use the function \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing +absurd \end_layout \end_inset -. - We can then pretend to convert that -\begin_inset Quotes eld -\end_inset - -value -\begin_inset Quotes erd -\end_inset - - (which will never be actually returned) into a value of any other type. - Example + from Example \begin_inset space ~ \end_inset @@ -30192,388 +32000,357 @@ noprefix "false" \end_inset - shows how to write a function + to obtain a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -absurd[A] +A \end_layout \end_inset - of type +. + It remains to get a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing => A +A => Nothing \end_layout \end_inset -. -\end_layout + from scratch. + But we cannot do that: Example +\begin_inset space ~ +\end_inset -\begin_layout Standard -To see how this trick is used, consider this code defining a value + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-type-identity-A-0" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) shows that the type \begin_inset listings inline true status open \begin_layout Plain Layout -x +A => Nothing \end_layout \end_inset -: + is itself void unless \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -val x: Double = if (t >= 0.0) math.sqrt(t) else throw new Exception( -\begin_inset Quotes eld -\end_inset - -error -\begin_inset Quotes erd -\end_inset - -) +A \end_layout \end_inset -The + is void. + So, we cannot compute a value of type \begin_inset listings inline true status open \begin_layout Plain Layout -else +A => Nothing \end_layout \end_inset - branch does not return a value, but + via fully parametric code that works in the same way for all types \begin_inset listings inline true status open \begin_layout Plain Layout -x +A \end_layout \end_inset - is declared to have type +. + We conclude that \begin_inset listings inline true status open \begin_layout Plain Layout -Double +bad4 \end_layout \end_inset -. - For this code to type-check, both branches must return values of the same - type. - So, the compiler needs to pretend that the -\begin_inset listings -inline true -status open + cannot be implemented. + +\begin_inset Formula $\square$ +\end_inset -\begin_layout Plain Layout -else \end_layout +\begin_layout Subsubsection +Example +\begin_inset CommandInset label +LatexCommand label +name "subsec:Example-boolean-implication-not-constructive" + \end_inset - branch also returns a value of type -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-boolean-implication-not-constructive" +plural "false" +caps "false" +noprefix "false" + +\end_inset + -Double \end_layout +\begin_layout Standard +Show that the Boolean identity +\begin_inset Formula $\left(\alpha\Rightarrow\beta\right)=\neg\alpha\vee\beta$ \end_inset -. - The compiler first assigns the type + does not hold in constructive logic by arguing that there is no fully parametri +c function with the type signature +\begin_inset Formula $\left(A\rightarrow B\right)\rightarrow(A\rightarrow\bbnum 0)+B$ +\end_inset + +, or in Scala: \begin_inset listings -inline true +inline false status open \begin_layout Plain Layout -Nothing +def bad5[A, B](f: A => B): Either[A => Nothing, B] \end_layout \end_inset - to the expression + +\end_layout + +\begin_layout Subparagraph +Solution +\end_layout + +\begin_layout Standard +The result type of \begin_inset listings inline true status open \begin_layout Plain Layout -throw ... +bad5 \end_layout \end_inset - and then automatically uses the conversion + is a disjunctive type, but the argument type is not. + The code of \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing => Double +bad5 \end_layout \end_inset - to convert that type to + cannot pattern-match on its argument \begin_inset listings inline true status open \begin_layout Plain Layout -Double +f \end_layout \end_inset -. - In this way, types will match in the definition of the value + to make a decision about returning a \begin_inset listings inline true status open \begin_layout Plain Layout -x +Left \end_layout \end_inset -. - -\end_layout - -\begin_layout Standard -This book does not discuss exceptions in much detail. - The functional programming paradigm does not use exceptions because their - presence prevents mathematical reasoning about code. -\end_layout - -\begin_layout Standard -As another example of using the void type, suppose an external library implement -s a function: + or a \begin_inset listings -inline false +inline true status open \begin_layout Plain Layout -def parallel_run[E, A, B](f: A => Either[E, B]): Either[E, B] = ??? +Right \end_layout \end_inset -We may imagine that +. + So, \begin_inset listings inline true status open \begin_layout Plain Layout -parallel_run(f) +bad5 \end_layout \end_inset - performs some parallel computations using a given function -\begin_inset Formula $f$ -\end_inset - -. - In general, functions -\begin_inset Formula $f^{:A\rightarrow E+B}$ + must hard-code that decision and either always return a value of type +\begin_inset Formula $(A\rightarrow\bbnum 0)+\bbnum 0^{:B}$ \end_inset - may return an error of type -\begin_inset Formula $E$ +, or always return a value of type +\begin_inset Formula $\bbnum 0^{:A\rightarrow\bbnum 0}+B$ \end_inset - or a result of type +. + A value of type \begin_inset Formula $B$ \end_inset -. - Suppose we know that a particular function -\begin_inset Formula $f$ + cannot be computed from scratch because the type +\begin_inset Formula $B$ \end_inset - never fails to compute its result. - To express that knowledge in code, we may explicitly set the type parameter - -\begin_inset Formula $E$ + is unknown. + The only way of getting a value of type +\begin_inset Formula $B$ \end_inset - to the void type + would be by computing \begin_inset listings inline true status open \begin_layout Plain Layout -Nothing +f(x) \end_layout \end_inset - when applying + for some \begin_inset listings inline true status open \begin_layout Plain Layout -parallel_run +x: A \end_layout \end_inset -: -\begin_inset listings -inline false -status open - -\begin_layout Plain Layout - -parallel_run[Nothing, A, B](f) // Types match only when values f(a) always - are of the form Right(b). - -\end_layout - +, but no values of type +\begin_inset Formula $A$ \end_inset -Returning an error is now impossible (the type -\begin_inset listings -inline true -status open + are available. + The remaining possibility is to return a value of type +\begin_inset Formula $A\rightarrow\bbnum 0$ +\end_inset -\begin_layout Plain Layout +. + But the type +\begin_inset Formula $A\rightarrow\bbnum 0$ +\end_inset -Nothing -\end_layout + is void unless +\begin_inset Formula $A=\bbnum 0$ +\end_inset + (see Example +\begin_inset space ~ \end_inset - has no values). - If the function -\begin_inset listings -inline true -status open -\begin_layout Plain Layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:ch-Example-type-identity-A-0" +plural "false" +caps "false" +noprefix "false" -parallel_run -\end_layout +\end_inset +). + As the type +\begin_inset Formula $A$ \end_inset - is fully parametric, it will work in the same way with all types -\begin_inset Formula $E$ + is unknown, we cannot write code that works in the same way for all types + +\begin_inset Formula $A$ \end_inset -, including -\begin_inset Formula $E=\bbnum 0$ + and produces a value of type +\begin_inset Formula $A\rightarrow\bbnum 0$ \end_inset . - The code implements our intention via type parameters, giving a compile-time - guarantee of correct results. -\end_layout - -\begin_layout Standard -So far, none of our examples involved the logical -\series bold -negation -\series default - -\begin_inset Index idx + So, the function +\begin_inset listings +inline true status open \begin_layout Plain Layout -negation (in logic) -\end_layout - -\end_inset - operation. - It is defined as: -\begin_inset Formula -\[ -\neg\alpha\triangleq(\alpha\Rightarrow False)\quad. -\] +bad5 +\end_layout \end_inset -Its practical use in functional programming is as limited as that of -\begin_inset Formula $False$ + cannot be implemented via fully parametric code. + +\begin_inset Formula $\square$ \end_inset - and the void type. - However, logical negation plays an important role in Boolean logic. -\end_layout - -\begin_layout Subsection -Relationship between Boolean logic and constructive logic -\begin_inset CommandInset label -LatexCommand label -name "subsec:Relationship-between-Boolean" - -\end_inset - \end_layout \begin_layout Standard -We have seen that some true theorems of Boolean logic are not true in constructi -ve logic. - For example, the Boolean identities -\begin_inset Formula $\neg\left(\neg\alpha\right)=\alpha$ -\end_inset - - and -\begin_inset Formula $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$ -\end_inset - - do not hold in the constructive logic. - However, as we will now show, any theorem of constructive logic is also - a theorem of Boolean logic. +Nevertheless, 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 \begin_inset space ~ \end_inset @@ -31106,31 +32883,39 @@ Since each proof rule of the constructive logic is translated into a true \end_inset for each axiom or proof rule. - The result is that any constructive proof for a sequent such as + So, a proof tree for a sequent such as \begin_inset Formula $\emptyset\vdash f(\alpha,\beta,\gamma)$ \end_inset - is translated into a chain of Boolean implications that look like this: + is translated into a tree of Boolean implications that look like this: \begin_inset Formula \[ -True=(...)\Rightarrow(...)\Rightarrow...\Rightarrow f(\alpha,\beta,\gamma)\quad. +True=(True)\Rightarrow(True)\Rightarrow...\Rightarrow f(\alpha,\beta,\gamma)\quad. \] \end_inset Since -\begin_inset Formula $\left(True\Rightarrow\alpha\right)=\alpha$ +\begin_inset Formula $\left(True\Rightarrow x\right)=x$ \end_inset -, this chain proves the Boolean formula + for any +\begin_inset Formula $x$ +\end_inset + +, the Boolean formula \begin_inset Formula $f(\alpha,\beta,\gamma)$ +\end_inset + + will be proved +\begin_inset Formula $True$ \end_inset . \end_layout \begin_layout Standard -For example, the proof tree shown in Figure +To see how this works in practice, consider the proof tree shown in Figure \begin_inset space ~ \end_inset @@ -31144,19 +32929,54 @@ noprefix "false" \end_inset - is translated into: + (page +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand pageref +reference "fig:Proof-of-the-sequent-example-2" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +). + Each step in that proof is made via an axiom or via a derivation rule. + Denoting for brevity +\begin_inset Formula $\gamma\triangleq\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta$ +\end_inset + +, let us translate each of those axioms and rules into Boolean formulas + that (as we know) all have value +\begin_inset Formula $True$ +\end_inset + +: \begin_inset Formula \begin{align*} -\text{axiom ``use valuue''}:\quad & True=\left(\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\neg\alpha\vee\alpha\right)\\ -\text{rule ``create function''}:\quad & \quad\Rightarrow\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\alpha\right)\quad.\\ -\text{axiom ``use value''}:\quad & True=\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\quad.\\ -\text{rule ``use function''}:\quad & True\Rightarrow\left(\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\beta\right)\\ -\text{rule ``create function''}:\quad & \quad\Rightarrow\left(\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\Rightarrow\beta\right)\quad. +\text{``use value''}:\quad & True=\left(\gamma\wedge\alpha\right)\Rightarrow\alpha\quad.\\ +\text{``create function''}:\quad & True=\gunderline{\left(\left(\gamma\wedge\alpha\right)\Rightarrow\alpha\right)}\Rightarrow\left(\gamma\Rightarrow\left(\alpha\Rightarrow\alpha\right)\right)\\ + & \quad\quad\quad=(True)\Rightarrow\left(\gamma\Rightarrow\left(\alpha\Rightarrow\alpha\right)\right)\quad.\\ +\text{``use value''}:\quad & True=\left(\gamma\Rightarrow\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\right)\quad.\\ +\text{``use function''}:\quad & True=\gunderline{(\gamma\Rightarrow(\alpha\Rightarrow\alpha))}\wedge\gunderline{\left(\gamma\Rightarrow\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\right)}\Rightarrow\left(\gamma\Rightarrow\beta\right)\\ + & \quad\quad\quad=(True)\wedge(True)\Rightarrow\left(\gamma\Rightarrow\beta\right)\quad.\\ +\text{``create function''}:\quad & True=\gunderline{\left(\gamma\Rightarrow\beta\right)}\Rightarrow\left(\gamma\Rightarrow\beta\right)=(True)\Rightarrow\left(\gamma\Rightarrow\beta\right)\quad. \end{align*} \end_inset +These Boolean implications ultimately show that +\begin_inset Formula $\gamma\Rightarrow\beta$ +\end_inset + + is +\begin_inset Formula $True$ +\end_inset +. \end_layout \begin_layout Standard @@ -31217,11 +33037,7 @@ not \end_inset -These formulas are also -\emph on -not -\emph default - true in the constructive logic. +These formulas are also not true in the constructive logic. \end_layout \begin_layout Subsection @@ -31383,7 +33199,11 @@ noprefix "false" \end_inset . - The formula + +\end_layout + +\begin_layout Standard +The formula \begin_inset Formula $\forall\alpha.\,\neg\alpha\vee\alpha=True$ \end_inset @@ -31432,7 +33252,7 @@ does not have \begin_layout Standard To see why, translate the constructive logic formula -\begin_inset Formula $\forall\alpha.\,\neg\alpha\vee\alpha=True$ +\begin_inset Formula $\forall\alpha.\,\neg\alpha\vee\alpha$ \end_inset into a type. @@ -31464,12 +33284,26 @@ To see why, translate the constructive logic formula \end_inset . - This decision needs to be made in advance independently of + This decision needs to be made independently of \begin_inset Formula $A$ \end_inset , because the code of a fully parametric function must operate in the same way for all types. + We cannot compute a value of type +\begin_inset Formula $A$ +\end_inset + + from scratch, as the type +\begin_inset Formula $A$ +\end_inset + + is unknown. + So, the only remaining possibility is to compute a value of type +\begin_inset Formula $A\rightarrow\bbnum 0$ +\end_inset + +. As we have seen in Example \begin_inset space ~ \end_inset @@ -31488,7 +33322,7 @@ noprefix "false" \begin_inset Formula $A\rightarrow\bbnum 0$ \end_inset - exists if the type + exists only if the type \begin_inset Formula $A$ \end_inset @@ -31527,11 +33361,7 @@ 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 @@ -32249,7 +34079,7 @@ ns always like the most minimal set of rules so that's why they say let's none of these other rules now what do these other rules do they do an interesti ng thing actually each of these rules is either about something in the sequence on the left to the trans time or something in the sequence to the right - of the transplant which I here shown in blue so these are the interesting + of the transplant which I here shown in red so these are the interesting parts of the sequence that are being worked on or transformed by the rule so here's an example this rule is actually two rules the eyes the index so I is one or two another two rules just written for gravity like this @@ -32356,7 +34186,7 @@ ing on the mathematicians results let us look at an example suppose we want four atomic variables conjunctions disjunction and implications and so we have here enumerated all the possibilities for what could be to the left of the implication in this premise which I have here shown in the - blue in blue and so for each of these we do certain things replacing this + red in red and so for each of these we do certain things replacing this sequence with one or more other sequence again it's quite a lot of work to prove that these rules are equivalent to these and also that the new rules are somehow better they are not giving loops a lot of work which @@ -32480,7 +34310,7 @@ g to talk about how it is done that's all it means could be for any number is proof into this we need a function that takes argument of type A to B to C to D and returns a function of type tuple a B going to C to D so here's the code we take a function f of type A to B to C to D we return - a function that takes a G of this type shown here in blue and return we + a function that takes a G of this type shown here in red and return we need to return a D so how do we get a deal we apply F to a function of type A to B to C so we create that function out of G X of type a going to Y of type B going to G of x1 so this is a function of type A to B to diff --git a/sofp-src/lyx/sofp-disjunctions.lyx b/sofp-src/lyx/sofp-disjunctions.lyx index 350349024..bc09c0fc8 100644 --- a/sofp-src/lyx/sofp-disjunctions.lyx +++ b/sofp-src/lyx/sofp-disjunctions.lyx @@ -1209,12 +1209,12 @@ status open \begin_layout Plain Layout -case class MySock_Int(size: Double, color: String, value: Int) +case class MySockInt(size: Double, color: String, value: Int) \end_layout \begin_layout Plain Layout -case class MySock_Boolean(size: Double, color: String, value: Boolean) +case class MySockBoolean(size: Double, color: String, value: Boolean) \end_layout \end_inset @@ -1488,8 +1488,8 @@ status open \begin_layout Plain Layout -def fits[A](sock: MySockX[A]): Boolean = (sock.size >= 10.5 && sock.size <= - 11.0) +def fits[A](sock: MySockX[A]): Boolean = sock.size >= 10.5 && sock.size <= + 11 \end_layout \end_inset @@ -1558,7 +1558,7 @@ blue \begin_inset Quotes erd \end_inset -, List(1, 2, 3))) // Type parameter A = List[Int]. +, List(1, 2, 3))) // Using MySockX[List[Int]]. \end_layout \begin_layout Plain Layout @@ -2709,7 +2709,8 @@ case $pattern$ => ... \begin_layout Standard In both situations, case classes can be used as patterns. - The following code is an example of a destructuring definition: + The following code is an example of a destructuring definition with case + classes: \begin_inset listings inline false status open @@ -3798,7 +3799,7 @@ sealed trait SearchResult \begin_layout Plain Layout -final case class Index(i: Int) extends SearchResult +final case class Index(x: Int) extends SearchResult \end_layout \begin_layout Plain Layout @@ -4153,13 +4154,12 @@ status open \begin_layout Plain Layout -x:RootsOfQ +x: RootsOfQ \end_layout \end_inset -? The main tool for working with values of disjunctive types is pattern - matching. +? Disjunctive types fit well with pattern matching. In Chapter \begin_inset space ~ \end_inset @@ -4204,7 +4204,7 @@ case \end_inset - patterns because we need to match several possible cases of the disjunctive + patterns because we need to detect several possible cases of the disjunctive type: \begin_inset listings inline false @@ -4934,7 +4934,7 @@ def findRoots(equs: Seq[QEqu]): Seq[RootsOfQ] = equs.map { case QEqu(b, c) \end_inset This code depends on some features of Scala syntax. - We can use the partial function + We can use the function expression \begin_inset listings inline true status open @@ -5028,7 +5028,7 @@ if \end_inset - within the + within a \begin_inset listings inline true status open @@ -5712,7 +5712,8 @@ status open \end_inset against various possibilities. - In this way, the code is clearer than code written with nested + When written in this way, the code is clearer than code written with nested + \begin_inset listings inline true status open @@ -5863,15 +5864,19 @@ Result[Int] \end_inset -, assuming that the operation never generates an error: +, assuming that the operation itself never generates an error: \begin_inset listings inline false status open \begin_layout Plain Layout -def sub(rx: Result[Int], ry: Result[Int]): Result[Int] = map2(rx, ry){ (x, - y) => x - y } +def sub(rx: Result[Int], ry: Result[Int]): Result[Int] = +\end_layout + +\begin_layout Plain Layout + + map2(rx, ry) { (x, y) => x - y } \end_layout \end_inset @@ -5966,10 +5971,8 @@ res11: Result[Int] = Error(error: 3 / 0) \end_inset -Indeed, all further computations are abandoned once an error occurs. - An error message shows only the immediate calculation that generated the - error. - For instance, the error message for +Let us check that all further computations are abandoned once an error occurs. + Indeed, the following example shows that the error message for \begin_inset Formula $20+1/0$ \end_inset @@ -6068,7 +6071,8 @@ Try \end_inset - because they are often useful. +. + These types are used often in Scala programs. \end_layout \begin_layout Paragraph @@ -6388,8 +6392,7 @@ None[T]() \end_layout \begin_layout Standard -Several consequences follow from the Scala library's decision to define - +The Scala library's decision to define \begin_inset listings inline true status open @@ -6401,8 +6404,7 @@ None \end_inset - without a type parameter. - One consequence is that + without a type parameter means that \begin_inset listings inline true status open @@ -7468,19 +7470,7 @@ Option[Long] \end_inset , extract the country code if it is present. - (Assume that the country code is any digits in front of the -\begin_inset Formula $10$ -\end_inset - --digit number; for the phone number -\begin_inset Formula $18004151212$ -\end_inset - -, the country code is -\begin_inset Formula $1$ -\end_inset - -.) The result must be again of type + The result must be again of type \begin_inset listings inline true status open @@ -7493,6 +7483,20 @@ Option[Long] \end_inset . + Assume that the country code is the digits in front of a +\begin_inset Formula $10$ +\end_inset + +-digit phone number; for the phone number +\begin_inset Formula $18004151212$ +\end_inset + +, the country code is +\begin_inset Formula $1$ +\end_inset + +. + \end_layout \begin_layout Subparagraph @@ -7530,11 +7534,7 @@ Option \end_inset - (i.e. -\begin_inset space ~ -\end_inset - -the value + (i.e., the value \begin_inset listings inline true status open @@ -8126,7 +8126,7 @@ lift \end_inset - for sequences, and + for sequences, as well as \begin_inset listings inline true status open @@ -8428,7 +8428,7 @@ get \end_inset method is a safe by-key access to dictionaries, unlike the direct access - that may fail: + that may fail with an exception: \begin_inset listings inline false status open @@ -10523,11 +10523,8 @@ List[A] via mathematical induction on the length of the list: \end_layout -\begin_layout Standard -\begin_inset Formula $\bullet$ -\end_inset - - Base case: empty list, +\begin_layout Itemize +Base case: empty list, \begin_inset listings inline true status open @@ -10542,11 +10539,8 @@ case class List0[A]() . \end_layout -\begin_layout Standard -\begin_inset Formula $\bullet$ -\end_inset - - Inductive step: given a list of a previously defined length, say +\begin_layout Itemize +Inductive step: given a list of a previously defined length, say \begin_inset listings inline true status open @@ -11175,7 +11169,7 @@ List[A] \end_inset - in a slightly different way: + in a different way: \begin_inset listings inline false status open @@ -11700,7 +11694,7 @@ def map[A, B](xs: List[A])(f: A => B): List[B] = xs match { \begin_layout Plain Layout - case head :: tail => f(head) :: map(tail)(f) // Not tail-recursive. + case head :: tail => f(head) :: map(tail)(f) \end_layout \end_inset @@ -11711,31 +11705,7 @@ ve. \end_layout \begin_layout Standard -Instead of implementing the often-used methods such as -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -map -\end_layout - -\end_inset - - or -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -filter -\end_layout - -\end_inset - - one by one, let us implement +To resolve this issue, let us implement a tail-recursive \begin_inset listings inline true status open @@ -11747,7 +11717,7 @@ foldLeft \end_inset -, because most of the other methods can be expressed via +, because many methods can be expressed via \begin_inset listings inline true status open @@ -11760,11 +11730,7 @@ foldLeft \end_inset . - -\end_layout - -\begin_layout Standard -The required type signature is: + The required type signature is: \begin_inset listings inline false status open @@ -11841,7 +11807,7 @@ status open \begin_layout Plain Layout -head:A +head: A \end_layout \end_inset @@ -11853,7 +11819,7 @@ status open \begin_layout Plain Layout -tail:List[A] +tail: List[A] \end_layout \end_inset @@ -12016,19 +11982,19 @@ res0: List[Int] = List(3, 2, 1) \end_inset -Without the explicit type annotation +Without the explicit type annotation ( \begin_inset listings inline true status open \begin_layout Plain Layout -Nil:List[A] +Nil: List[A] \end_layout \end_inset -, the Scala compiler will decide that +), the Scala compiler will decide that \begin_inset listings inline true status open @@ -12053,7 +12019,7 @@ List[Nothing] \end_inset , and the types will not match later in the code. - In Scala, one often finds that the initial value for + In Scala, the initial value for \begin_inset listings inline true status open @@ -12065,7 +12031,7 @@ foldLeft \end_inset - needs an explicit type annotation. + often needs an explicit type annotation. \end_layout \begin_layout Standard @@ -12216,7 +12182,7 @@ map \end_inset - using low-level tricks for better performance.) + using mutable variables to improve performance.) \end_layout \begin_layout Subsubsection @@ -13019,7 +12985,7 @@ status open \begin_layout Plain Layout -def map[A,B](xs: NEL[A])(f: A => B): NEL[B] = ??? +def mapNEL[A,B](xs: NEL[A])(f: A => B): NEL[B] = ??? \end_layout \begin_layout Plain Layout @@ -13028,7 +12994,7 @@ def map[A,B](xs: NEL[A])(f: A => B): NEL[B] = ??? \begin_layout Plain Layout -scala> map[Int, Int](toNEL(10, List(20, 30)))(_ + 5) +scala> mapNEL[Int, Int](toNEL(10, List(20, 30)))(_ + 5) \end_layout \begin_layout Plain Layout @@ -13090,6 +13056,70 @@ res8: NEL[Int] = More(1,More(2,More(3,More(4,Last(5))))) \end_inset +\end_layout + +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Disjunctive-Exercise-non-empty-list-2-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Disjunctive-Exercise-non-empty-list-2-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Implement +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +flatten +\end_layout + +\end_inset + + for non-empty lists: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def flattenNEL[A](xs: NEL[Nel[A]]): NEL[A] = ??? +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> flattenNEL(More(More(1, Last(2)), More(More(3, Last(4)), Last(More(5, + Last(6)))))) +\end_layout + +\begin_layout Plain Layout + +res9: NEL[Int] = More(1,More(2,More(3,More(4,More(5,Last(6)))))) +\end_layout + +\end_inset + + \end_layout \begin_layout Subsection @@ -14588,7 +14618,7 @@ status open \begin_layout Plain Layout -xs:PTree[(A, A)] +xs: PTree[(A, A)] \end_layout \end_inset @@ -16562,6 +16592,12 @@ Define a disjunctive type that describes the real roots of the equation \end_inset are arbitrary real numbers. + Write a function that returns a value of that type and solves a given equation + of the form +\begin_inset Formula $ax^{2}+bx+c=0$ +\end_inset + +. \end_layout \begin_layout Subparagraph @@ -16715,6 +16751,121 @@ NoRoots() for all three different no-roots cases. \end_layout +\begin_layout Standard +To solve a given equation, we need to decide which part of the disjunctive + type to return. + The code is: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +def solveQ2(a: Double, b: Double, c: Double) : RootsOfQ2 = (a, b, c) match + { +\end_layout + +\begin_layout Plain Layout + + case (0.0, 0.0, 0.0) => AllRoots() +\end_layout + +\begin_layout Plain Layout + + case (0.0, 0.0, _) => NoRealRoots() +\end_layout + +\begin_layout Plain Layout + + case (0.0, _, _) => Linear(-c / b) +\end_layout + +\begin_layout Plain Layout + + case _ => // We match here only if `a` is nonzero. +\end_layout + +\begin_layout Plain Layout + + val d = b * b - 4 * a * c +\end_layout + +\begin_layout Plain Layout + + val p = - b / (2.0 * a) +\end_layout + +\begin_layout Plain Layout + + if (d < 0.0) NoRealRoots() +\end_layout + +\begin_layout Plain Layout + + else if (d == 0.0) OneRootQ(p) +\end_layout + +\begin_layout Plain Layout + + else { +\end_layout + +\begin_layout Plain Layout + + val s = math.sqrt(d) / (2.0 * a) +\end_layout + +\begin_layout Plain Layout + + TwoRootsQ(p - s, p + s) +\end_layout + +\begin_layout Plain Layout + + } +\end_layout + +\begin_layout Plain Layout + +} +\end_layout + +\end_inset + +Let us test this code with various input parameters: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +scala> solveQ2(1, 1, 1) +\end_layout + +\begin_layout Plain Layout + +res0: RootsOfQ2 = NoRealRoots() +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> solveQ2(1, 0, -4) +\end_layout + +\begin_layout Plain Layout + +res1: RootsOfQ2 = TwoRootsQ(-2.0, 2.0) +\end_layout + +\end_inset + + +\end_layout + \begin_layout Subsubsection Example \begin_inset CommandInset label @@ -16789,7 +16940,7 @@ val rootAverage: RootsOfQ2 => Option[Double] = ??? \end_inset -The function should return +Return \begin_inset listings inline true status open @@ -16801,7 +16952,7 @@ None \end_inset - if the average is undefined. + if the average is undefined (no roots or all values are roots). \end_layout \begin_layout Subparagraph @@ -17771,7 +17922,7 @@ Either[A, Option[B]] \end_inset . - We execute the same argument as before: The return value must be + We use the same argument as before: The return value must be \begin_inset listings inline true status open @@ -17895,7 +18046,7 @@ def f1[A, B]: Option[Either[A, B]] => Either[A, Option[B]] = { \begin_layout Plain Layout - case None => Right(None) // No other choice here. + case None => Right(None) // No other choice here. \end_layout \begin_layout Plain Layout @@ -17905,7 +18056,7 @@ def f1[A, B]: Option[Either[A, B]] => Either[A, Option[B]] = { \begin_layout Plain Layout - case Left(a) => Left(a) // Could return Right(None) here. + case Left(a) => Left(a) // Could return Right(None) here. \end_layout \begin_layout Plain Layout @@ -17925,7 +18076,7 @@ def f1[A, B]: Option[Either[A, B]] => Either[A, Option[B]] = { \end_inset -Let us decide whether to return +Should we return \begin_inset listings inline true status open @@ -17949,8 +18100,7 @@ Right(None) \end_inset - in line 4. - Both choices will satisfy the required return type + in line 4? Both choices will satisfy the required return type \begin_inset listings inline true status open @@ -17987,7 +18137,7 @@ a: A \end_inset -, which loses information. +, losing information. \begin_inset Index idx status open @@ -18885,7 +19035,7 @@ Seq[(Double, Double)] \begin_inset Formula $\left(a,b\right)$ \end_inset - of the coefficients of + of coefficients of \begin_inset Formula $ax+b=0$ \end_inset @@ -18943,6 +19093,82 @@ noprefix "false" . \end_layout +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-disjunctive-4-1" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-disjunctive-4-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +Use the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +rootAverage +\end_layout + +\end_inset + + from Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-disjunctive-3" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + to compute the average root of +\begin_inset Formula $100$ +\end_inset + + equations whose coefficients ( +\begin_inset Formula $a$ +\end_inset + +, +\begin_inset Formula $b$ +\end_inset + +, +\begin_inset Formula $c$ +\end_inset + +) are chosen randomly between +\begin_inset Formula $0$ +\end_inset + + and +\begin_inset Formula $1$ +\end_inset + +. + Ignore equations for which the average root value is undefined. +\end_layout + \begin_layout Subsubsection Exercise \begin_inset CommandInset label @@ -19110,7 +19336,7 @@ Func[A](f) \end_inset -, create a procedure from a function +, to create a procedure from a function \begin_inset listings inline true status open @@ -19171,7 +19397,7 @@ Sequ(p1, p2) \end_inset -, execute two procedures sequentially. +, to execute two procedures sequentially. 3) \begin_inset listings inline true @@ -19184,7 +19410,7 @@ Para(p1, p2) \end_inset -, execute two procedures in parallel. +, to execute two procedures in parallel. Then implement a \begin_inset Quotes eld \end_inset @@ -19225,7 +19451,16 @@ status open \begin_layout Plain Layout -sealed trait Proc; final case class Func[A](???) // And so on. +sealed trait Proc +\end_layout + +\begin_layout Plain Layout + +final case class Func[A](???) extends Proc // And so on. +\end_layout + +\begin_layout Plain Layout + \end_layout \begin_layout Plain Layout @@ -19328,7 +19563,7 @@ def f2[A, B]: Either[A, B] => (Option[A], Option[B]) = ??? \begin_layout Plain Layout -def f3[A,B,C]: Either[A, Either[B,C]] => Either[Either[A,B], C] = ??? +def f3[A, B, C]: Either[A, Either[B, C]] => Either[Either[A, B], C] = ??? \end_layout \end_inset @@ -19669,20 +19904,19 @@ def isDoubleRoot(r: RootsOfQ) = ... \end_inset -The type of the argument +The type \begin_inset listings inline true status open \begin_layout Plain Layout -r:RootsOfQ +RootsOfQ \end_layout \end_inset - represents the mathematical domain of the function, that is, the set of - admissible values of the argument + represents the set of admissible values of the argument \begin_inset listings inline true status open @@ -19694,6 +19928,22 @@ r \end_inset +, that is, the mathematical +\series bold +domain +\series default + of the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +isDoubleRoot +\end_layout + +\end_inset + . What kind of domain is that? The set of real roots of a quadratic equation @@ -19713,14 +19963,14 @@ r \begin_inset Formula $x$ \end_inset - is pictured as a point on a line (a one-dimensional space), and pair of + is pictured as a point in a line (a one-dimensional space), and pair of numbers \begin_inset Formula $\left(x,y\right)$ \end_inset - is pictured as a point 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 + is pictured as a point in a Cartesian plane (a two-dimensional space). + The no-roots case corresponds to a zero-dimensional space, which can be + pictured as a single point (see Figure \begin_inset space ~ \end_inset @@ -19734,7 +19984,7 @@ noprefix "false" \end_inset -. +). The point, the 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 @@ -19767,7 +20017,7 @@ status open \begin_inset Note Note -status open +status collapsed \begin_layout Plain Layout \align center @@ -20049,8 +20299,8 @@ OneRootQ(x) \end_layout \begin_layout Standard -In the Scala code, each part of a disjunctive type must be distinguished - by a unique name such as +In Scala code, each part of a disjunctive type must be distinguished by + a unique name such as \begin_inset listings inline true status open @@ -20087,8 +20337,8 @@ TwoRoots \end_inset . - To represent this mathematically, we can attach a distinct label to each - part of the union. + To represent this mathematically, we need to attach a distinct label to + each part of the union. 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 @@ -20133,7 +20383,7 @@ labeled union \series bold labeled union \series default - (it is also called tagged union or disjoint union + (also a tagged union or a disjoint union \begin_inset Index idx status open @@ -20221,7 +20471,7 @@ RootsOfQ \end_inset . - This value cannot be missing, which would happen if we used an empty set + That value cannot be missing, which would happen if we used an empty set to represent the no-roots case. It is natural to use the named empty tuple \begin_inset listings @@ -20235,7 +20485,7 @@ NoRoots() \end_inset - to represent this case, just as we used a named + to represent that case, just as we used a named \begin_inset Formula $2$ \end_inset @@ -20327,7 +20577,19 @@ NoRoots() \end_inset . - This Scala value is fully analogous to the mathematical notation + The Scala value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +NoRoots() +\end_layout + +\end_inset + + is fully analogous to the mathematical notation \begin_inset Formula $\left(\text{\texttt{NoRoots}},u\right)_{u\in\mathbb{R}^{0}}$ \end_inset @@ -20347,7 +20609,8 @@ Unit \end_inset - except for an added name, e.g., + except for an added name. + For instance, \begin_inset listings inline true status open @@ -20359,7 +20622,7 @@ NoRoots() \end_inset - is the + can be regarded as the \begin_inset listings inline true status open @@ -20425,9 +20688,8 @@ Disjunctive types in other programming languages Disjunctive types and pattern matching turns out to be one of the defining features of FP languages. Languages that were not designed for functional programming do not support - these features, while ML, OCaml, Haskell, F#, Scala, Swift, Elm, PureScript, - and Rust support disjunctive types and pattern matching as part of the - language design. + these features, while OCaml, Haskell, F#, Scala, Swift, and Rust support + disjunctive types and pattern matching as part of the language design. \end_layout @@ -20812,7 +21074,7 @@ status open \begin_layout Plain Layout -type RootsOfQ = NoRoots | OneRoot of float | TwoRoots of float*float +type RootsOfQ = NoRoots | OneRoot of float | TwoRoots of float * float \end_layout \end_inset diff --git a/sofp-src/lyx/sofp-essay1.lyx b/sofp-src/lyx/sofp-essay1.lyx index 42904c731..f47546d94 100644 --- a/sofp-src/lyx/sofp-essay1.lyx +++ b/sofp-src/lyx/sofp-essay1.lyx @@ -544,11 +544,10 @@ The functional programming paradigm is based on mathematical principles: , and each type of data is required to match correctly during the computations. The type-checking process automatically prevents programmers from making many kinds of coding errors. - In addition, programming languages such as Scala and Haskell have a set - of features adapted to building powerful abstractions and domain-specific - languages. + In addition, programming languages such as Scala and Haskell have features + intended for building powerful abstractions and domain-specific languages. This power of abstraction is not accidental. - Since mathematics is the ultimate art of building abstractions, math-based + Mathematics is the ultimate art of building formal abstractions, and math-based functional programming languages capitalize on several millennia of mathematica l experience. \end_layout @@ -869,9 +868,8 @@ A => B \end_inset . - All modern functional languages such as OCaml, Haskell, Scala, F#, and - Swift support these three type constructions and thus obey the CH correspondenc -e. + All modern functional languages such as OCaml, Haskell, Scala, F#, Swift, + and Rust support these type constructions and obey the CH correspondence. Having a \emph on complete @@ -1015,7 +1013,7 @@ The power of abstraction \begin_layout Standard Early adopters of Scala, such as Netflix, LinkedIn, and Twitter, were implementi -ng what is now called +ng what was then called \begin_inset Quotes eld \end_inset diff --git a/sofp-src/lyx/sofp-essay3.lyx b/sofp-src/lyx/sofp-essay3.lyx index 1b42f6f09..4e5e7af76 100644 --- a/sofp-src/lyx/sofp-essay3.lyx +++ b/sofp-src/lyx/sofp-essay3.lyx @@ -2573,8 +2573,8 @@ types/functions \begin_inset CommandInset href LatexCommand href -name "https://cstheory.stackexchange.com/questions/53389" -target "https://cstheory.stackexchange.com/questions/53389" +name "https://math.andrej.com/2016/08/06/hask-is-not-a-category/" +target "https://math.andrej.com/2016/08/06/hask-is-not-a-category/" literal "false" \end_inset diff --git a/sofp-src/lyx/sofp-filterable.lyx b/sofp-src/lyx/sofp-filterable.lyx index 38d618afe..a6275e0e0 100644 --- a/sofp-src/lyx/sofp-filterable.lyx +++ b/sofp-src/lyx/sofp-filterable.lyx @@ -9814,7 +9814,7 @@ These methods are fully parametric since their code uses only the eight \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" @@ -26884,7 +26884,7 @@ always hold \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" diff --git a/sofp-src/lyx/sofp-free-type.lyx b/sofp-src/lyx/sofp-free-type.lyx index 9aed2c2fb..82ec9f05a 100644 --- a/sofp-src/lyx/sofp-free-type.lyx +++ b/sofp-src/lyx/sofp-free-type.lyx @@ -1454,7 +1454,7 @@ type mismatch; \begin_layout Plain Layout -val res4 = runFile(Read(Read(Val("file")))) +res4 = runFile(Read(Read(Val("file")))) \end_layout \begin_layout Plain Layout @@ -1588,7 +1588,7 @@ scala> runComplex(prgComplex3) // The result is incorrect, but there \begin_layout Plain Layout -val res5: Complex = Complex(11.0, -2.0) +res5: Complex = Complex(11.0, -2.0) \end_layout \end_inset diff --git a/sofp-src/lyx/sofp-higher-order-functions.lyx b/sofp-src/lyx/sofp-higher-order-functions.lyx index 2d96dd2c0..47f74ffc1 100644 --- a/sofp-src/lyx/sofp-higher-order-functions.lyx +++ b/sofp-src/lyx/sofp-higher-order-functions.lyx @@ -896,7 +896,7 @@ logWith(prefix) \end_inset -, the (immutable) value of +, the (immutable) reference to \begin_inset listings inline true status open @@ -909,8 +909,8 @@ prefix \end_inset is stored within the body of the newly created function. - This is a general feature of nameless functions: the function's body keeps - copies of all the outer-scope values it uses. + This is a general feature of nameless functions: the function's body captures + references to all the outer-scope values it uses. One sometimes says that the function's body \begin_inset Quotes eld \end_inset @@ -942,26 +942,34 @@ closures \end_inset . - One could also say that nameless functions -\begin_inset Quotes eld -\end_inset - -capture -\begin_inset Quotes erd -\end_inset + +\end_layout +\begin_layout Standard +However, nameless functions do not +\emph on +copy +\emph default values from outer scopes. + Those values are captured by reference. + This distinction is important in Scala as it supports mutable values (as + well as classes that encapsulate mutable values). \end_layout \begin_layout Standard -As another example of the capture of values, consider this code: +Here is an example of a function body capturing references to variables: \begin_inset listings inline false status open \begin_layout Plain Layout -val f: (Int => Int) = { // Parentheses around (Int => Int) are optional. +var c: Int = 10 // Mutable variable! +\end_layout + +\begin_layout Plain Layout + +val f: Int => Int = { \end_layout \begin_layout Plain Layout @@ -976,7 +984,7 @@ val f: (Int => Int) = { // Parentheses around (Int => Int) are optional. \begin_layout Plain Layout - x => p + q * x + x => p + q * x + c \end_layout \begin_layout Plain Layout @@ -1005,12 +1013,13 @@ status open \begin_layout Plain Layout -{ x => 10 + 20 * x } +{ x => 10 + 20 * x + c } \end_layout \end_inset - because the values +. + The values \begin_inset listings inline true status open @@ -1034,8 +1043,139 @@ q = 20 \end_inset - are captured. - + are local constants captured in the function's body. + However, the value +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +c +\end_layout + +\end_inset + + is captured by reference. + If we change +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +c +\end_layout + +\end_inset + +, the behavior of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f +\end_layout + +\end_inset + + will also change: +\begin_inset listings +inline false +status open + +\begin_layout Plain Layout + +scala> f(10) +\end_layout + +\begin_layout Plain Layout + +res0: Int = 220 +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> c = 1000 +\end_layout + +\begin_layout Plain Layout + +c: Int = 1000 +\end_layout + +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> f(10) +\end_layout + +\begin_layout Plain Layout + +res1: Int = 1210 +\end_layout + +\end_inset + +A captured reference to a mutable external variable +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +c +\end_layout + +\end_inset + + makes the function +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f +\end_layout + +\end_inset + + itself mutable, even though +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +f +\end_layout + +\end_inset + + was defined as a +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +val +\end_layout + +\end_inset + +. + We will avoid such code in this book and instead use immutable values. \end_layout \begin_layout Subsection @@ -1670,7 +1810,7 @@ D \end_layout \begin_layout Standard -In Scala, functions defined with multiple argument groups (enclosed in multiple +In Scala, functions defined with multiple argument lists (enclosed in multiple pairs of parentheses) are curried functions. We have seen examples of curried functions before: \begin_inset listings @@ -2549,7 +2689,7 @@ r2 \end_inset - by partially applying + by applying \begin_inset listings inline true status open @@ -2562,7 +2702,7 @@ f2 \end_inset to the first argument but not to the second. - Other than that, + Then \begin_inset listings inline true status open @@ -2671,7 +2811,11 @@ f2 \end_inset , because the syntax is shorter. - However, the types of functions + However, the +\emph on +types +\emph default + of functions \begin_inset listings inline true status open @@ -2719,6 +2863,18 @@ status open f1 \end_layout +\end_inset + + of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Int => Int => Int +\end_layout + \end_inset we can reconstruct @@ -2731,6 +2887,18 @@ status open f2 \end_layout +\end_inset + + of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(Int, Int) => Int +\end_layout + \end_inset and vice versa, without loss of information: @@ -2834,7 +3002,39 @@ equality different \emph default ; but each of them can be reconstructed from the other. - + The one-to-one correspondence between all functions of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Int => Int => Int +\end_layout + +\end_inset + + and all functions of type +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +(Int, Int) => Int +\end_layout + +\end_inset + + is what we call the +\begin_inset Quotes eld +\end_inset + +equivalence of types +\begin_inset Quotes erd +\end_inset + +. \end_layout \begin_layout Standard @@ -3981,8 +4181,8 @@ def cos_sin_parametric[A](p: (A, A), distance: (A, A) => A, ratio: (A, A) \end_layout \begin_layout Standard -Typically, a fully parametric function has all its arguments typed with - type parameters or with some combinations of type parameters, i.e., +A fully parametric function has all its arguments typed with type parameters + or with some combinations of type parameters, i.e., \series bold type expressions \series default @@ -4919,7 +5119,7 @@ String \end_layout \begin_layout Standard -Functions with type parameters are sometimes called +Functions with type parameters are often called \begin_inset Quotes eld \end_inset @@ -5019,7 +5219,7 @@ identity laws!of function composition \begin_inset Formula $f$ \end_inset - with the identity function ( + with an identity function ( \begin_inset listings inline true status open @@ -5105,8 +5305,8 @@ The composition of the identity function with an arbitrary function The resulting two laws are: \begin_inset Formula \begin{align*} -\text{left identity law of composition}:\quad & \text{id}\bef f=f\quad,\\ -\text{right identity law of composition}:\quad & f\bef\text{id}=f\quad. +\text{left identity law of function composition}:\quad & \text{id}\bef f=f\quad,\\ +\text{right identity law of function composition}:\quad & f\bef\text{id}=f\quad. \end{align*} \end_inset @@ -5386,7 +5586,7 @@ expanded form of a function \end_inset - of the same function + of the function \begin_inset Formula $f$ \end_inset @@ -6419,7 +6619,7 @@ symbolic ) without substituting any specific values for these symbols but only using some general rules and properties. This is similar to symbolic calculations in mathematics, such as -\begin_inset Formula $\left(x-y\right)\left(x^{2}+xy+y^{2}\right)=x^{3}-y^{3}$ +\begin_inset Formula $\left(x-y\right)(x^{2}+xy+y^{2})=x^{3}-y^{3}$ \end_inset . @@ -6659,7 +6859,7 @@ status open \end_inset . - Check the result in Scala: + Test in Scala: \begin_inset listings inline false status open @@ -6777,12 +6977,21 @@ expr(x,y,z) \end_inset . - In this way, we can easily apply a curried function to any number of curried - arguments. + +\begin_inset Note Note +status open + +\begin_layout Plain Layout +In this way, we can apply a curried function to several curried arguments. +\end_layout + +\end_inset + + \end_layout \begin_layout Standard -This calculation is helped by the convention that +This calculation is made easier by the convention that \begin_inset listings inline true status open @@ -6926,19 +7135,23 @@ status open \begin_layout Standard To make calculations shorter, we will write code in a mathematical notation rather than in the Scala syntax. - Type annotations are written with a colon in the superscript, for example: - + Type annotations are written with a +\emph on +colon +\emph default + in the superscript. + For example, \begin_inset Formula $x^{:\text{Int}}\rightarrow x+10$ \end_inset - instead of the Scala expression + is the code notation corresponding to the Scala expression \begin_inset listings inline true status open \begin_layout Plain Layout -((x: Int) => x + 10) +(x: Int) => x + 10 \end_layout \end_inset @@ -7240,7 +7453,7 @@ res4: Int => Int = \begin_layout Plain Layout -scala> ((p:I nt) => (z: Int) => z * p)(10)(4) +scala> ((p: Int) => (z: Int) => z * p)(10)(4) \end_layout \begin_layout Plain Layout @@ -7269,20 +7482,28 @@ In the following examples, some arguments are themselves functions. \end_inset -The result of this expression cannot be simplified any more. - It is the function +The final result, \begin_inset Formula $p\rightarrow p(2)$ \end_inset - that applies +, cannot be simplified any more. + +\end_layout + +\begin_layout Standard +The function +\begin_inset Formula $p\rightarrow p(2)$ +\end_inset + + applies \emph on its \emph default - argument + argument ( \begin_inset Formula $p$ \end_inset - to the value +) to the value \begin_inset Formula $2$ \end_inset @@ -7296,7 +7517,7 @@ its \end_inset . - So, let us apply the expression in Eq. + Let us apply expression \begin_inset space ~ \end_inset @@ -7436,7 +7657,7 @@ Finally, we need to make sure that the types match in the function \end_inset . - So + So, \begin_inset Formula $f$ \end_inset @@ -9585,7 +9806,7 @@ Q = Y \end_inset . - So + So, \begin_inset listings inline true status open @@ -9982,7 +10203,7 @@ A => B \begin_layout Plain Layout \size small -\begin_inset Formula $x^{:\text{Int}}\rightarrow f(x)$ +\begin_inset Formula $x^{:\text{Int}}\rightarrow x+1$ \end_inset @@ -10002,7 +10223,7 @@ status open \begin_layout Plain Layout -{ x: Int => f(x) } +(x: Int) => x + 1 \end_layout \end_inset @@ -10018,14 +10239,14 @@ status open \begin_layout Plain Layout \size small -a nameless function with argument +a nameless function of type \begin_inset listings inline true status open \begin_layout Plain Layout -x +Int => Int \end_layout \end_inset @@ -10079,7 +10300,7 @@ def f[A, B] = ... \begin_layout Plain Layout \size small -define a function with type parameters +a function with type parameters \end_layout \end_inset @@ -10598,14 +10819,14 @@ Stream.iterate \end_inset keeps all computed values in memory) or the user will run out of patience. - So + So, \begin_inset listings inline true status open \begin_layout Plain Layout -.find(cond) +_.find(cond) \end_layout \end_inset @@ -10662,7 +10883,7 @@ status open \end_inset To test this code, compute an approximation to -\begin_inset Formula $\sqrt{q}$ +\begin_inset Formula $\sqrt{q}\,$ \end_inset by Newton's method @@ -10721,7 +10942,7 @@ def approx_sqrt(q: Double, precision: Double): Double = { \end_inset Newton's method for -\begin_inset Formula $\sqrt{q}$ +\begin_inset Formula $\sqrt{q}\,$ \end_inset is guaranteed to converge when @@ -10831,8 +11052,8 @@ Solution \end_layout \begin_layout Standard -Let us first write down the required type signature: the function must take - an integer argument +Let us first write down the required type signature. + The function must take an integer argument \begin_inset listings inline true status open @@ -11999,7 +12220,7 @@ q[A, B](q[C, D]) \begin_inset Formula $D$ \end_inset - because these type parameters may need to be set differently from + because those type parameters may need to be set differently from \begin_inset Formula $A$ \end_inset @@ -12393,8 +12614,8 @@ noprefix "false" \end_layout \begin_layout Standard -For the following expressions, infer the most general types or determine - that the expression is not well-typed using simple type parameters: +For the following expressions, infer the most general types or show that + the expression is not well-typed with simple types: \end_layout \begin_layout Standard @@ -12433,6 +12654,34 @@ For the following expressions, infer the most general types or determine \end_layout +\begin_layout Standard +By +\begin_inset Quotes eld +\end_inset + +simple types +\begin_inset Quotes erd +\end_inset + + we mean that +\begin_inset Formula $f$ +\end_inset + +, +\begin_inset Formula $g$ +\end_inset + +, +\begin_inset Formula $h$ +\end_inset + + cannot have +\emph on +their own +\emph default + type parameters. +\end_layout + \begin_layout Subparagraph Solution \end_layout @@ -12507,6 +12756,46 @@ Solution is not well-typed. \end_layout +\begin_layout Standard +This conclusion holds only because we do not allow the function +\begin_inset Formula $f$ +\end_inset + + to have its own type parameters. + Otherwise, the expression +\begin_inset Formula $f(f)$ +\end_inset + + could be well-typed. + See, for instance, Example +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Example-hof-derive-types-3" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + showing that the expression +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +twice(twice) +\end_layout + +\end_inset + + is well-typed. +\end_layout + \begin_layout Standard \series bold @@ -12650,7 +12939,7 @@ There are no other restrictions. We have found the most general type: \begin_inset Formula \[ -\big(f^{:((B\rightarrow D)\rightarrow D)\rightarrow E}\rightarrow g^{:B}\rightarrow f(h^{:B\rightarrow D}\rightarrow h(g))\big):((B\rightarrow D)\rightarrow D)\rightarrow E)\rightarrow B\rightarrow E\quad. +\big(f^{:((B\rightarrow D)\rightarrow D)\rightarrow E}\rightarrow g^{:B}\rightarrow f(h^{:B\rightarrow D}\rightarrow h(g))\big):(((B\rightarrow D)\rightarrow D)\rightarrow E)\rightarrow B\rightarrow E\quad. \] \end_inset @@ -13082,7 +13371,7 @@ The type of this expression is \end_inset any further. - We conclude that the final simplified form of Eq. + So, the final simplified form of Eq. \begin_inset space ~ \end_inset @@ -13761,7 +14050,7 @@ noprefix "false" \begin_layout Standard Implement a fully parametric, information-preserving, curried function that - recovers an error using a given function argument. + recovers from an error using a given function argument. The type signature and an example test: \begin_inset listings inline false @@ -14296,7 +14585,7 @@ curry2 \end_inset - converting an uncurried function of type + converting a function of type \family typewriter \begin_inset listings @@ -15496,7 +15785,7 @@ In mathematics, function applications are sometimes written without parentheses, \end_inset imply parentheses as -\begin_inset Formula $2\cdot\sin\left(x\right)\cdot\cos\left(x\right)$ +\begin_inset Formula $2\cdot(\sin\left(x\right))\cdot(\cos\left(x\right))$ \end_inset . @@ -15521,7 +15810,7 @@ operators \end_layout \begin_layout Standard -Some programming languages (such as ML, OCaml, Haskell, and F#) have adopted +Some programming languages (such as OCaml, Haskell, and F#) have adopted this \begin_inset Quotes eld \end_inset @@ -15540,7 +15829,7 @@ operator syntax \begin_inset Quotes erd \end_inset -, making parentheses optional for function arguments. +, making parentheses optional for all function arguments. In those languages, \begin_inset listings inline true @@ -15567,7 +15856,7 @@ f(x) . \begin_inset Foot -status collapsed +status open \begin_layout Plain Layout The operator syntax has a long history in programming. @@ -15583,6 +15872,18 @@ cp file1 file2 \end_inset +, and also in the language +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +Tcl +\end_layout + +\end_inset + . In LISP-like languages, function applications are enclosed in parentheses but the arguments are space-separated, for example @@ -15598,8 +15899,6 @@ status open \end_inset . - Operator syntax is also used in some programming languages such as Tcl, - Groovy, and Coffeescript. \end_layout \end_inset @@ -15861,7 +16160,7 @@ status open \begin_layout Plain Layout -def summation1(a: Int, b: Int, g: Int => Int): Int = (a to b).map(g).sum +def summation1(a: Int, b: Int, g: Int => Double): Double = (a to b).map(g).sum \end_layout \begin_layout Plain Layout @@ -15870,7 +16169,7 @@ def summation1(a: Int, b: Int, g: Int => Int): Int = (a to b).map(g).sum \begin_layout Plain Layout -def summation2(a: Int, b: Int)(g: Int => Int): Int = (a to b).map(g).sum +def summation2(a: Int, b: Int)(g: Int => Double): Double = (a to b).map(g).sum \end_layout \end_inset @@ -15887,7 +16186,7 @@ scala> summation1(1, 10, { x => x * x * x + 2 * x }) \begin_layout Plain Layout -res0: Int = 3135 +res0: Double = 3135.0 \end_layout \begin_layout Plain Layout @@ -15901,7 +16200,7 @@ scala> summation2(1, 10) { x => x * x * x + 2 * x } \begin_layout Plain Layout -res1: Int = 3135 +res1: Double = 3135.0 \end_layout \end_inset diff --git a/sofp-src/lyx/sofp-induction.lyx b/sofp-src/lyx/sofp-induction.lyx index 67bd6c61e..0173b62c2 100644 --- a/sofp-src/lyx/sofp-induction.lyx +++ b/sofp-src/lyx/sofp-induction.lyx @@ -445,8 +445,7 @@ type error \end_inset - to use incorrect types in a tuple, or an incorrect number of parts of a - tuple: + to use incorrect types in a tuple, or an incorrect number of parts: \begin_inset listings inline false status open @@ -727,6 +726,20 @@ scala> c._2 res1: (String, Int) = (abc,3) \end_layout +\begin_layout Plain Layout + +\end_layout + +\begin_layout Plain Layout + +scala> c._2._1 +\end_layout + +\begin_layout Plain Layout + +res2: String = abc +\end_layout + \end_inset @@ -936,11 +949,11 @@ pattern matching \series default . - Pattern matching occurs in two situations in Scala: + Pattern matching occurs in Scala as: \end_layout \begin_layout Itemize -destructuring definition: +a destructuring definition: \begin_inset listings lstparams "mathescape=true" inline true @@ -957,6 +970,7 @@ val $pattern$ = ... \end_layout \begin_layout Itemize +a \begin_inset listings inline true status open @@ -1216,7 +1230,7 @@ z \begin_layout Standard In the example above, the left-hand side of the destructuring definition - contains a tuple pattern + contains the tuple pattern \begin_inset listings inline true status open @@ -1445,7 +1459,7 @@ c \end_inset - are as yet undefined new variables, — that is, they are + are as yet undefined new variables, — they are called \begin_inset Index idx status open @@ -1455,7 +1469,11 @@ pattern variables \end_inset -pattern variables. + +\series bold +pattern variables +\series default +. If the pattern matching succeeds, the pattern variables \begin_inset listings inline true @@ -2162,7 +2180,7 @@ sum \end_inset to manipulate sequences of tuples. - The names of the pattern variables + The names of the pattern variables ( \begin_inset Quotes eld \end_inset @@ -2202,7 +2220,7 @@ count \begin_inset Quotes erd \end_inset - are chosen to help us remember the meaning of the parts of tuples. +) are chosen to help us remember the meaning of the parts of tuples. \end_layout \begin_layout Standard @@ -3414,7 +3432,7 @@ status open \end_layout \begin_layout Standard -By definition, +Note that \begin_inset listings inline true status open @@ -3974,7 +3992,7 @@ sortBy function \emph default that computes the sorting key from a sequence element. - This gives us flexibility to elements in a custom way: + This gives us flexibility to sort elements in a custom way: \begin_inset listings inline false status open @@ -5466,20 +5484,7 @@ List(1, 2, 3) \end_inset - in the outside scope. - Using this -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -map -\end_layout - -\end_inset - - operation, we obtain: + in the outside scope: \begin_inset listings inline false status open @@ -5639,7 +5644,7 @@ status open \end_inset . - To achieve this, we use + To achieve that, we use \begin_inset listings inline true status open @@ -5651,7 +5656,7 @@ map \end_inset - with a function that computes the product and creates these nested tuples: + with a function that computes the product and creates those nested tuples: \begin_inset listings inline false status open @@ -5699,7 +5704,7 @@ status open \end_inset -, and later map each tuple +, and later mapping each tuple \begin_inset listings inline true status open @@ -7875,7 +7880,7 @@ status open \begin_layout Plain Layout -p:Seq[String] +p: Seq[String] \end_layout \end_inset @@ -7887,7 +7892,7 @@ status open \begin_layout Plain Layout -q:Seq[Int] +q: Seq[Int] \end_layout \end_inset @@ -9281,7 +9286,7 @@ def digitsToInt(ds: Seq[Int]): Int = { \begin_layout Plain Layout -scala> digitsToInt(Seq(2,4,0,5)) +scala> digitsToInt(Seq(2, 4, 0, 5)) \end_layout \begin_layout Plain Layout @@ -9469,7 +9474,7 @@ f \end_inset - is only defined for non-empty sequences, we need to specify what the function + is defined only for non-empty sequences, we need to specify what the function \begin_inset listings inline true @@ -10164,9 +10169,7 @@ xs \end_inset . - In the base case, we need to prove that the property holds for the base - case of the function's definition. - In the base case, we need to prove that the property holds for an empty + In the base case, we need to prove that the property holds for an empty sequence \begin_inset listings inline true @@ -10389,8 +10392,8 @@ reduce \end_inset . - Most often it is better to use the standard library functions, but sometimes - the code is more transparent when using explicit recursion. + Often it is better to use library functions, but sometimes the code is + more transparent when recursion is explicit. So, let us consider each of these ways in turn. \end_layout @@ -10453,7 +10456,7 @@ infiniteLoop: (x: Int)Int \begin_layout Plain Layout -scala> infiniteLoop(2) // You will need to press Ctrl-C to stop this. +scala> infiniteLoop(0) // You will need to press Ctrl-C to stop this. \end_layout \end_inset @@ -10733,12 +10736,12 @@ x \begin_layout Standard For computing the sum of a numerical sequence, the order of summation does not matter. - However, the order of operations + But the order of operations \emph on will \emph default matter for many other computational tasks. - We need to choose whether the inductive step should split the sequence + We will need to choose whether the inductive step should split the sequence as \begin_inset listings inline true @@ -10810,7 +10813,7 @@ def digitsToInt(s: Seq[Int]): Int = if (s.isEmpty) 0 else { \begin_layout Plain Layout - val xs = s.take(s.length - 1) // and xs. + val xs = s.init // and xs. \end_layout \begin_layout Plain Layout @@ -10864,7 +10867,19 @@ x +: xs . The reason is that digits increase their numerical value from right to - left, so the correct result is computed if we split + left, so the correct result is computed as +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +digitsToInt(xs) * 10 + x +\end_layout + +\end_inset + + if we split \begin_inset listings inline true status open @@ -10889,30 +10904,27 @@ xs :+ x \end_inset - and multiply +. + For that splitting, we use the standard library methods \begin_inset listings inline true status open \begin_layout Plain Layout -digitsToInt(xs) +init \end_layout \end_inset - by -\begin_inset Formula $10$ -\end_inset - - before adding + and \begin_inset listings inline true status open \begin_layout Plain Layout -x +last \end_layout \end_inset @@ -11378,19 +11390,7 @@ lengthT(...) \end_inset . - In the code of -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -lengthT -\end_layout - -\end_inset - -, recursive calls never occur within any sub-expressions. + \end_layout \begin_layout Standard @@ -11711,7 +11711,7 @@ lengthT \end_inset - is the additional argument, + is the additional argument ( \begin_inset listings inline true status open @@ -11723,7 +11723,7 @@ res \end_inset -, called the +), called the \series bold accumulator \series default @@ -11768,7 +11768,7 @@ res + 1 ) is computed and passed on to the next recursive call via the accumulator argument. In the base case of the recursion, the function now returns the accumulated - result, + result ( \begin_inset listings inline true status open @@ -11780,7 +11780,7 @@ res \end_inset -, rather than +) rather than \begin_inset listings inline true status open @@ -12223,7 +12223,12 @@ associativity law \series default of addition. So, the computation can be rearranged to group all additions to the left. - The accumulator value is the result of adding up to some number of parentheses. + During the evaluation, the accumulator's value corresponds to a certain + number of left-grouped parentheses, +\begin_inset Formula $\left(\left(0+1\right)...\right)+1$ +\end_inset + +. In code, it means that intermediate expressions are fully computed before making recursive calls. So, recursive calls always occur outside all other sub-expressions — that @@ -12660,11 +12665,12 @@ noprefix "false" \end_inset . - Then write the inductive step (we will use the symbol + Then write the inductive step. + We use the symbol \begin_inset Formula $\overset{?}{=}$ \end_inset - to denote equations we still need to prove): + to denote equations we still need to prove: \begin_inset Formula \begin{equation} f([x]\pplus s,r)\overset{?}{=}d([x]\pplus s)+r*10^{\left|s\right|+1}\quad.\label{eq:stmt-need-to-prove-step} @@ -12688,7 +12694,7 @@ noprefix "false" \end_inset -): +) is: \begin_inset Formula \begin{align*} & f([x]\pplus s,r)\\ @@ -12716,7 +12722,7 @@ noprefix "false" \begin_inset Formula $d([x]\pplus s)$ \end_inset -, which we somehow need to simplify. +, which we now need to rewrite. Assuming that \begin_inset Formula $d(s)$ \end_inset @@ -12916,7 +12922,7 @@ noprefix "false" \end_inset -This demonstrates Eq. +This establishes Eq. \begin_inset space ~ \end_inset @@ -12966,7 +12972,7 @@ aggregation converts a sequence of values into a single value. In general, the type of the result may be different from the type of sequence elements. - To describe that general situation, we introduce type parameters, + To describe that general situation, we introduce type parameters \begin_inset listings inline true status open @@ -13083,7 +13089,7 @@ f(xs :+ x) = g(x, b) \end_inset - where +, where \begin_inset listings inline true status open @@ -13095,7 +13101,7 @@ g \end_inset - is a given function with type signature + is a given function, \begin_inset listings inline true status open @@ -13111,7 +13117,7 @@ g: (A, B) => B \end_layout \begin_layout Standard -The code implementing +The code for \begin_inset listings inline true status open @@ -13123,7 +13129,31 @@ f \end_inset - is written using recursion: + is written using recursion and the methods +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +init +\end_layout + +\end_inset + + and +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +last +\end_layout + +\end_inset + +: \begin_inset listings inline false status open @@ -13140,7 +13170,7 @@ def f[A, B](s: Seq[A]): B = \begin_layout Plain Layout - else g(s.last, f(s.take(s.length - 1))) + else g(s.last, f(s.init)) \end_layout \end_inset @@ -13188,7 +13218,7 @@ def f[A, B](s: Seq[A], b: B, g: (A, B) => B): B = \begin_layout Plain Layout - else g(s.last, f(s.take(s.length - 1), b, g) + else g(s.last, f(s.init, b, g) \end_layout \end_inset @@ -13306,7 +13336,7 @@ status open \begin_layout Plain Layout -s.take(s.length - 1) :+ s.last +s.init :+ s.last \end_layout \end_inset @@ -18084,7 +18114,7 @@ digitsOf \end_inset , ...) and the corresponding sequence of last digits, -\begin_inset Formula $n_{k}\text{ mod }10$ +\begin_inset Formula $n_{k}\,\%\,10$ \end_inset (in this example: @@ -18392,7 +18422,7 @@ Here \begin_layout Plain Layout \size small -\begin_inset Formula $n_{k}\text{ mod }10=$ +\begin_inset Formula $n_{k}\,\%\,10=$ \end_inset @@ -18670,6 +18700,10 @@ def digitsOf(n: Int): Seq[Int] = \end_inset +\begin_inset Formula $\square$ +\end_inset + + \end_layout \begin_layout Standard @@ -18698,7 +18732,7 @@ def iterate[A](init: A)(next: A => A): Stream[A] \end_inset This shows a close correspondence to a definition by mathematical induction. - The base case is the first value, + The base case is the first value ( \begin_inset listings inline true status open @@ -18710,7 +18744,7 @@ init \end_inset -, and the inductive step is a function, +) and the inductive step is a function ( \begin_inset listings inline true status open @@ -18722,7 +18756,7 @@ next \end_inset -, that computes the next element from the previous one. +) that computes the next element from the previous one. It is a general way of creating sequences whose length is not determined in advance. \end_layout @@ -19131,10 +19165,7 @@ Summary \begin_layout Standard We have seen a number of ways for translating mathematical induction into Scala code. -\end_layout - -\begin_layout Standard -What problems can we solve now? + What problems can we solve now? \end_layout \begin_layout Itemize @@ -20269,7 +20300,7 @@ 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 + The accumulator of the aggregation will be a dictionary of word counts for all the words seen so far: \begin_inset listings inline false @@ -20744,7 +20775,7 @@ status open \end_inset -We will first decide the type and the initial value of the accumulator, +We will first figure out the type and the initial value of the accumulator, then implement the updater. \end_layout @@ -21059,7 +21090,7 @@ status open \begin_layout Plain Layout -(k, k+1) +(k, k + 1) \end_layout \end_inset @@ -21218,7 +21249,8 @@ business logic \begin_inset Quotes erd \end_inset - (i.e., implementing the base case, the inductive step, and the post-processing). + (i.e., from specific computations needed in the base case, the inductive + step, and the post-processing). \end_layout \begin_layout Subsubsection @@ -21250,7 +21282,7 @@ status open \begin_layout Plain Layout -n:Int +n: Int \end_layout \end_inset @@ -21504,7 +21536,7 @@ res2: List[(Int, Int)] = List((0,0), (0,99), (99,18), (18,9), (9,9), (9,9), \begin_layout Plain Layout -scala> res2.drop(1).takeWhile { case (x, y) => x != y } +scala> res2.drop(1).takeWhile { case (x, y) => x != y } \end_layout \begin_layout Plain Layout @@ -21521,7 +21553,7 @@ status open \begin_layout Plain Layout -def sdSeq(n: Int): Seq[Int] = Stream.iterate(n)(SD) // Stream[Int] +def sdSeq(n: Int): Seq[Int] = Stream.iterate(n)(SD) // Stream[Int] \end_layout \begin_layout Plain Layout @@ -21532,17 +21564,17 @@ def sdSeq(n: Int): Seq[Int] = Stream.iterate(n)(SD) // Stream[Int] \begin_layout Plain Layout - .drop(1).takeWhile { case (x, y) => x != y } // Stream[(Int, Int)] + .drop(1).takeWhile { case (x, y) => x != y } // Stream[(Int, Int)] \end_layout \begin_layout Plain Layout - .map(_._2) // Stream[Int] + .map(_._2) // Stream[Int] \end_layout \begin_layout Plain Layout - .toList // List[Int] + .toList // List[Int] \end_layout \begin_layout Plain Layout @@ -22921,15 +22953,7 @@ foldLeft \end_layout \begin_layout Standard -We first need to determine the type of the accumulator value, or the -\begin_inset Quotes eld -\end_inset - -state -\begin_inset Quotes erd -\end_inset - -. +We first need to determine the type of the accumulator value. The task is to find the longest subsequence without adjacent duplicates. So, the accumulator should represent the longest subsequence found so far, as well as any required extra information about other subsequences that @@ -23185,7 +23209,7 @@ dsq \end_inset - that computes the sum of squared digits of a given integer; for example, + that computes the sum of squared digits of a given integer; for instance, \begin_inset listings inline true @@ -23254,7 +23278,7 @@ def digitsFSum(x: Int)(f: Int => Int): Int = ??? \begin_layout Plain Layout -scala> digitsFSum(123){ x => x * x } +scala> digitsFSum(123) { x => x * x } \end_layout \begin_layout Plain Layout @@ -23268,7 +23292,7 @@ res0: Int = 14 \begin_layout Plain Layout -scala> digitsFSum(123){ x => x * x * x } +scala> digitsFSum(123) { x => x * x * x } \end_layout \begin_layout Plain Layout @@ -23735,7 +23759,8 @@ noprefix "false" \end_inset - for a set of sets: instead of just three sets + but using a set of sets. + Instead of just three sets \begin_inset listings inline true status open @@ -23771,7 +23796,7 @@ c \end_inset -, a +, we are given a value of type \begin_inset listings inline true status open @@ -23783,7 +23808,7 @@ Set[Set[Int]] \end_inset - is given. +. The required type signature and a sample test: \begin_inset listings inline false @@ -23863,20 +23888,8 @@ noprefix "false" \end_layout \begin_layout Standard -In a sorted array -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -xs:Array[Int] -\end_layout - -\end_inset - - where no values are repeated, find all pairs of values whose sum equals - a given number +In a sorted integer array where no values are repeated, find all pairs of + values whose sum equals a given number \begin_inset Formula $n$ \end_inset @@ -23898,12 +23911,12 @@ def pairs(goal: Int, xs: Array[Int]): Set[(Int, Int)] = ??? \begin_layout Plain Layout -scala> pairs(10, Array(1, 2, 3, 4, 5, 6, 7, 8))() +scala> pairs(10, Array(1, 2, 4, 5, 6, 8)) \end_layout \begin_layout Plain Layout -res0: Set[(Int, Int)] = Set((2,8), (3,7), (4,6), (5,5)) +res0: Set[(Int, Int)] = Set((2,8), (4,6), (5,5)) \end_layout \end_inset @@ -23957,7 +23970,7 @@ A quick brown fox \begin_inset Quotes erd \end_inset -) // Words are separated by a single space. +) // Words are separated by one space. \end_layout \begin_layout Plain Layout @@ -25129,7 +25142,7 @@ Total and partial functions \end_layout \begin_layout Standard -In Scala, functions can be total or partial. +Functions can be total or partial. A \series bold @@ -25237,7 +25250,7 @@ java.lang.UnsupportedOperationException: empty.max \end_inset -This kind of error may crash the entire program at run time. +This kind of error may crash a program at run time. Unlike the type errors \begin_inset Index idx status open @@ -25266,13 +25279,13 @@ run-time error 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. + which may crash the program in the middle of a long computation. \end_layout \begin_layout Standard -So, it seems clear that we should write code that does not generate such +So, it seems clear that we should avoid writing code that generates such errors. - For instance, it is safe to apply + For instance, we will prefer to apply \begin_inset listings inline true status open @@ -25284,7 +25297,7 @@ max \end_inset - to a sequence if we know that it is non-empty. + only to sequences that are known to be non-empty. \end_layout \begin_layout Standard @@ -25294,11 +25307,23 @@ Sometimes, a function that uses pattern matching turns out to be a partial \end_layout \begin_layout Standard -If a pattern matching expression fails, the code will throw an exception - and stop running. - In functional programming, we usually want to avoid 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 +If none of the cases matches in a pattern matching expression, the code + will throw an exception (a +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +MatchError +\end_layout + +\end_inset + +). + In functional programming, we usually want to avoid that situation because + reasoning about program correctness becomes hard. + In most cases, programs can be rewritten to avoid the possibility of match errors. An example of an unsafe pattern matching expression is: \begin_inset listings @@ -25408,7 +25433,7 @@ h \end_layout \begin_layout Standard -Pattern matching failures never happen if we match a tuple of correct size +Pattern matching errors never happen if we match a tuple of correct size with a pattern such as \begin_inset listings inline true @@ -25603,7 +25628,7 @@ def f(x: (Int, Int)): Int = x match { case (x, y) => x + y } \begin_layout Plain Layout -scala> f( (2,4) ) +scala> f( (2, 4) ) \end_layout \begin_layout Plain Layout @@ -25644,7 +25669,7 @@ status open \begin_layout Plain Layout -(Int,Int) +(Int, Int) \end_layout \end_inset @@ -25851,7 +25876,8 @@ bound variable \end_layout \begin_layout Standard -The problem is easy to avoid: we can give the pattern variable another name. +This problem is easy to avoid: we can give the pattern variable another + name. Since the pattern variable is locally scoped, it can be renamed within its scope without affecting any other code: \begin_inset listings @@ -25922,7 +25948,7 @@ infinite \begin_inset Quotes erd \end_inset - sequences, although in practice a stream is always finite because computers + sequences, although in practice a stream is always finite because programs cannot run infinitely long. Also, computers cannot store infinitely many values in memory. @@ -27087,7 +27113,7 @@ immutable value , \series default - i.e., cannot be changed. + i.e., cannot be modified. (What would it mean to \begin_inset Quotes eld \end_inset @@ -27472,7 +27498,11 @@ was \emph on partially \emph default - correct numbers. + +\emph on +correct +\emph default + numbers. \end_layout \begin_layout Standard @@ -27526,23 +27556,7 @@ iter \end_inset is used twice in this code, which leads to errors. - Apparently, -\begin_inset listings -inline true -status open - -\begin_layout Plain Layout - -iter -\end_layout - -\end_inset - - -\emph on -does not behave as a value -\emph default -! Creating an + Creating an \begin_inset listings inline true status open @@ -27921,7 +27935,7 @@ side effect Examples of side effects are: modifying a value stored in memory; starting and stopping processes or threads; reading or writing files; printing; sending or receiving data over a network; showing images on a display; - playing or recording sounds; getting photo or video from a digital camera. + playing or recording sounds; getting photos or videos from a digital camera. \end_layout @@ -27931,8 +27945,8 @@ Code that performs side effects does not behave as a value. not the same as just re-using the result value twice. A function with a side effect may return different values each time it is called, even when the same arguments are given to the function. - (For example, a digital camera will typically give a different image each - time.) + (For example, a digital camera will typically return a different image + each time.) \begin_inset Index idx status open @@ -28005,7 +28019,7 @@ def sum(xs: Seq[Int]): Int = { \begin_layout Plain Layout - var result: Int = 0 // A mutable variable! + var result: Int = 0 // A mutable variable. \end_layout \begin_layout Plain Layout diff --git a/sofp-src/lyx/sofp-monads.lyx b/sofp-src/lyx/sofp-monads.lyx index ed78169ca..4dc5f2a38 100644 --- a/sofp-src/lyx/sofp-monads.lyx +++ b/sofp-src/lyx/sofp-monads.lyx @@ -19540,7 +19540,29 @@ flatten \end_inset - function defined as + function +\begin_inset Index idx +status open + +\begin_layout Plain Layout +naturality law!of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +flatten +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + defined as \begin_inset Formula $\text{ftn}\triangleq\text{flm}\left(\text{id}\right)$ \end_inset @@ -29571,14 +29593,14 @@ flatMap Exercise \begin_inset CommandInset label LatexCommand label -name "subsec:Exercise-1-monads-3" +name "subsec:Exercise-1-monads-3-2" \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Exercise-1-monads-3" +reference "subsec:Exercise-1-monads-3-2" plural "false" caps "false" noprefix "false" @@ -29604,6 +29626,120 @@ Reader monad by an explicit derivation. \end_layout +\begin_layout Subsubsection +Exercise +\begin_inset CommandInset label +LatexCommand label +name "subsec:Exercise-1-monads-3" + +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exercise-1-monads-3" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + +\end_layout + +\begin_layout Standard +The naturality law +\begin_inset space ~ +\end_inset + +( +\begin_inset CommandInset ref +LatexCommand ref +reference "eq:naturality-law-of-flatten" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +) of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +flatten +\end_layout + +\end_inset + + is written in the code notation as: +\begin_inset Index idx +status open + +\begin_layout Plain Layout +naturality law!of +\begin_inset listings +inline true +status open + +\begin_layout Plain Layout + +flatten +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Formula +\[ +f^{\uparrow S\uparrow S}\bef\text{ftn}_{S}=\text{ftn}_{S}\bef f^{\uparrow S}\quad. +\] + +\end_inset + +Show that one +\emph on +cannot +\emph default + replace +\begin_inset Formula $f^{\uparrow S}$ +\end_inset + + in that law by an arbitrary function +\begin_inset Formula $g:S^{A}\rightarrow S^{B}$ +\end_inset + +. + Find a counterexample with a specific +\begin_inset Formula $S$ +\end_inset + +, +\begin_inset Formula $A$ +\end_inset + +, +\begin_inset Formula $B$ +\end_inset + +, and +\begin_inset Formula $g:S^{A}\rightarrow S^{B}$ +\end_inset + + for which +\begin_inset Formula $g^{\uparrow S}\bef\text{ftn}_{S}\neq\text{ftn}_{S}\bef g$ +\end_inset + +. +\end_layout + \begin_layout Subsubsection Exercise \begin_inset CommandInset label diff --git a/sofp-src/lyx/sofp-nameless-functions.lyx b/sofp-src/lyx/sofp-nameless-functions.lyx index 2d31e2e48..b08bb31d3 100644 --- a/sofp-src/lyx/sofp-nameless-functions.lyx +++ b/sofp-src/lyx/sofp-nameless-functions.lyx @@ -966,7 +966,7 @@ maps to \begin_inset Formula \[ -x\rightarrow\left(\text{some formula}\right)\quad. +x\rightarrow\left(\text{some formula that may use }x\right)\quad. \] \end_inset @@ -2473,7 +2473,7 @@ only inside \end_inset -\begin_inset Formula $\forall k.\,...$ +\begin_inset Formula $\forall k...$ \end_inset @@ -3781,7 +3781,7 @@ def countEven(s: List[Int]): Int = s \end_layout \begin_layout Standard -In Scala, methods are often used one after another, as if in a chain. +In Scala, methods are often used one after another in a chain. For instance, \begin_inset listings inline true @@ -4374,7 +4374,7 @@ status open \begin_layout Plain Layout -scala> List(1, 2, 3, 4, 5).filter(k => k != 3) // Exclude the value +scala> List(1, 2, 3, 4, 5).filter(k => k != 3) // Exclude the value 3. \end_layout @@ -4438,7 +4438,7 @@ status open \begin_layout Plain Layout -scala> List(1, 2, 3, 4, 5).takeWhile(k => k != 3) // Truncate at the value +scala> List(1, 2, 3, 4, 5).takeWhile(k => k != 3) // Truncate at the value 3. \end_layout @@ -7522,7 +7522,7 @@ Mathematical intuition is useful for programming tasks because it is backed \end_inset , and to develop the corresponding rules of calculation. - Converting formulas into code, FP capitalizes on the power of these reasoning + Converting formulas into code, FP capitalizes on the power of those reasoning tools. \end_layout @@ -7637,12 +7637,19 @@ Here the index \end_inset . - And yet no mathematics textbook would define this formula via loops or - by saying + No mathematics textbook would define the standard deviation +\begin_inset Formula $\sigma$ +\end_inset + + via loops or by saying \begin_inset Quotes eld \end_inset -now repeat this equation ten times +now repeat this equation +\begin_inset Formula $n$ +\end_inset + + times \begin_inset Quotes erd \end_inset @@ -7651,7 +7658,7 @@ now repeat this equation ten times \begin_inset Formula $x_{i}^{2}$ \end_inset - ten times, as the value of + many times, as the value of \begin_inset Formula $x_{i}^{2}$ \end_inset @@ -7681,7 +7688,7 @@ expressions \end_inset denote certain iterative computations. - Such computations are can be defined rigorously using mathematical induction + Such computations are defined rigorously using mathematical induction \begin_inset Index idx status open @@ -7733,14 +7740,13 @@ sum . The next chapter shows more general methods for implementing inductive computations. - These methods can be combined in flexible ways, enabling programmers to + Those 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: + defined by the formula shown above is computed by this code: \begin_inset listings inline false status open @@ -7872,11 +7878,7 @@ variable \end_inset - are used first of all as -\emph on -arguments -\emph default - of functions; e.g., the formula: + are used first of all as arguments of functions; e.g., the formula: \begin_inset Formula \[ f(x)=x^{2}+x @@ -8880,7 +8882,7 @@ local scope \end_layout \begin_layout Subsection -Named and nameless expressions and their uses +Named and nameless expressions \end_layout \begin_layout Standard diff --git a/sofp-src/lyx/sofp-preface.lyx b/sofp-src/lyx/sofp-preface.lyx index 6fff8b7d2..3142b07bf 100644 --- a/sofp-src/lyx/sofp-preface.lyx +++ b/sofp-src/lyx/sofp-preface.lyx @@ -432,9 +432,9 @@ 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. + Concepts such as functors or natural transformations arise from the practice + of reasoning about code and are first explained without reference to category + theory. \end_layout diff --git a/sofp-src/lyx/sofp-reasoning.lyx b/sofp-src/lyx/sofp-reasoning.lyx index a64916c46..02b7e5db6 100644 --- a/sofp-src/lyx/sofp-reasoning.lyx +++ b/sofp-src/lyx/sofp-reasoning.lyx @@ -364,7 +364,7 @@ eight code constructions \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" @@ -2042,7 +2042,7 @@ matrix notation status open \begin_layout Plain Layout -disjunctive type!in matrix notation +disjunctive type!matrix notation \end_layout \end_inset @@ -2573,7 +2573,7 @@ n. \begin_inset CommandInset ref LatexCommand ref -reference "subsec:The-rules-of-proof" +reference "subsec:Short-notation-for-eight-code-constructions" plural "false" caps "false" noprefix "false" diff --git a/sofp-src/lyx/sofp-traversable.lyx b/sofp-src/lyx/sofp-traversable.lyx index 1d96d3891..936e72981 100644 --- a/sofp-src/lyx/sofp-traversable.lyx +++ b/sofp-src/lyx/sofp-traversable.lyx @@ -10220,8 +10220,7 @@ scala> x.run.right.get(()) // No stack overflows. \begin_layout Plain Layout -val res0: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) - +res0: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) \end_layout \begin_layout Plain Layout @@ -10235,7 +10234,7 @@ scala> x.run.right.get(()).run.right.get(()) // This is again the same value: \begin_layout Plain Layout -val res1: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) +res1: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) \end_layout \end_inset diff --git a/sofp-src/scripts/functions.sh b/sofp-src/scripts/functions.sh index 40c729e50..953da6dfd 100644 --- a/sofp-src/scripts/functions.sh +++ b/sofp-src/scripts/functions.sh @@ -50,10 +50,10 @@ function add_lulu { } function assemble_sources { - rm -f tex/*.lyx tex/*.bak tex/sofp.source_hash # Copies of LyX files and other temporary files from tex/ should not be in sources. + rm -f tex/*.lyx tex/*.bak tex/sofp.source_hash lyx/*~ lyx/\#* # Copies of LyX files and other temporary files from tex/ should not be in sources. test -d build || mkdir build tar jcvf build/"$name-src.tar.bz2" \ - README*.md LICENSE *.sh scripts tex/chapter3-picture.pdf cover tex/*.tex lyx \ + README*.md LICENSE *.sh scripts tex/chapter3-picture.pdf cover tex/*.tex lyx/*.lyx \ >& /dev/null size=$(kbSize build/"$name-src.tar.bz2") echo "File build/$name-src.tar.bz2 created, size $size bytes." diff --git a/sofp-src/scripts/prepare_volume.sh b/sofp-src/scripts/prepare_volume.sh index b0e9310a9..e0dcceb53 100644 --- a/sofp-src/scripts/prepare_volume.sh +++ b/sofp-src/scripts/prepare_volume.sh @@ -108,13 +108,14 @@ esac echo "Detected previous chapter $firstchapter, first page $firstpage, previous part number $firstpart" - sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|; s|\(\\part{.*}\)|\\setcounter{page}{'$firstpage'}\\setcounter{part}{'$firstpart'}\\setcounter{chapter}{'$firstchapter'}\1|;' $dir/$name.tex + # Title on front leaf. "Science of Functional Programming. Part I" + sed -i.bak -e 's|\(of Functional Programming\)|\1. '"$title1"'|; s|\(\\part{.*}\)|\\setcounter{page}{'$firstpage'}\\setcounter{part}{'$firstpart'}\\setcounter{chapter}{'$firstchapter'}\1|;' $dir/$name.tex - # Subtitle on cover page. + # Subtitle on cover page. "Part I: Introductory level" sed -i.bak -e 's|% End of title.|\\vspace{0.2in}\\centerline{\\fontsize{20pt}{20pt}\\selectfont{'"$title2"'}}|' $dir/sofp-cover-page-no-bg.tex - # Title on spine. - sed -i.bak -e 's|\(of Functional Programming\)|\1, '"$title1"'|;' $dir/sofp-spine.tex + # Title on spine. "Science of Functional Programming. Part I" + sed -i.bak -e 's|\(of Functional Programming\)|\1. '"$title1"'|;' $dir/sofp-spine.tex # Replace lulu.com hyperlink. sed -i.bak -e 's|{https://www.lulu.com/[^}]*}{\(Print on demand[^}]*\)}|{'"$url"'}{\1}|;' $dir/$name.tex diff --git a/sofp-src/tex/chapter3-picture.pdf b/sofp-src/tex/chapter3-picture.pdf index d18be4c35..706c13201 100644 Binary files a/sofp-src/tex/chapter3-picture.pdf and b/sofp-src/tex/chapter3-picture.pdf differ diff --git a/sofp-src/tex/sofp-appendices.tex b/sofp-src/tex/sofp-appendices.tex index dd786cbc1..6149e710d 100644 --- a/sofp-src/tex/sofp-appendices.tex +++ b/sofp-src/tex/sofp-appendices.tex @@ -750,8 +750,8 @@ \chapter{Parametricity theorem and naturality laws\label{app:Proofs-of-naturalit Functional programming focuses on a small set of language features \textemdash{} the six type constructions and the nine code constructions\index{nine code constructions}, introduced in Sections~\ref{subsec:Type-notation-and-standard-type-constructions} -and~\ref{subsec:The-rules-of-proof}. These constructions, summarized -again in Tables~\ref{tab:Mathematical-notation-for-basic-code-constructions} +and~\ref{subsec:Short-notation-for-eight-code-constructions}. These +constructions, summarized again in Tables~\ref{tab:Mathematical-notation-for-basic-code-constructions} and \ref{tab:six-pure-type-constructions}\textendash \ref{tab:nine-pure-code-constructions}, create \textbf{fully parametric} programs\index{fully parametric!code} and are sufficient to implement all design patterns of functional @@ -775,17 +775,16 @@ \chapter{Parametricity theorem and naturality laws\label{app:Proofs-of-naturalit laws for profunctors. This Appendix presents sufficient theoretical material to be able to derive all those laws. -\begin{wraptable}{l}{0.545\columnwidth}% +\begin{table} \begin{centering} -\vspace{-0.2\baselineskip} \begin{tabular}{|c|c|c|} \hline \textbf{\small{}Type construction} & \textbf{\small{}Scala example} & \textbf{\small{}Type notation}\tabularnewline \hline \hline -{\small{}unit or \textsf{``}named unit\textsf{''}} & {\small{}}\lstinline!Unit!{\small{} or }\lstinline!None!{\small{} } & {\small{}$\bbnum 1$}\tabularnewline +{\small{}unit or \textsf{``}named unit\textsf{''}} & {\small{}}\lstinline!Unit!{\small{} or }\lstinline!None! & {\small{}$\bbnum 1$}\tabularnewline \hline -{\small{}type parameter} & {\small{}}\lstinline!A!{\small{} as in }\lstinline!F[A]!{\small{} } & {\small{}$A$ as in $F^{A}$}\tabularnewline +{\small{}type parameter} & {\small{}}\lstinline!A!{\small{} as in }\lstinline!F[A]! & {\small{}$A$ as in $F^{A}$}\tabularnewline \hline {\small{}product type} & {\small{}}\lstinline!(A, B)! & {\small{}$A\times B$}\tabularnewline \hline @@ -799,7 +798,7 @@ \chapter{Parametricity theorem and naturality laws\label{app:Proofs-of-naturalit \par\end{centering} \caption{\index{fully parametric!type constructions}The six type constructions that may be used in fully parametric programs.\label{tab:six-pure-type-constructions}} -\end{wraptable}% +\end{table} \begin{table} \begin{centering} @@ -4985,7 +4984,7 @@ \subsubsection*{Exercise \ref{subsec:Exercise-hof-simple-8}} \begin{lstlisting} @tailrec def convergeN[X](p: X => Boolean)(x:X)(m:Int)(f: X => X): Option[X] = { if (m <= 0) None - else if (p(x)) Some(x) else converge(p)(f(x))(m-1)(f) } + else if (p(x)) Some(x) else converge(p)(f(x))(m - 1)(f) } // Defining it as def convergeN[X]: (X => Boolean) => X => Int => (X => X) => Option[X] = ??? // will break tail recursion! \end{lstlisting} diff --git a/sofp-src/tex/sofp-back-cover-no-bg.tex b/sofp-src/tex/sofp-back-cover-no-bg.tex index 7db4bdd92..36cd9e17a 100644 --- a/sofp-src/tex/sofp-back-cover-no-bg.tex +++ b/sofp-src/tex/sofp-back-cover-no-bg.tex @@ -25,10 +25,10 @@ parametricity theorems. Long and difficult, yet boring explanations are logically -developed in excruciating detail through 1884 +developed in excruciating detail through 1893 Scala code snippets, 191 statements with step-by-step -derivations, 103 diagrams, 221 examples -with tested Scala code, and 297 exercises. Discussions +derivations, 103 diagrams, 223 examples +with tested Scala code, and 300 exercises. Discussions build upon each chapter\textsf{'}s material further. Beginners in FP will find tutorials about the \texttt{map}/\texttt{reduce} diff --git a/sofp-src/tex/sofp-curry-howard.tex b/sofp-src/tex/sofp-curry-howard.tex index 4a5a5583f..044aae7e5 100644 --- a/sofp-src/tex/sofp-curry-howard.tex +++ b/sofp-src/tex/sofp-curry-howard.tex @@ -73,10 +73,10 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} the code should be able to \emph{return} \lstinline!x! as a result value. This requires computing \lstinline!x! in all cases, not just within one part (\lstinline!case ...!) of a pattern-matching expression. -In other words, we should be able to implement the following type -signature: +For that, one would need to implement the following type signature +via fully parametric code: \begin{lstlisting} -def bad[A, B](f: A => B)(pa: Option[A]): A = ??? +def bad[A, B](f: A => B)(pa: Option[A]): A = ??? // Cannot implement. \end{lstlisting} So, the question \textsf{``}can we compute a value of type \lstinline!A! @@ -111,15 +111,29 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} to create a function of type \lstinline!A => B!. Similarly, \lstinline!bad3! is not able to return \lstinline!Right(f)! with some \lstinline!f: A => C!. -In all these examples, we see that the impossibility of implementing -a type signature means that the information given in a function\textsf{'}s -arguments is in some way insufficient for computing the result value. +Could we try to switch between functions of type \lstinline!A => B! +and \lstinline!A => C! depending on a given value of type \lstinline!A!? +This idea means that we are working with a different type signature, +which has an additional argument of type \lstinline!A!. That type +signature \emph{can} be implemented, for instance, by this Scala code: +\begin{lstlisting} +def q[A, B, C](g: A => Either[B, C])(a: A): Either[A => B, A => C] = + g(a) match { + case Left(b) => Left(_ => b) + case Right(c) => Right(_ => c) + } +\end{lstlisting} +But \lstinline!q! does not have the required type signature of \lstinline!bad3!. + +In all these examples, we see that the a type signature cannot be +implemented because the information given in a function\textsf{'}s arguments +is in some way insufficient for computing the result value. The type signature inverse to that of \lstinline!bad3! is: \begin{lstlisting} def good3[A, B, C](q: Either[A => B, A => C]): A => Either[B, C] = ??? \end{lstlisting} -This type signature \emph{can} be implemented, but only in one way: +This type signature \emph{can} be implemented: \begin{lstlisting} def good3[A, B, C](q: Either[A => B, A => C]): A => Either[B, C] = q match { case Left(k) => { a => Left(k(a)) } @@ -142,7 +156,7 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} Can we prove rigorously that the functions \lstinline!bad!, \lstinline!bad2!, \lstinline!bad3! cannot be implemented by any fully parametric code? -Or, perhaps, we were mistaken and a clever trick \emph{could} produce +Or, perhaps, we are mistaken and a clever trick \emph{could} produce some code for those type signatures? So far, we only saw informal arguments about whether values of certain @@ -159,16 +173,16 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} arguments, which might have types, say, $X$, $Y$, ..., $Z$. So, we are interested in proving statements like this: \begin{align} - & \text{a fully parametric expression can compute a value of type }A\nonumber \\ - & \text{using previously given values of types }X,Y,...,Z\quad.\label{eq:ch-CH-proposition-def} + & \text{a fully parametric function can compute a value of type }A\nonumber \\ + & \text{using given arguments of types }X,Y,...,Z\quad.\label{eq:ch-CH-proposition-def} \end{align} Here $X$, $Y$, ..., $Z$, $A$ may be either type parameters or more complicated type expressions, such as $B\rightarrow C$ or $(C\rightarrow D)\rightarrow E$, built from some type parameters. -If values of types $X$, $Y$, ..., $Z$ are given, it means we \textsf{``}already -have\textsf{''} values of those types, i.e., the propositions ${\cal CH}(X)$, -${\cal CH}(Y)$, ..., ${\cal CH}(Z)$ will be already true. So, proposition~(\ref{eq:ch-CH-proposition-def}) +If arguments of types $X$, $Y$, ..., $Z$ are given, it means we +\textsf{``}already have\textsf{''} values of those types, i.e., the propositions ${\cal CH}(X)$, +${\cal CH}(Y)$, ..., ${\cal CH}(Z)$ will be true. So, proposition~(\ref{eq:ch-CH-proposition-def}) 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)} @@ -181,10 +195,11 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} the proposition ${\cal CH}(A)$ is called the \textbf{goal}\index{sequent (in logic)!goal} of the sequent. -Sequents provide a notation for the questions about types of fully -parametric functions. Since our goal is to answer such questions rigorously, -we will need to be able to \emph{prove} sequents of the form~(\ref{eq:ch-example-sequent}). -The following sequents correspond to the type signatures we just saw: +Sequents provide a notation for questions about implementability of +fully parametric functions. Since our goal is to answer such questions +rigorously, we will need to be able to \emph{prove} sequents of the +form~(\ref{eq:ch-example-sequent}). The following sequents correspond +to the type signatures we just saw: \begin{align*} {\color{greenunder}\text{\texttt{fmap} for \texttt{Option}}:}\quad & {\cal CH}(\text{\texttt{A => B}})\vdash{\cal CH}(\text{\texttt{Option[A] => Option[B]}})\\ {\color{greenunder}\text{the function \texttt{before}}:}\quad & {\cal CH}(\text{\texttt{A => B}}),{\cal CH}(\text{\texttt{B => C}})\vdash{\cal CH}(\text{\texttt{A => C}})\\ @@ -198,62 +213,181 @@ \subsection{Motivation and outlook\label{subsec:Motivation-and-outlook}} In formal logic, sequents are proved\index{proof (in logic)} by starting with certain axioms and following certain derivation rules. Different choices of axioms and derivation rules will give different \emph{logics}. -We will need to discover the correct logic for reasoning about sequents -with ${\cal CH}$-propositions. To discover that logic\textsf{'}s complete -set of axioms and derivation rules, we need to examine systematically -what types and code constructions are possible in a fully parametric +We need to discover the correct logic for reasoning about sequents +with ${\cal CH}$-propositions. To find that logic\textsf{'}s complete set +of axioms and derivation rules, we will systematically examine all +the types and code constructions that are possible in a fully parametric function. The resulting logic is known under the name \textsf{``}constructive -logic\textsf{''}. That logic\textsf{'}s axioms and derivation rules directly correspond -to programming language constructions allowed by fully parametric -code. For that reason, constructive logic gives correct answers about -implementable and non-implementable type signatures of fully parametric -functions. +propositional logic\textsf{''}. That logic\textsf{'}s axioms and derivation rules directly +correspond to programming language constructions allowed by fully +parametric code. For that reason, constructive propositional logic +gives correct answers about implementable and non-implementable type +signatures of fully parametric functions. -We will then be able to borrow the results and methods already available -in the mathematical literature on formal logic. The main result is -an algorithm (called LJT) for finding a proof for a given sequent -in the constructive logic. If a proof is found, the algorithm also -provides the code of a function that has the type signature corresponding -to the sequent. If a proof is not found, it means that the given type -signature cannot be implemented by fully parametric code. +We will then be able to borrow the results and methods available in +the mathematical literature. The main result is an algorithm (called +LJT) for finding a proof for a given sequent in the constructive propositional +logic. If a proof is found, the algorithm also provides the code of +a function that has the type signature corresponding to the sequent. +If a proof is not found, it means that the given type signature cannot +be implemented by fully parametric code. -\subsection{Type notation and ${\cal CH}$-propositions for standard type constructions\label{subsec:Type-notation-and-standard-type-constructions}} +\subsection{Type notation for standard type constructions\label{subsec:Type-notation-and-standard-type-constructions}} -Here and in the following sections, we will be reasoning about sequents -of the form: +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 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)$. +be convenient 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 -of reasoning about ${\cal CH}$-propositions for case classes and -for disjunctive types. We will now extend this reasoning systematically -to all type constructions that fully parametric programs could use. -The result will be that we rewrite ${\cal CH}$-propositions with -arbitrary type expressions, such as ${\cal CH}($\lstinline!Either[(A, A), Option[B] => Either[(A, B), C]]!$)$, -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} on page~\pageref{chap:Appendix-Notations} -for a summary of the type notation.) +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} +on page~\pageref{chap:Appendix-Notations} for a full summary of +the type notation.) There exist \textbf{six} \textbf{standard type constructions}\index{six type constructions} 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. +types}), function types, parameterized types, and recursive types. + +We now define a shorter notation for those types. This notation is +often found in the literature on functional programming languages, +except we are using \emph{superscripts} to denote type parameters. +\begin{center} +\begin{tabular}{|c|c|c|} +\hline +\textbf{\small{}Description} & \textbf{\small{}Scala syntax} & \textbf{\small{}Type notation}\tabularnewline +\hline +\hline +{\small{}Unit type} & \lstinline!Unit! & $\bbnum 1$\tabularnewline +\hline +{\small{}Void type} & \lstinline!Nothing! & $\bbnum 0$\tabularnewline +\hline +{\small{}Built-in types} & {\small{}}\lstinline!Int!{\small{}, }\lstinline!String!{\small{}, +...} & {\small{}$\text{Int}$, $\text{String}$, ...}\tabularnewline +\hline +{\small{}Tuple type} & \lstinline!(A, B)! & $A\times B$\tabularnewline +\hline +{\small{}Disjunctive type} & \lstinline!Either[A, B]! & $A+B$\tabularnewline +\hline +{\small{}Function type} & \lstinline!A => B! & $A\rightarrow B$\tabularnewline +\hline +{\small{}Parameterized types} & \lstinline!def f[A]: F[A]! & $f^{A}:F^{A}${\small{} or $f:\forall A.\,F^{A}$}\tabularnewline +\hline +\end{tabular} +\par\end{center} + +Tuples and case classes with more than two parts are denoted by $A\times B\times C$ +or $A\times B\times C\times D$, etc. For example, the Scala definition: +\begin{lstlisting} +case class Person(firstName: String, lastName: String, age: Int) +\end{lstlisting} +is written in the type notation as $\text{String}\times\text{String}\times\text{Int}$. + +The Scala type \lstinline!Either[A, B]! is written as $A+B$, and +disjunctive types with more parts are written as $A+B+C$ and so on. +As another example, the Scala definition: +\begin{lstlisting} +sealed trait RootsOfQ +final case class NoRoots() extends RootsOfQ +final case class OneRoot(x: Double) extends RootsOfQ +final case class TwoRoots(x: Double, y: Double) extends RootsOfQ +\end{lstlisting} +is translated to the type notation as: +\[ +\text{RootsOfQ}\triangleq\bbnum 1+\text{Double}+\text{Double}\times\text{Double}\quad. +\] +The type notation is significantly shorter because it omits all case +class names and part names from the Scala type definitions. + +To clarify our notation for parameterized types, consider this code: +\begin{lstlisting} +def f[A, B]: A => (A => B) => B = { x => g => g(x) } +\end{lstlisting} +The type notation for the type signature of \lstinline!f! may be +written as: +\[ +f^{A,B}:A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\quad\text{or equivalently}:\quad f:\forall(A,B).\,A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad. +\] +The type quantifier $\forall(A,B)$ (reads \textsf{``}for all $A$ and $B$\textsf{''}) +indicates that $f$ can be used with all types $A$ and $B$. + +In Scala, 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 signature of the function \lstinline!f! looks +like this: +\begin{lstlisting} +type F[A, B] = A => (A => B) => B +def f[A, B]: F[A, B] = { x => g => g(x) } +\end{lstlisting} +This is written in the type notation by placing all type parameters +into superscripts: +\begin{align*} +F^{A,B} & \triangleq A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\\ +f^{A,B}:F^{A,B} & \triangleq x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad, +\end{align*} +or equivalently (although less readably) as: +\[ +f:\big(\forall(A,B).\,F^{A,B}\big)\triangleq\,^{A,B}\rightarrow x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad. +\] + +In Scala 3, the function \lstinline!f! can be written as a value +(\lstinline!val!) via this syntax: +\begin{lstlisting} +val f: [A, B] => A => (A => B) => B = { // Valid only in Scala 3. + [A, B] => (x: A) => (g: A => B) => g(x) +} +\end{lstlisting} +This syntax closely corresponds to the code notation $\,^{A,B}\rightarrow x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)$. + +The precedence\index{type notation!operator precedence} of operators +in the type notation is chosen in order to write fewer parentheses +in some frequently used type expressions. The rules of precedence +are: +\begin{itemize} +\item The type product operator ($\times$) groups stronger than the disjunctive +operator ($+$), so that type expressions such as $A+B\times C$ have +the same operator precedence as in arithmetic. That is, $A+B\times C$ +means $A+\left(B\times C\right)$. This convention makes type expressions +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$ +(representing \lstinline!((A, B)) => C!) can be written without any +parentheses. Type expressions such as $\left(A\rightarrow B\right)\times C$ +will require parentheses but are needed less often. +\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 at the top level of a type expression. When that +is not the case, parentheses are necessary. An example is the type +expression $\left(\forall A.\,A\rightarrow A\rightarrow A\right)\rightarrow\bbnum 1+\bbnum 1$. +\end{itemize} + +\subsection{Rules for writing ${\cal CH}$-propositions} + +In Section~\ref{subsec:Disjunctions-and-conjunctions} we saw examples +of reasoning about ${\cal CH}$-propositions for case classes and +for disjunctive types. This reasoning needs to be extended systematically +to all type constructions that fully parametric programs may use. +Then we will be able to express ${\cal CH}$-propositions with arbitrary +type expressions, such as ${\cal CH}($\lstinline!Either[(A, A), Option[B] => Either[(A, B), C]]!$)$, +in terms of ${\cal CH}$-propositions for simple type parameters: +${\cal CH}(A)$, ${\cal CH}(B)$, etc. + We will now derive the rules for writing ${\cal CH}$-propositions -for each of these type constructions except recursive types. +for each of the standard type constructions except recursive types. \paragraph{1a) Rule for the \texttt{Unit} type} The \lstinline!Unit! type has only a single value \lstinline!()!, -an \textsf{``}empty tuple\textsf{''}. This value can be \emph{always} computed since +an \textsf{``}empty tuple\textsf{''}. This value can be \emph{always} computed as it does not need any previous data: \begin{lstlisting} def f[...]: ... = { @@ -271,13 +405,13 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru final case class N1() \end{lstlisting} defines a named unit type. We can compute a value of type \lstinline!N1! -without using any other given values: +without using any previously given values: \begin{lstlisting} val x: N1 = N1() \end{lstlisting} So, the proposition ${\cal CH}($\lstinline!N1!$)$ is always true. In the type notation, named unit types are also denoted by $\bbnum 1$, -just as the \lstinline!Unit! type itself. +same as the \lstinline!Unit! type itself. \paragraph{1b) Rule for the void type} @@ -289,7 +423,8 @@ \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 may use a constant value, e.g.: +is \emph{always true} because we may always create a constant value +of that type, e.g.: \begin{lstlisting} def f[...]: ... { ... @@ -307,14 +442,8 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru This is expressed by the logical formula ${\cal CH}($\lstinline!(A, B)!$)={\cal CH}(A)\wedge{\cal CH}(B)$. 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 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} -is written in the type notation as $\text{String}\times\text{String}\times\text{Int}$. -So, the rule for tuples is: +as $A\times B$, and tuples with more parts are written similarly. +So, we write the rule for tuples as: \[ {\cal CH}\left(A\times B\times...\times C\right)={\cal CH}(A)\wedge{\cal CH}(B)\wedge...\wedge{\cal CH}(C)\quad. \] @@ -328,21 +457,9 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru 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)$. -In the type notation, the Scala type \lstinline!Either[A, B]! is -written as $A+B$. As another example, the Scala definition: -\begin{lstlisting} -sealed trait RootsOfQ -final case class NoRoots() extends RootsOfQ -final case class OneRoot(x: Double) extends RootsOfQ -final case class TwoRoots(x: Double, y: Double) extends RootsOfQ -\end{lstlisting} -is translated to the type notation as: -\[ -\text{RootsOfQ}\triangleq\bbnum 1+\text{Double}+\text{Double}\times\text{Double}\quad. -\] -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: +In the type notation, disjunctive types with more than two parts are +written similarly as $A+B+...+C$. So, 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. \] @@ -374,7 +491,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \paragraph{5) Rule for parameterized types} -Here is an example of a function with type parameters: +Consider this function with type parameters: \begin{lstlisting} def f[A, B]: A => (A => B) => B = { x => g => g(x) } \end{lstlisting} @@ -390,66 +507,27 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \forall(A,B).\,{\cal CH}\left(A\rightarrow(A\rightarrow B)\rightarrow B\right)\quad. \] The symbol $\forall$ means \textsf{``}for all\textsf{''} and is called the \index{universal quantifier (forall)@universal quantifier ($\forall$)}\textbf{universal -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{''}. +quantifier} in logic. We read $\forall A.\,{\cal CH}(F^{A})$ as the +proposition \textsf{``}for all types \lstinline!A!, we can compute a value +of type \lstinline!F[A]!\textsf{''}. Here, \lstinline!F[A]! can be any type +expression that depends on \lstinline!A! (or even a type expression +that does not depend on \lstinline!A!). -So, the rule for parameterized types with the type notation $\forall A.\,F^{A}$ +So, the rule for parameterized types of the form $\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: -\[ -f^{A,B}:A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\quad\text{or equivalently}:\quad f:\forall(A,B).\,A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad. -\] -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 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 -like this: -\begin{lstlisting} -type F[A, B] = A => (A => B) => B -def f[A, B]: F[A, B] = { x => g => g(x) } -\end{lstlisting} -This is written in the type notation by placing all type parameters -into superscripts: -\begin{align*} -F^{A,B} & \triangleq A\rightarrow\left(A\rightarrow B\right)\rightarrow B\quad,\\ -f^{A,B}:F^{A,B} & \triangleq x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad, -\end{align*} -or equivalently (although somewhat less readably) as: -\[ -f:\big(\forall(A,B).\,F^{A,B}\big)\triangleq\forall(A,B).\,x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)\quad. -\] - -In Scala 3, the function \lstinline!f! can be written as a value -(\lstinline!val!) via this syntax: -\begin{lstlisting} -val f: [A, B] => A => (A => B) => B = { // Valid only in Scala 3. - [A, B] => (x: A) => (g: A => B) => g(x) -} -\end{lstlisting} -This syntax closely corresponds to the code notation $\forall(A,B).\,x^{:A}\rightarrow g^{:A\rightarrow B}\rightarrow g(x)$. - -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 -notation is designed to support nameless type expressions. - The rules just shown will allow us to express ${\cal CH}$-propositions for complicated types via ${\cal CH}$-propositions for type parameters. 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 a fully parametric type +In this way, we find 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. +\textbf{Curry-Howard correspondence}\index{Curry-Howard correspondence}. Table~\ref{tab:ch-correspondence-type-notation-CH-propositions} summarizes the type notation and shows how to translate it into logic @@ -458,28 +536,6 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru lists all type constructions that may be used in the code of a fully parametric function. -The precedence\index{type notation!operator precedence} of operators -in the type notation is chosen to have fewer parentheses in the type -expressions that are frequently used. The rules of precedence are: -\begin{itemize} -\item The type product operator ($\times$) groups stronger than the disjunctive -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 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$ -(representing \lstinline!((A, B)) => C!) can be written without any -parentheses. Type expressions such as $\left(A\rightarrow B\right)\times C$ -will require parentheses but are needed less often. -\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 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} \begin{tabular}{|c|c|c|} @@ -487,7 +543,12 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \textbf{\small{}Scala syntax} & \textbf{\small{}Type notation} & \textbf{\small{}${\cal CH}$-proposition}\tabularnewline \hline \hline -\lstinline![A]! & $A$ & ${\cal CH}(A)$\tabularnewline +\lstinline!Unit! & $\bbnum 1$ & ${\cal CH}(\bbnum 1)=True$\tabularnewline +\hline +\lstinline!Nothing! & $\bbnum 0$ & ${\cal CH}(\bbnum 0)=False$\tabularnewline +\hline +{\small{}}\lstinline!Int!{\small{}, }\lstinline!String!{\small{}, +...} & {\small{}$\text{Int}$, $\text{String}$, ...} & ${\cal CH}(\text{Int})=True$\tabularnewline \hline \lstinline!(A, B)! & $A\times B$ & ${\cal CH}(A)$ $\wedge$ ${\cal CH}(B)$\tabularnewline \hline @@ -495,12 +556,7 @@ \subsection{Type notation and ${\cal CH}$-propositions for standard type constru \hline \lstinline!A => B! & $A\rightarrow B$ & ${\cal CH}(A)$ $\Rightarrow$ ${\cal CH}(B)$\tabularnewline \hline -\lstinline!Unit! & $\bbnum 1$ & ${\cal CH}(\bbnum 1)=True$\tabularnewline -\hline -{\small{}}\lstinline!Int!{\small{}, }\lstinline!String!{\small{}, -...} & {\small{}$\text{Int}$, $\text{String}$, ...} & ${\cal CH}(\text{Int})=True$\tabularnewline -\hline -\lstinline!Nothing! & $\bbnum 0$ & ${\cal CH}(\bbnum 0)=False$\tabularnewline +\lstinline!A!{\small{} (type parameter)} & $A$ & ${\cal CH}(A)$\tabularnewline \hline \lstinline!def f[A]: F[A]! & $f^{A}:F^{A}$ & $\forall A.\,{\cal CH}(F^{A})$\tabularnewline \hline @@ -517,13 +573,13 @@ \subsection{Examples: Type notation\index{examples (with code)}} From now on, we will prefer to write types in the type notation rather than in the Scala syntax. The type notation allows us to write nameless type expressions and makes the structure of complicated types clearer -than in the Scala syntax. Names of types and parts of types are, of -course, helpful for reminding programmers of the meaning of data in -a program. However, writing names for every part of every type does -not help reasoning about the properties of types. Once the programmer -has finished deriving the necessary types and verifying their properties, -the type notation can be straightforwardly translated into Scala code. -Let us get some experience doing that. +than in the Scala syntax. Names are, of course, helpful for reminding +programmers of the meaning of data represented by case classes and +disjunctive types. However, writing names for every part of every +type does not help in reasoning about the properties of types. Once +the programmer has finished deriving the necessary types and verifying +their properties, the type notation can be straightforwardly translated +into Scala code. Let us get some experience doing that. \subsubsection{Example \label{subsec:Example-ch-dupl-function}\ref{subsec:Example-ch-dupl-function}} @@ -581,8 +637,8 @@ \subsubsection{Example \label{subsec:Example-ch-dupl-function}\ref{subsec:Exampl It is intuitively clear that the proposition ${\cal CH}(\Delta)$ is true: it just says that if ${\cal CH}(A)$ is true then ${\cal CH}(A)$ and ${\cal CH}(A)$ is true. The point of writing ${\cal CH}(\Delta)$ -in a mathematical notation is to prepare for proving this proposition -rigorously rather than based on intuition. +in a mathematical notation is to prepare for proving that proposition +rigorously. \subsubsection{Example \label{subsec:Example-ch-notation-function-1}\ref{subsec:Example-ch-notation-function-1}} @@ -697,8 +753,9 @@ \subsubsection{Example \label{subsec:Example-ch-notation-function-4}\ref{subsec: 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$ -rather than $\text{id}\triangleq\forall A.\,x^{:A}\rightarrow x$. +than under type quantifiers. For example, we will prefer to write +the type signature of an identity function as $\text{id}^{A}:A\rightarrow A$ +rather than as $\text{id}:\forall A.\,A\rightarrow A$. \subsection{Exercises: Type notation\index{exercises}} @@ -723,30 +780,44 @@ \subsubsection{Exercise \label{subsec:Exercise-type-notation-3}\ref{subsec:Exerc \subsubsection{Exercise \label{subsec:Exercise-type-notation-4}\ref{subsec:Exercise-type-notation-4}} -Write a Scala type signature for the fully parametric function: +Write a Scala type signature for this fully parametric function: \[ -\text{flatMap}^{A,B}:\bbnum 1+A\rightarrow\left(A\rightarrow\bbnum 1+B\right)\rightarrow\bbnum 1+B +f^{A,B,C}:\bbnum 1+A+B+C\rightarrow\left(A\rightarrow\bbnum 1+B\right)\rightarrow\bbnum 1+B+C\quad. \] -and implement this function, preserving information as much as possible. - -\section{The logic of ${\cal CH}$-propositions} +Implement this function, preserving information as much as possible. -\subsection{Motivation and first examples\label{subsec:ch-Motivation-and-first-examples}} +\section{The logic of ${\cal CH}$-propositions\label{sec:The-logic-of-ch-propositions}} So far, we were able to convert statements such as \textsf{``}\emph{a fully parametric function can compute values of type} $A$\textsf{''} into logical propositions that we called ${\cal CH}$-propositions. The next step -is to determine the proof rules suitable for reasoning about ${\cal CH}$-propositions. +is to determine the proof rules suitable for rigorous reasoning about +${\cal CH}$-propositions. Those rules will be rules of a formal logic. + +This section is an extended voyage into certain aspects of formal +logic that are needed for obtaining proofs of ${\cal CH}$-propositions +and deriving program code from those proofs. While that theory (known +as the \index{Curry-Howard correspondence}Curry-Howard correspondence) +is important as a technique of reasoning about types in functional +programs, the material of Section~\ref{sec:The-logic-of-ch-propositions} +is used only for the discussions in Section~\ref{sec:Discussion-curry-howard}. +An exception is Section~\ref{subsec:Short-notation-for-eight-code-constructions} +that introduces the short notation for fully parametric code. That +notation will be further developed and used throughout the book. Other +than that, the rest of the book does not depend on the Curry-Howard +correspondence. + +\subsection{Motivation and first examples\label{subsec:ch-Motivation-and-first-examples}} Formal logic uses axioms and derivation rules for proving that certain formulas are true or false. We will use Greek letters ($\alpha$, -$\beta$, etc.) to denote propositions in logic. +$\beta$, etc.) to denote propositions. We will often need logical formulas that talk about properties of \emph{arbitrary} propositions. This is denoted by the \textbf{universal quantifier}\index{universal quantifier (forall)@universal quantifier ($\forall$)} symbol ($\forall$), which means \textsf{``}for all\textsf{''}. The universal quantifier -will be usually located in front of the formula, for example: +will be usually located in front of the formula, e.g.: \[ \forall(\alpha,\beta).\,\left(\alpha\Rightarrow\beta\right)\Rightarrow\alpha\Rightarrow\alpha\quad. \] @@ -754,7 +825,7 @@ \subsection{Motivation and first examples\label{subsec:ch-Motivation-and-first-e $\alpha\Rightarrow\beta$ means that \emph{if} $\alpha$ is proved true \emph{then} $\beta$ will be proved true. -Formulas whose propositions are universally quantified correspond +Formulas whose propositions are all universally quantified correspond to type signatures that are made entirely from type parameters. For instance, the formula shown above corresponds to the following type signature: @@ -765,8 +836,9 @@ \subsection{Motivation and first examples\label{subsec:ch-Motivation-and-first-e fact that the function \lstinline!f! works with any choice of types \lstinline!A! and \lstinline!B!. -A simple example of a true logical formula is \textsf{``}any proposition $\alpha$ -follows from itself\textsf{''}: +A simple example of a true logical formula is \textsf{``}if $\alpha$ is true +then $\alpha$ is true\textsf{''} (any proposition $\alpha$ follows from +itself): \begin{equation} \forall\alpha.\,\alpha\Rightarrow\alpha\quad.\label{eq:ch-type-sig-1a} \end{equation} @@ -814,40 +886,39 @@ \subsection{Motivation and first examples\label{subsec:ch-Motivation-and-first-e an introduction for programmers\textsf{''}. An early draft version of that book is available at \texttt{\href{https://homepages.phonecoop.coop/randj/richard/books/ProofandDisproof.pdf}{https://homepages.phonecoop.coop/randj/richard/books/ProofandDisproof.pdf}}} -\subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rules-of-proof}} +\subsection{Short notation for fully parametric code\label{subsec:Short-notation-for-eight-code-constructions}} To derive the suitable logical axioms and proof rules systematically, -let us examine what could make a sequent with ${\cal CH}$-propositions +we need to examine what could make a sequent with ${\cal CH}$-propositions true. A sequent ${\cal CH}(A)\vdash{\cal CH}(X)$ is true when a value of type $X$ can be computed by fully parametric code that may only use a given value of type $A$. To describe all possible ways of computing a value of type $X$, we need to enumerate all possible ways of \emph{writing -code} for a fully parametric function body. The requirement of full -parametricity means that we are not allowed to use any specific types -such as \lstinline!Int! or \lstinline!String!, any concrete values -such as \lstinline!123! or \lstinline!"hello"!, or any library functions -that work with specific (non-parametric) types. We are only allowed -to work with values of unknown types described by the given type parameters. -However, we are permitted to use fully parametric types such as \lstinline!Either[A, B]! +code} in a fully parametric function. The requirement of full parametricity +means that we are not allowed to use any specific types such as \lstinline!Int! +or \lstinline!String!, any concrete values such as \lstinline!123! +or \lstinline!"hello"!, or any library functions that work with specific +(non-parametric) types. We are only allowed to work with values of +unknown types described by the given type parameters. However, we +are permitted to use fully parametric types such as \lstinline!Either[A, B]! or \lstinline!Option[A]!. In fact, we can enumerate all the allowed constructions that may be -used by fully parametric code implementing a ${\cal CH}$-proposition. -There are \emph{eight} code constructions\index{eight code constructions}\index{fully parametric!code constructions} -as illustrated by this code: -\begin{lstlisting} +used by fully parametric code. There are \emph{eight} code constructions\index{eight code constructions}\index{fully parametric!code constructions} +as illustrated here: +\begin{lstlisting}[mathescape=true] def f[A, B, ...](a: A, b: B): X = { // Any given type signature. val x1: Unit = () // 1) Use a value of type Unit. - val x2: A = a // 2) Use a given argument value. - val x3 = { x: A => b } // 3) Create a function. + val x2: A = a // 2) Use a given argument. + val x3 = { (x: A) => b } // 3) Create a function. val x4: D = x3(x2) // 4) Use a function. val x5: (A, B) = (a, b) // 5) Create a tuple. val x6: B = x5._2 // 6) Use a tuple. val x7: Either[A, B] = Right(x6) // 7) Create values of a disjunctive type. val x8 = x7 match { ... } // 8) Use values of a disjunctive type. -} // 9) Call f() itself recursively. Not included here because recursion is not supported by CH-propositions. +} // 9) Call f itself recursively. Not included here because recursion is not supported by $\color{dkgreen}\cal{CH}$-propositions. \end{lstlisting} The proposition ${\cal CH}(X)$ is true if we can create a sequence of computed values such as \lstinline!x1!, \lstinline!x2!, ..., @@ -862,9 +933,162 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul code\textsf{''}\index{fully parametric!code|textit} and allows us to \emph{prove} ${\cal CH}$-propositions. -Reasoning about proof rules is easier with a compact notation. To -obtain that notation, we first need to translate the eight code constructs -into the notation of sequents. A proof of a sequent, e.g., $\mathcal{CH}(A)\vdash\mathcal{CH}(X)$, +The ninth code construction (the recursive call) is also a valid construction +in fully parametric code. We will be using that construction in later +chapters of this book. However, that construction is not supported +by propositional logic, so we cannot map recursive code to a proof +rule for ${\cal CH}$-propositions. + +When writing code and reasoning symbolically about code, the syntax +of Scala is too verbose. We have started introducing a shorter code +notation in Chapter~\ref{chap:Higher-order-functions}, and we will +develop it in more detail in this chapter. This code notation will +be used systematically in later chapters of this book. + +In the code notation, we denote values of the \lstinline!Unit! type +by the symbol $1$. There will be no confusion with the integer value +$1$ because the latter is rarely used in symbolic reasoning. + +We denote functions by expressions of the form $x^{:A}\rightarrow f(x)$. +We will use two equivalent notations for applying a function to an +argument: $f(x)$ and $x\triangleright f$ (the \index{pipe notation}\textbf{pipe +notation}). + +Tuples are denoted using the product symbol ($\times$). For example, +a pair \lstinline!(a, b)! is written in the code notation as $a\times b$. +A tuple \lstinline!(a, b, c)! is written as $a\times b\times c$, +etc. + +In this book, all type parameters are capitalized and all values are +written in lowercase. This makes it clear that, say, $A\rightarrow A$ +and $A\times B$ are \emph{type} expressions while $x\rightarrow x$ +and $a\times b$ are values. + +Functions that pattern-match on a tuple are denoted by $a\times b\rightarrow...$ +(that is, the argument is written in a tuple form). For example, the +function denoted in Scala by \lstinline!_._1! is written as $a\times b\rightarrow a$. + +Disjunctive types are treated specially in the code notation. As a +motivating example, consider the standard type \lstinline!Either[A, B]!. +In the type notation, it is written as $A+B$. Values of that type +can be of the form \lstinline!Left(x)! or \lstinline!Right(y)!. +Those values are written as $x+\bbnum 0$ and $\bbnum 0+y$ in the +code notation. + +To motivate this unconventional notation, consider the type inferred +by Scala for a value \lstinline!Left(123)!: +\begin{lstlisting} +scala> Left(123) +res0: Left[Int, Nothing] = Left(123) +\end{lstlisting} +The inferred type is \lstinline!Left[Int, Nothing]!, which is written +as $\text{Int}+\bbnum 0$ in the type notation. As the void type ($\bbnum 0$) +has no values, it makes sense that any value of type $\text{Int}+\bbnum 0$ +\emph{must} be of the form \lstinline!Left(x)! with an integer \lstinline!x!. +More generally, a value of type $A+\bbnum 0$ is always of the form +\lstinline!Left(x)! with some \lstinline!x: A!, and a value of type +$\bbnum 0+B$ must be of the form \lstinline!Right(y)! with some +\lstinline!y: B!. So, the code notation writes $x^{:A}+\bbnum 0$ +for values of type $A+\bbnum 0$ and $\bbnum 0+y^{:B}$ for values +of type $\bbnum 0+B$. + +The type notation $A+\bbnum 0$ and $\bbnum 0+B$ for the \lstinline!Left! +and the \lstinline!Right! parts of the disjunctive type \lstinline!Either[A, B]! +agrees with the behavior of the Scala compiler, which will infer the +types \lstinline!Either[A, Nothing]! and \lstinline!Either[Nothing, B]! +for the corresponding code: +\begin{lstlisting} +def toLeft[A, B]: A => Either[A, B] = x => Left(x) +def toRight[A, B]: B => Either[A, B] = y => Right(y) + +scala> toLeft(123) +res0: Either[Int, Nothing] = Left(123) + +scala> toRight("abc") +res1: Either[Nothing, String] = Right("abc") +\end{lstlisting} +We can write the functions \lstinline!toLeft! and \lstinline!toRight! +in the code notation as: +\[ +\text{toLeft}^{A,B}\triangleq x^{:A}\rightarrow x+\bbnum 0^{:B}\quad,\quad\quad\text{toRight}^{A,B}\triangleq y^{:B}\rightarrow\bbnum 0^{:A}+y\quad. +\] +The code notation shows values of disjunctive types without using +Scala class names such as \lstinline!Either!, \lstinline!Right!, +and \lstinline!Left!. This shortens the writing and speeds up reasoning +about code. + +In the notation $\bbnum 0^{:A}+y$, we use the symbol $\bbnum 0$ +rather than an ordinary zero ($0$), to avoid suggesting that $0$ +is a value of type $\bbnum 0$. The void type $\bbnum 0$ has \emph{no} +values, unlike the \lstinline!Unit! type, $\bbnum 1$, which has +a value denoted by $1$ in the code notation. + +Type annotations such as $\bbnum 0^{:A}$ are helpful to remind ourselves +about the type parameter $A$ used, e.g., by the disjunctive value +$\bbnum 0^{:A}+y^{:B}$ in the body of \lstinline!toRight[A, B]!. +Without that type annotation, $\bbnum 0+y^{:B}$ needs to be interpreted +as a value of type \lstinline!Either[A, B]!, where the type parameter +$A$ must be determined by matching with the types of other expressions. +When it is clear what types are being used, we may omit type annotations +and write simply $\bbnum 0+y$ instead of $\bbnum 0^{:A}+y^{:B}$. + +The type notation for pattern matching is also unconventional because +it uses \textsf{``}function matrices\textsf{''} (matrices whose elements are functions). +To motivate that, we view a \lstinline!match!/\lstinline!case! expression +as a set of functions that map parts of a disjunctive type into parts +of another disjunctive type. Consider this example code: +\begin{lstlisting}[numbers=left] +def f: Either[Int, String] => Either[String, Int] = { + case Left(x) => Right(10 * x) + case Right(y) => Left("a" + y + "b") +} +\end{lstlisting} +If we ignore the type names (\lstinline!Left! and \lstinline!Right!), +we will see that line~2 is similar to the function \lstinline!x => 10 * x! +of type \lstinline!Int => Int!, while line~3 is similar to the function +\lstinline!y => "a" + y + "b"! of type \lstinline!String => String!. +These functions become matrix elements in the \textsf{``}function matrix\textsf{''} +for \lstinline!f!: +\[ +f^{:\text{Int}+\text{String}\rightarrow\text{String}+\text{Int}}\triangleq\,\begin{array}{|c||cc|} + & \text{String} & \text{Int}\\ +\hline \text{Int} & \bbnum 0 & x\rightarrow10*x\\ +\text{String} & y\rightarrow\text{"a"}+y+\text{"b"} & \bbnum 0 +\end{array}\quad. +\] +The rows of the matrix correspond to the \lstinline!case! rows in +the Scala code. There is one row for each part of the disjunctive +type of the input argument. The columns of the matrix correspond to +the parts of the disjunctive type of the output.\index{pattern matching!in matrix notation} +The matrix element in the first row and second column is the function +$x\rightarrow10*x$ that corresponds to line~2 in the Scala code. +The result type for that case is \lstinline!Right[Nothing, Int]!, +which is written as $\bbnum 0+\text{Int}$ in the type notation. The +function $x\rightarrow10*x$ is written in the second column to indicate +that the result type is $\bbnum 0+\text{Int}$. The matrix element +in the first row and the first column is written as $\bbnum 0$ because +no value of the type \lstinline!Left! is returned in that case. + +The matrix element in the second row and first column is the function +$y\rightarrow\text{"a"}+y+\text{"b"}$ that corresponds to line~3 +in the Scala code. The result type for that case is $\text{String}+\bbnum 0$. +The other matrix element in the second row is written as $\bbnum 0$, +according to the return type $\text{String}+\bbnum 0$. + +In this way, we translate all lines of the \lstinline!match!/\lstinline!case! +expression into a code matrix. In each row of the matrix, there can +be only one element that is not $\bbnum 0$. + +It turns out that the matrix notation is well adapted to computing\emph{ +forward compositions} of functions that operate on disjunctive types. +We will see many examples of such computations later in this book. +In this chapter, we will use code matrices in Example~\ref{subsec:ch-Example-A+B}, +Example~\ref{subsec:ch-Example-type-identity-5}, and some others. + +\subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rules-of-proof}} + +Reasoning about proof rules begins by translating the eight standard +code constructs into sequents. A proof of a sequent, e.g., $\mathcal{CH}(A)\vdash\mathcal{CH}(X)$, will consist of applying some of those proof rules. We will then combine the code constructs corresponding to each rule and obtain some code that computes a value of type $X$ using an argument of type $A$. @@ -876,8 +1100,8 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul a proof of the proposition ${\cal CH}(X)$. 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. +programs and proofs of sequents. This is the second part of the \textbf{Curry-Howard +correspondence}\index{Curry-Howard correspondence}. In the following text, we will need to write ${\cal CH}$-propositions such as Eq.~(\ref{eq:ch-CH-proposition-def}) as sequents such as @@ -893,7 +1117,7 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul With these notations, we list the rules for proving ${\cal CH}$-propositions and the corresponding code: -\paragraph{1) Use the \texttt{Unit} value} +\paragraph{1) The \texttt{Unit} value} At any place in the code, we may write the expression \lstinline!()! of type \lstinline!Unit!. This expression corresponds to a proof @@ -928,17 +1152,31 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul So, the corresponding proposition, $\alpha\triangleq{\cal CH}(A)$, belongs to the set of premises of the sequent we are trying to prove. To indicate this, we write the set of premises as \textsf{``}$\Gamma,\alpha$\textsf{''}. -The code construct \lstinline!x: A! computes a value of type $A$, -i.e., shows that $\alpha$ is true with premises $\Gamma,\alpha$. -This is expressed by the sequent $\Gamma,\alpha\vdash\alpha$. The -proof code for this sequent is an expression that just returns the -given value (which we denoted by $x^{:A}$): +The code construct \lstinline!x! computes a value of type $A$, i.e., +shows that \textsf{``}$\alpha$ is true with premises $\Gamma,\alpha$\textsf{''}. +That proposition is the meaning of the sequent $\Gamma,\alpha\vdash\alpha$. +The proof code for that sequent is an expression that just returns +the value $x$: \[ \text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }x^{:A}}=x\quad. \] -This sequent is an axiom since its proof requires no previous sequents; -a value of type $A$ is already given in the premises. We denote this -axiom by: +Here, the subscript \textsf{``}given $x^{:A}$\textsf{''} indicates that the value +$x^{:A}$ must come from the premises. In this case, the set of premises +is $\Gamma,\alpha$ and so the proposition $\alpha$ must have been +already proved. The proof of $\alpha$ will give a value $x^{:A}$. + +Actually, the premises for the sequent $\Gamma,\alpha\vdash\alpha$ +may give us not only a value $x^{:A}$ but also some other values +of other types. We may collectively denote those values by $p^{:\Gamma}$. +But the proof of the sequent $\Gamma,\alpha\vdash\alpha$ does not +need to use $p$. To show that explicitly, we may write: +\[ +\text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }p^{:\Gamma},\,x^{:A}}=x\quad. +\] + +The sequent $\Gamma,\alpha\vdash\alpha$ is an axiom since its proof +requires no previous sequents; a value of type $A$ is already given +in the premises. We denote this axiom by: \[ \frac{~}{\Gamma,\alpha\vdash\alpha}\quad(\text{use value})\quad\quad. \] @@ -947,17 +1185,18 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul \paragraph{3) Create a function} At any place in the code, we may compute a nameless function of type, -say, $A\rightarrow B$, by writing \lstinline!(x:A) => expr! as long -as a value \lstinline!expr! of type $B$ can be computed in the inner -scope of the function. The code for \lstinline!expr! is also required -to be fully parametric; it may use \lstinline!x! and/or other values -visible in that scope. So, we now need to answer the question of whether -a fully parametric function can compute a value of type $B$, given -an argument of type $A$ as well as all other arguments previously -given to the parent function. This question is answered by a sequent -whose premises contain one more proposition, ${\cal CH}(A)$, in addition -to all previously available premises. Translating this into the language -of ${\cal CH}$-propositions, we find that we will prove the sequent: +say, $A\rightarrow B$, by writing \lstinline!(x: A) => expr! as +long as a value \lstinline!expr! of type $B$ can be computed in +the inner scope of the function. The code for \lstinline!expr! is +also required to be fully parametric; it may use \lstinline!x! and/or +other values visible in that scope. So, we now need to answer the +question of whether a fully parametric function can compute a value +of type $B$, given an argument of type $A$ as well as all other +arguments previously given to the parent function. This question is +answered by a sequent whose premises contain one more proposition, +${\cal CH}(A)$, in addition to all previously available premises. +Translating this into the language of ${\cal CH}$-propositions, we +find that we will prove the sequent: \[ \Gamma\vdash{\cal CH}(A\rightarrow B)\quad=\quad\Gamma\vdash{\cal CH}(A)\Rightarrow{\cal CH}(B)\quad=\quad\Gamma\vdash\alpha\Rightarrow\beta \] @@ -992,12 +1231,9 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul rule \textsf{``}$\text{create function}$\textsf{''}. That rule\textsf{'}s proof transformer is: \[ -\text{Proof}\,\big(\Gamma\vdash\alpha\Rightarrow\beta\big)=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,\alpha\vdash\beta\big)_{\text{given }x^{:A}}\quad. +\text{Proof}\,\big(\Gamma\vdash\alpha\Rightarrow\beta\big)_{\text{given }p^{:\Gamma}}=x^{:A}\rightarrow\text{Proof}\,\big(\Gamma,\alpha\vdash\beta\big)_{\text{given }p^{:\Gamma},\,x^{:A}}\quad. \] -Here, the subscript \textsf{``}given $x^{:A}$\textsf{''} indicates that the value -$x^{:A}$ must come from the premises. (In this case, the set of premises -is $\Gamma,\alpha$ and so the proposition $\alpha$ must have been -already proved. The proof of $\alpha$ will give a value $x^{:A}$.) + \paragraph{4) Use a function} @@ -1010,12 +1246,13 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\alpha\Rightarrow\beta}{\Gamma\vdash\beta}\quad(\text{use function})\quad\quad. \] The code corresponding to this proof rule takes previously computed -values \lstinline!x:A! and \lstinline!f:A => B!, and writes the +values \lstinline!x: A! and \lstinline!f: A => B!, and writes the expression \lstinline!f(x)!. This can be written as a function application: \[ \text{Proof}\,(\Gamma\vdash\beta)=\text{Proof}\left(\Gamma\vdash\alpha\Rightarrow\beta\right)(\text{Proof}\,(\Gamma\vdash\alpha))\quad. \] - +Here we omitted the subscripts \textsf{``}$\text{given }p^{:\Gamma}$\textsf{''} for +brevity, since all sequents have the same premises $\Gamma$. \paragraph{5) Create a tuple} @@ -1025,8 +1262,8 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul \[ \frac{\Gamma\vdash\alpha\quad\quad\Gamma\vdash\beta}{\Gamma\vdash\alpha\wedge\beta}\quad(\text{create tuple})\quad\quad. \] -Writing $a\times b$ to mean the pair \lstinline!(a, b)!, we can -write the corresponding code expression as: +In the code notation, $a\times b$ means the pair \lstinline!(a, b)!, +so we can write the code as: \[ \text{Proof}\left(\Gamma\vdash\alpha\wedge\beta\right)=\text{Proof}\left(\Gamma\vdash\alpha\right)\times\text{Proof}\left(\Gamma\vdash\beta\right)\quad. \] @@ -1034,17 +1271,17 @@ \subsection{The rules of proof for ${\cal CH}$-propositions\label{subsec:The-rul This rule describes creating a tuple of $2$ values. A larger tuple, such as \lstinline!(w, x, y, z)!, can be expressed via nested pairs, e.g., as \lstinline!(w, (x, (y, z)))!. So, it suffices to have a -derivation rule for creating pairs. That rule allows us to express -the rules for creating all larger tuples, and so we do not need to -define separate rules for, say, $\Gamma\vdash\alpha\wedge\beta\wedge\gamma$. +derivation rule for creating pairs. That rule allows us to derive +the rules for creating all larger tuples, without having to define +separate rules for, say, $\Gamma\vdash\alpha\wedge\beta\wedge\gamma$. \paragraph{6) Use a tuple} -If we already have a value \lstinline!t:(A,B)! of a tuple type $A\times B$, -we can extract one of the parts of the tuple and obtain a value of -type \lstinline!A! or a value of type \lstinline!B!. The code is -\lstinline!t._1! and \lstinline!t._2! respectively, and the corresponding -sequent proof rules are: +If we already have a value \lstinline!t: (A, B)! of a tuple type +$A\times B$, we can extract one of the parts of the tuple and obtain +a value of type \lstinline!A! or a value of type \lstinline!B!. +The code is \lstinline!t._1! and \lstinline!t._2! respectively, +and the corresponding 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. \] @@ -1247,12 +1484,14 @@ \subsubsection{Example \label{subsec:Example-derive-code-1}\ref{subsec:Example-d \end{figure} Now we need to extract code from the proof. We begin with the leaves -of the tree and trace back the proof towards the top. The axiom \textsf{``}use -value\textsf{''} has the proof code $x$, where $x$ is given in the premises: +of the tree and go back towards the top of the proof. + +The axiom \textsf{``}use value\textsf{''} has the proof code $x$, where $x$ is given +in the premises: \[ \text{Proof}\,\big(\Gamma,\alpha\vdash\alpha\big)_{\text{given }x^{:A}}=x\quad. \] -The proof used this axiom twice with $\alpha=\chi$. Recall that $\chi$ +The proof uses this axiom twice with $\alpha=\chi$. Recall that $\chi$ denotes ${\cal CH}(X)$, and so the value $x$ must have type $X$. So, we write: \[ @@ -1285,7 +1524,7 @@ \subsubsection{Example \label{subsec:Example-derive-code-1}\ref{subsec:Example-d \begin{lstlisting} def d[X]: X => (X, X) = (x: X) => (x, x) \end{lstlisting} -$\square$ + \subsubsection{Example \label{subsec:Example-derive-code-2}\ref{subsec:Example-derive-code-2}} @@ -1317,8 +1556,8 @@ \subsubsection{Example \label{subsec:Example-derive-code-2}\ref{subsec:Example-d Begin by looking for a proof rule whose \textsf{``}denominator\textsf{''} has a sequent similar to Eq.~(\ref{eq:ch-example-sequent-2}), i.e., has an implication ($p\Rightarrow q$) in the goal. We have only one rule with the \textsf{``}denominator\textsf{''} -of the form $\Gamma\vdash(p\Rightarrow q$); this is the rule \textsf{``}$\text{create function}$\textsf{''}, -which we will rewrite as: +of the form $\Gamma\vdash p\Rightarrow q$. That rule is \textsf{``}$\text{create function}$\textsf{''}, +which we will rewrite for clarity as: \[ \frac{\Gamma,p\vdash q}{\Gamma\vdash p\Rightarrow q}\quad(\text{create function}) \] @@ -1372,7 +1611,7 @@ \subsubsection{Example \label{subsec:Example-derive-code-2}\ref{subsec:Example-d {\footnotesize{}}% \fbox{\begin{minipage}[t]{0.7\columnwidth}% \begin{center} -{\footnotesize{}}{\footnotesize{}\Tree[ .$\emptyset\vdash((\alpha\Rightarrow\alpha)\Rightarrow\beta)\Rightarrow\beta $ [ .{rule \textsf{``}$\text{create function}$\textsf{''}} [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\beta$ [ .{rule \textsf{``}$\text{use function}$\textsf{''}} [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\alpha\Rightarrow\alpha$ [ .{rule \textsf{``}$\text{create function}$\textsf{''}} [ .$\gamma,\alpha\vdash\alpha$ {axiom \textsf{``}$\text{use value}$\textsf{''}} ] ] ] [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash(\alpha\Rightarrow\alpha)\Rightarrow\beta$ {axiom \textsf{``}$\text{use value}$\textsf{''}} ] ] ] ] ]} +{\footnotesize{}}{\footnotesize{}\Tree[ .$\emptyset\vdash((\alpha\Rightarrow\alpha)\Rightarrow\beta)\Rightarrow\beta $ [ .{rule \textsf{``}$\text{create function}$\textsf{''}} [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\beta$ [ .{rule \textsf{``}$\text{use function}$\textsf{''}} [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash\alpha\Rightarrow\alpha$ [ .{rule \textsf{``}$\text{create function}$\textsf{''}} [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta,\alpha\vdash\alpha$ {axiom \textsf{``}$\text{use value}$\textsf{''}} ] ] ] [ .$(\alpha\Rightarrow\alpha)\Rightarrow\beta\vdash(\alpha\Rightarrow\alpha)\Rightarrow\beta$ {axiom \textsf{``}$\text{use value}$\textsf{''}} ] ] ] ] ]} \par\end{center}% \end{minipage}}{\footnotesize\par} \par\end{centering} @@ -1396,11 +1635,11 @@ \subsubsection{Example \label{subsec:Example-derive-code-2}\ref{subsec:Example-d Note that in this code we are able to use a value $x$ of type $A$ even though no such value is given as an argument of our function \lstinline!s[A, B]!. The reason is that the sequent $\gamma,\alpha\vdash\alpha$ -has an extra premise $\alpha$ added to the set of premises only for -this step of the proof. Once we are finished with this step, we again -will not have any values of type $A$ available. In the code, this -corresponds to the local scoping of the bound value $x^{:A}$ in the -function $x^{:A}\rightarrow x$. +has an extra premise $\alpha$ added to the set of premises at this +step of the proof. Once we are finished with this step, we again will +not have any values of type $A$ available. In the code, this corresponds +to the local scoping of the bound value $x^{:A}$ in the function +$x^{:A}\rightarrow x$. We continue tracing the proof tree bottom-up. The right-most leaf \textsf{``}$\text{use value}$\textsf{''} corresponds to the code $f^{:(A\rightarrow A)\rightarrow B}$, @@ -1511,9 +1750,9 @@ \subsubsection{Example \label{subsec:Example-derive-code-2}\ref{subsec:Example-d The LJT algorithm will sometimes find several inequivalent proofs of the same logic formula. In that case, each of the different proofs will be automatically translated into code. The \lstinline!curryhoward! -library tries to select the code that has the least information loss, -according to several heuristics. In many cases, the heuristics select -the implementation that is most useful to the programmer. +library uses heuristics to try finding the code that has the least +information loss. In many cases, the heuristics will select the implementation +that is most useful to the programmer. The rules of constructive logic and the LJT algorithm define rigorously what it means to write code \textsf{``}guided by the types\textsf{''}. However, in @@ -1568,9 +1807,11 @@ \subsection{The LJT algorithm\label{app:The-LJT-algorithm}} 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 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$. +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$. The rule does not tell us how to choose the proposition $\alpha$ correctly. We need to guess the correct $\alpha$ by trial and error. Even after choosing $\alpha$ in some way, we will have to prove a @@ -1592,7 +1833,7 @@ \subsection{The LJT algorithm\label{app:The-LJT-algorithm}} \index{LJT algorithm}LJT, first formulated in 1992.\footnote{An often cited paper by R.~Dyckhoff\index{Roy Dyckhoff} is \texttt{\href{https://philpapers.org/rec/DYCCSC}{https://philpapers.org/rec/DYCCSC}}. For the history of that research, see \texttt{\href{https://research-repository.st-andrews.ac.uk/handle/10023/8824}{https://research-repository.st-andrews.ac.uk/handle/10023/8824}}} -We will first present the LJ algorithm. Although that algorithm does +We will begin with the LJ algorithm. Although that algorithm does not guarantee termination, it is simpler to understand and to apply by hand. Then we will show how to modify the LJ algorithm in order to obtain the always-terminating LJT algorithm. @@ -1606,18 +1847,18 @@ \subsubsection*{The LJ algorithm} $X\vee Y$, and implication $X\Rightarrow Y$) there is one rule where that sub-expression is a premise (at \textsf{``}left\textsf{''}) and one rule where that sub-expression is the goal (at \textsf{``}right\textsf{''}). Those sub-expressions -are shown in blue in Figure~\ref{fig:Rules-of-the-LJ-algorithm} -to help us look for a proof. To find out which rules apply, we match -some part of the sequent with a blue sub-expression. +are shown in red in Figure~\ref{fig:Rules-of-the-LJ-algorithm} to +help us look for a proof. To find out which rules apply, we match +some part of the sequent with a red sub-expression. \begin{figure} \begin{centering} \fbox{\begin{minipage}[t]{0.7\linewidth}% \begin{align*} -\frac{}{\Gamma,X\vdash{\color{blue}X}}~(\text{Id})\qquad & \qquad\frac{}{\Gamma\vdash{\color{blue}\top}}~(\text{True})\\ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\qquad & \qquad\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{blue}A\Rightarrow B}}~(\text{Right}\Rightarrow)\\ -\frac{\Gamma,A_{i}\vdash C}{\Gamma,{\color{blue}A_{1}\wedge A_{2}}\vdash C}~(\text{Left}\wedge_{i})\qquad & \qquad\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{blue}A\wedge B}}~(\text{Right}\wedge)\\ -\frac{\Gamma,A\vdash C\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\vee B}\vdash C}~(\text{Left}\vee)\qquad & \qquad\frac{\Gamma\vdash A_{i}}{\Gamma\vdash{\color{blue}A_{1}\vee A_{2}}}~(\text{Right}\vee_{i}) +\frac{}{\Gamma,X\vdash{\color{red}X}}~(\text{Id})\qquad & \qquad\frac{}{\Gamma\vdash{\color{red}\top}}~(\text{True})\\ +\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\qquad & \qquad\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{red}A\Rightarrow B}}~(\text{Right}\Rightarrow)\\ +\frac{\Gamma,A_{i}\vdash C}{\Gamma,{\color{red}A_{1}\wedge A_{2}}\vdash C}~(\text{Left}\wedge_{i})\qquad & \qquad\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{red}A\wedge B}}~(\text{Right}\wedge)\\ +\frac{\Gamma,A\vdash C\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\vee B}\vdash C}~(\text{Left}\vee)\qquad & \qquad\frac{\Gamma\vdash A_{i}}{\Gamma\vdash{\color{red}A_{1}\vee A_{2}}}~(\text{Right}\vee_{i}) \end{align*} % \end{minipage}} @@ -1685,12 +1926,12 @@ \subsubsection*{The LJ algorithm} \subsubsection*{Extracting code from proofs} -According to the Curry-Howard correspondence, a sequent (such as $A,B,...,C\vdash X$) -represents the task of writing a fully parametric code expression -of type $X$ that uses some given values of types $A$, $B$, ..., -$C$. The sequent is true (i.e., can be proved) if that code expression -can be found. So, the code serves as an \textsf{``}evidence of proof\textsf{''} for -the sequent. +According to the Curry-Howard correspondence, a sequent of the form + ${\cal CH}(A),{\cal CH}(B),...,{\cal CH}(C)\vdash{\cal CH}(X)$ represents +the task of writing a fully parametric code expression of type $X$ +that uses some given values of types $A$, $B$, ..., $C$. The sequent +is true (i.e., can be proved) if that code expression can be found. +So, the code serves as an \textsf{``}evidence of proof\textsf{''} for the sequent. \begin{figure} \begin{centering} @@ -1698,28 +1939,28 @@ \subsubsection*{Extracting code from proofs} \noindent\fbox{\begin{minipage}[t]{1\columnwidth - 2\fboxsep - 2\fboxrule}% {\small{} \begin{align*} -\frac{}{\Gamma,A\vdash{\color{blue}A}}~(\text{Id})\quad & \quad\text{Proof}\,(\Gamma,A\vdash A)_{\text{given }p^{:\Gamma},x^{:A}}=x\\ -\frac{}{\Gamma\vdash{\color{blue}\top}}~(\text{True})\quad & \quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\\ -\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma,A\Rightarrow B\vdash C)_{\text{given }p^{:\Gamma},q^{:A\rightarrow B}}\\ +\frac{}{\Gamma,A\vdash{\color{red}A}}~(\text{Id})\quad & \quad\text{Proof}\,(\Gamma,A\vdash A)_{\text{given }p^{:\Gamma},x^{:A}}=x\\ +\frac{}{\Gamma\vdash{\color{red}\top}}~(\text{True})\quad & \quad\text{Proof}\,(\Gamma\vdash\top)_{\text{given }p^{:\Gamma}}=1\\ +\frac{\Gamma,A\Rightarrow B\vdash A\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\Rightarrow B}\vdash C}~(\text{Left}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma,A\Rightarrow B\vdash C)_{\text{given }p^{:\Gamma},q^{:A\rightarrow B}}\\ & \quad\quad=\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p,b^{:B}}\\ \text{where} & \quad b^{:B}\triangleq q\big(\text{Proof}\,(\Gamma,A\Rightarrow B\vdash A)_{\text{given }p,q}\big)\\ -\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{blue}A\Rightarrow B}}~(\text{Right}\Rightarrow)\quad & \quad\text{Proof}\,(\Gamma\vdash A\Rightarrow B)_{\text{given }p^{:\Gamma}}\\ +\frac{\Gamma,A\vdash B}{\Gamma\vdash{\color{red}A\Rightarrow B}}~(\text{Right}\Rightarrow)\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}}\\ -\frac{\Gamma,A\vdash C}{\Gamma,{\color{blue}A\wedge B}\vdash C}~(\text{Left}\wedge_{1})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ +\frac{\Gamma,A\vdash C}{\Gamma,{\color{red}A\wedge B}\vdash C}~(\text{Left}\wedge_{1})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ & \quad\quad=\text{Proof}\,(\Gamma,A\vdash C)_{\text{given }p^{:\Gamma},a^{:A}}\\ -\frac{\Gamma,B\vdash C}{\Gamma,{\color{blue}A\wedge B}\vdash C}~(\text{Left}\wedge_{2})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ +\frac{\Gamma,B\vdash C}{\Gamma,{\color{red}A\wedge B}\vdash C}~(\text{Left}\wedge_{2})\quad & \quad\text{Proof}\,(\Gamma,A\wedge B\vdash C)_{\text{given }p^{:\Gamma},(a^{:A}\times b^{:B})}\\ & \quad\quad=\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p^{:\Gamma},b^{:B}}\\ -\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{blue}A\wedge B}}~(\text{Right}\wedge)\quad & \quad\text{Proof}\,(\Gamma\vdash A\wedge B)_{\text{given }p^{:\Gamma}}\\ +\frac{\Gamma\vdash A\quad\quad\Gamma\vdash B}{\Gamma\vdash{\color{red}A\wedge B}}~(\text{Right}\wedge)\quad & \quad\text{Proof}\,(\Gamma\vdash A\wedge B)_{\text{given }p^{:\Gamma}}\\ & \quad\quad=\text{Proof}\,(\Gamma\vdash A)_{\text{given }p^{:\Gamma}}\\ & \quad\quad\quad\times\text{Proof}\,(\Gamma\vdash B)_{\text{given }p^{:\Gamma}}\\ -\frac{\Gamma,A\vdash C\quad\quad\Gamma,B\vdash C}{\Gamma,{\color{blue}A\vee B}\vdash C}~(\text{Left}\vee)\quad & \quad\text{Proof}\,(\Gamma,A\vee B\vdash C)_{\text{given }p^{:\Gamma},q^{:A+B}}\\ +\frac{\Gamma,A\vdash C\quad\quad\Gamma,B\vdash C}{\Gamma,{\color{red}A\vee B}\vdash C}~(\text{Left}\vee)\quad & \quad\text{Proof}\,(\Gamma,A\vee B\vdash C)_{\text{given }p^{:\Gamma},q^{:A+B}}\\ & \quad\quad=q\triangleright\begin{array}{|c||c|} & C\\ \hline A & x^{:A}\rightarrow\text{Proof}\,(\Gamma,A\vdash C)_{\text{given }p,x}\\ B & y^{:B}\rightarrow\text{Proof}\,(\Gamma,B\vdash C)_{\text{given }p,y} \end{array}\\ -\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) +\frac{\Gamma\vdash A}{\Gamma\vdash{\color{red}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{red}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{} }% @@ -1860,8 +2101,8 @@ \subsubsection*{The LJT algorithm} Each of these rules contains a different pattern instead of $A$ in the premise $A\Rightarrow C$: \begin{align*} -\text{(}A\text{ is atomic)\,}\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{blue}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\qquad & \quad\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\\ -\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\quad\Gamma,C\vdash D}{\Gamma,{\color{blue}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\qquad & \quad\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee}) +\text{(}A\text{ is atomic)\,}\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{red}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\qquad & \quad\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\\ +\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\quad\Gamma,C\vdash D}{\Gamma,{\color{red}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\qquad & \quad\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee}) \end{align*} The rule \textsf{``}$\text{Left}\Rightarrow_{A}$\textsf{''} applies only if the implication starts with an \textsf{``}atomic\textsf{''} type expression, i.e., a single type parameter @@ -1881,7 +2122,7 @@ \subsubsection*{The LJT algorithm} define the set of proof transformers sufficient for using the LJT algorithm in practice. The \index{curryhoward library@\texttt{curryhoward} library}\lstinline!curryhoward! library\texttt{}\footnote{See \texttt{\href{https://github.com/Chymyst/curryhoward}{https://github.com/Chymyst/curryhoward}}} -implements these proof transformers. +implements those proof transformers. The most complicated of the new rules is the rule \textsf{``}($\text{Left}\Rightarrow_{\Rightarrow}$)\textsf{''}. It is far from obvious why the rule $\text{Left}\Rightarrow_{\Rightarrow}$ @@ -1943,16 +2184,16 @@ \subsubsection*{The LJT algorithm} \noindent\fbox{\begin{minipage}[t]{1\columnwidth - 2\fboxsep - 2\fboxrule}% {\small{} \begin{align*} -\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{blue}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\quad & \quad\text{Proof}\,(\Gamma,A,A\Rightarrow B\vdash D)_{\text{given }p^{:\Gamma},x^{:A},q^{:A\rightarrow B}}\\ +\frac{\Gamma,A,B\vdash D}{\Gamma,A,{\color{red}A\Rightarrow B}\vdash D}~(\text{Left}\Rightarrow_{A})\quad & \quad\text{Proof}\,(\Gamma,A,A\Rightarrow B\vdash D)_{\text{given }p^{:\Gamma},x^{:A},q^{:A\rightarrow B}}\\ & \quad\quad=\text{Proof}\,(\Gamma,A,B\vdash D)_{\text{given }p,x,q(x)}\\ -\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\quad & \quad\text{Proof}\,(\Gamma,(A\wedge B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A\times B\rightarrow C}}\\ +\frac{\Gamma,A\Rightarrow B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\wedge B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\wedge})\quad & \quad\text{Proof}\,(\Gamma,(A\wedge B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A\times B\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,\\ & \quad\quad\quad A\Rightarrow B\Rightarrow C\vdash D)_{\text{given }p,(a^{:A}\rightarrow b^{:B}\rightarrow q(a\times b))}\\ -\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{blue}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee})\quad & \quad\text{Proof}\,(\Gamma,(A\vee B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A+B\rightarrow C}}\\ +\frac{\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D}{\Gamma,{\color{red}(A\vee B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\vee})\quad & \quad\text{Proof}\,(\Gamma,(A\vee B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:A+B\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,A\Rightarrow C,B\Rightarrow C\vdash D)_{\text{given }p,r,s}\\ & \quad\quad\text{where}~r\triangleq a^{:A}\rightarrow q(a+\bbnum 0)\\ & \quad\quad\text{ and }s\triangleq b^{:B}\rightarrow q(\bbnum 0+b)\\ -\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\Gamma,C\vdash D}{\Gamma,{\color{blue}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\quad & \quad\text{Proof}\,(\Gamma,(A\Rightarrow B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:\left(A\rightarrow B\right)\rightarrow C}}\\ +\frac{\Gamma,B\Rightarrow C\vdash A\Rightarrow B\quad\Gamma,C\vdash D}{\Gamma,{\color{red}(A\Rightarrow B)\Rightarrow C}\vdash D}~(\text{Left}\Rightarrow_{\Rightarrow})\quad & \quad\text{Proof}\,(\Gamma,(A\Rightarrow B)\Rightarrow C\vdash D)_{\text{given }p^{:\Gamma},q^{:\left(A\rightarrow B\right)\rightarrow C}}\\ & \quad\quad=\text{Proof}\,(\Gamma,C\vdash D)_{\text{given }p,c}\\ & \quad\quad\text{ where}~c^{:C}\triangleq q\big(\text{Proof}\,(\Gamma,\\ & \quad\quad\quad\quad\quad\quad\quad\quad B\Rightarrow C\vdash A\Rightarrow B)_{\text{given }p,r}\big)\\ @@ -1969,7 +2210,7 @@ \subsubsection*{The LJT algorithm} The reason the LJT algorithm terminates is that each rule replaces a given sequent by one or more sequents with simpler premises or goals.\footnote{The paper \texttt{\href{http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.35.2618}{http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.35.2618}} shows that the LJT algorithm terminates by giving an explicit decreasing -measure on proof trees.} This guarantees that the proof search will terminate either with +measure on sequents.} This guarantees that the proof search will terminate either with a complete proof or with a sequent to which no more rules apply. An example of such a \textsf{``}dead-end\textsf{''} sequent is $\alpha\vdash\beta$ where $\alpha$ and $\beta$ are different, unrelated propositions. When @@ -2007,8 +2248,8 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi into a \index{truth table}truth table. The formula is true if all values in its truth table are $True$. -Disjunction, conjunction, negation, and implication operations have -the following truth table: +Disjunction, conjunction, negation, and implication operations are +described by this truth table: \begin{center} {\small{}}% \begin{tabular}{|c|c|c|c|c|c|} @@ -2073,7 +2314,7 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi \hline {\footnotesize{}$\forall\alpha.\,\alpha\Rightarrow True$} & {\footnotesize{}$\forall A.\,A\rightarrow\bbnum 1$} & \lstinline!def toUnit[A](x: A): Unit = ()!\tabularnewline \hline -{\footnotesize{}$\forall(\alpha,\beta).\,\alpha\Rightarrow(\alpha\vee\beta)$} & {\footnotesize{}$\forall(A,B).\,A\rightarrow A+B$} & \lstinline!def f[A, B](x: A): Either[A, B] = Left(x)!\tabularnewline +{\footnotesize{}$\forall(\alpha,\beta).\,\alpha\Rightarrow(\alpha\vee\beta)$} & {\footnotesize{}$\forall(A,B).\,A\rightarrow A+B$} & \lstinline!def f[A,B](x: A): Either[A,B] = Left(x)!\tabularnewline \hline {\footnotesize{}$\forall(\alpha,\beta).\,(\alpha\wedge\beta)\Rightarrow\alpha$} & {\footnotesize{}$\forall(A,B).\,A\times B\rightarrow A$} & \lstinline!def f[A, B](p: (A, B)): A = p._1!\tabularnewline \hline @@ -2110,76 +2351,23 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi \end{table} At first sight, it may appear from these examples that whenever a -logical formula is true in Boolean logic, the corresponding type signature +formula is true in Boolean logic, the corresponding type signature can be implemented in code, and vice versa. However, this is \emph{incorrect}: the rules of Boolean logic are not fully suitable for reasoning about -types in a functional language. We will now show some examples of -formulas that are true in Boolean logic but correspond to unimplementable -type signatures. - -The first example is given by the following type: +types in a functional language. False Boolean formulas do correspond +to unimplementable type signatures. But \emph{not all} true Boolean +formulas correspond to implementable function types. An example is +the function \lstinline!bad3! shown in Section~\ref{subsec:Motivation-and-outlook}: +\begin{lstlisting} +def bad3[A, B, C](g: A => Either[B, C]): Either[A => B, A => C] = ??? +\end{lstlisting} \begin{equation} \forall(A,B,C).\,\left(A\rightarrow B+C\right)\rightarrow\left(A\rightarrow B\right)+\left(A\rightarrow C\right)\quad,\label{eq:ch-example-boolean-bad-type} \end{equation} -which corresponds to the Scala type signature (shown in Section~\ref{subsec:Motivation-and-outlook}): -\begin{lstlisting} -def bad2[A, B, C](g: A => Either[B, C]): Either[A => B, A => C] = ??? -\end{lstlisting} -The function \lstinline!bad2! \emph{cannot} be implemented via fully -parametric code. To see why, consider that the only available data -is a function $g^{:A\rightarrow B+C}$, which returns values of type -$B$ or $C$ depending (in some unknown way) on the input value of -type $A$. The function \lstinline!bad2! must return either a function -of type $A\rightarrow B$ or a function of type $A\rightarrow C$. -How can the code of \lstinline!bad2! make that decision? The only -input data is the function $g$ that takes an argument of type $A$. -We could imagine applying $g$ to various arguments of type $A$ and -to see whether $g$ returns a $B$ or a $C$. However, the type $A$ -is arbitrary, and a fully parametric function cannot produce a value -of type $A$ in order to apply $g$ to it. So, the decision about -whether to return $A\rightarrow B$ or $A\rightarrow C$ must be independent -of $g$. That decision must be hard-coded in the function \lstinline!bad2!. - -Suppose we hard-coded the decision to return a function of type $A\rightarrow B$. -How would we create a function of type $A\rightarrow B$ in the body -of \lstinline!bad2!? Given a value $x^{:A}$ of type $A$, we would -need to compute some value of type $B$. Since the type $B$ is arbitrary -(it is a type parameter), we cannot produce a value of type $B$ from -scratch. The only potential source of values of type $B$ is the given -function $g$. The only way of using $g$ is to apply it to $x^{:A}$. -However, for some $x$, the value $g(x)$ may be of the form \lstinline!Right(c)!, -where \lstinline!c! is of type $C$. In that case, we will have a -value of type $C$, not $B$. So, in general, we cannot guarantee -that we can always obtain a value of type $B$ from a given value -$x^{:A}$. This means we cannot build a function of type $A\rightarrow B$ -out of the function $g$. Similarly, we cannot build a function of -type $A\rightarrow C$ out of $g$. - -Whether we decide to return $A\rightarrow B$ or $A\rightarrow C$, -we will not be able to return a value of the required type, as we -just saw. We must conclude that we cannot implement \lstinline!bad! -as a fully parametric function. - -We could try to switch between $A\rightarrow B$ and $A\rightarrow C$ -depending on a given value of type $A$. This idea, however, means -that we are working with a different type signature: -\[ -\forall(A,B,C).\,\left(A\rightarrow B+C\right)\rightarrow A\rightarrow\left(A\rightarrow B\right)+\left(A\rightarrow C\right)\quad. -\] -This type signature \emph{can} be implemented, for instance, by this -Scala code: -\begin{lstlisting} -def q[A, B, C](g: A => Either[B, C]): A => Either[A => B, A => C] = { a => - g(a) match { - case Left(b) => Left(_ => b) - case Right(c) => Right(_ => c) - } -} -\end{lstlisting} -But this is not the required type signature~(\ref{eq:ch-example-boolean-bad-type}). - -Now let us convert the type signature~(\ref{eq:ch-example-boolean-bad-type}) -into a ${\cal CH}$-proposition: +The function \lstinline!bad3! \emph{cannot} be implemented via fully +parametric code, as we already discussed in Section~\ref{subsec:Motivation-and-outlook}. +Now, the type signature~(\ref{eq:ch-example-boolean-bad-type}) gives +this ${\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}\\ {\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 @@ -2188,15 +2376,15 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi this, we need to show that Eq.~(\ref{eq:abc-example-classical-logic-bad}) is equal to $True$ for any Boolean values of the variables $\alpha$, $\beta$, $\gamma$. One way is to rewrite the expression~(\ref{eq:abc-example-classical-logic-bad}) -using the rules of Boolean logic, such as Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic}): +using the rules of Boolean logic: \begin{align*} & \gunderline{\alpha\Rightarrow}\left(\beta\vee\gamma\right)\\ {\color{greenunder}\text{definition of }\Rightarrow\text{ via Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:}\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad,\\ & \gunderline{\left(\alpha\Rightarrow\beta\right)}\vee\gunderline{\left(\alpha\Rightarrow\gamma\right)}\\ {\color{greenunder}\text{definition of }\Rightarrow\text{ via Eq.~(\ref{eq:ch-definition-of-implication-in-Boolean-logic})}:}\quad & \quad=\gunderline{(\neg\alpha)}\vee\beta\vee\gunderline{(\neg\alpha)}\vee\gamma\\ -{\color{greenunder}\text{property }x\vee x=x\text{ in Boolean logic}:}\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad, +{\color{greenunder}\text{property }x\vee x=x\text{ in Boolean logic}:}\quad & \quad=(\neg\alpha)\vee\beta\vee\gamma\quad. \end{align*} -showing that $\alpha\Rightarrow(\beta\vee\gamma)$ is in fact \emph{equal} +So, $\alpha\Rightarrow(\beta\vee\gamma)$ is in fact \emph{equal} to $\left(\alpha\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\gamma\right)$ in Boolean logic. @@ -2205,8 +2393,8 @@ \subsection{Failure of Boolean logic in reasoning about $\mathcal{CH}$-propositi 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$ and $\left(\alpha\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\gamma\right)=False$. -A disjunction can be false only when both parts are false; so we must -have both $\left(\alpha\Rightarrow\beta\right)=False$ and $\left(\alpha\Rightarrow\gamma\right)=False$. +A disjunction can be false only when both parts are false. So, we +must have both $\left(\alpha\Rightarrow\beta\right)=False$ and $\left(\alpha\Rightarrow\gamma\right)=False$. This is only possible if $\alpha=True$ and $\beta=\gamma=False$. But, with these value assignments, we find $\left(\alpha\Rightarrow(\beta\vee\gamma)\right)=False$ rather than $True$ as we assumed. It follows that we cannot ever @@ -2345,8 +2533,7 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse \lstinline!f1 andThen f2!. We omit type annotations since we already checked that the types match.) If these conditions hold, there is a one-to-one correspondence between values of types $P$ and $Q$. -This is the same as to say that the data types $P$ and $Q$ \textsf{``}carry -equivalent information\textsf{''}. +In other words, the data types $P$ and $Q$ carry equivalent information. To verify that the Scala functions \lstinline!f1! and \lstinline!f2! defined above are inverses of each other, we first check if $f_{1}\bef f_{2}=\text{id}$. @@ -2459,7 +2646,7 @@ \subsection{Logical identity does not correspond to type equivalence\label{subse correspondence maps Eq.~(\ref{eq:ch-example-distributive-2}) into the type equation: \begin{equation} -\forall(A,B,C).\,\left(A\times B\right)+C=\left(A+C\right)\times\left(B+C\right)\quad.\label{eq:ch-example-incorrect-identity-2} +\forall(A,B,C).\,\left(A\times B\right)+C\overset{?}{=}\left(A+C\right)\times\left(B+C\right)\quad.\label{eq:ch-example-incorrect-identity-2} \end{equation} However, the types $A\times B+C$ and $\left(A+C\right)\times\left(B+C\right)$ are \emph{not} equivalent. To see why, look at the possible code of @@ -2523,14 +2710,14 @@ \subsection{Arithmetic identity corresponds to type equivalence} corresponding type equivalences. In all rows, quantifiers such as $\forall\alpha$ or $\forall(A,B)$ are implied as necessary. -Because we chose the type notation to be similar to the ordinary arithmetic -notation, it is easy to translate a possible type equivalence into -an arithmetic equation. In all cases, valid arithmetic identities -correspond to type equivalences, and failures to obtain a type equivalence -correspond to incorrect arithmetic identities. With regard to type -equivalence, types such as $A+B$ and $A\times B$ behave similarly -to arithmetic expressions such as $10+20$ and $10\times20$ and not -similarly to logical formulas such as $\alpha\vee\beta$ and $\alpha\wedge\beta$. +Because the type notation is similar to the ordinary arithmetic notation, +it is easy to translate a possible type equivalence into an arithmetic +equation. In all cases, valid arithmetic identities correspond to +type equivalences, and failures to obtain a type equivalence correspond +to incorrect arithmetic identities. With regard to type equivalence, +types such as $A+B$ and $A\times B$ behave similarly to arithmetic +expressions such as $10+20$ and $10\times20$ and not similarly to +logical formulas such as $\alpha\vee\beta$ and $\alpha\wedge\beta$. \begin{table} \begin{centering} @@ -2610,14 +2797,14 @@ \subsubsection{Example \label{subsec:ch-Example-0-plus-A}\ref{subsec:ch-Example- The argument of $f_{1}$ is of type \lstinline!Either[Nothing, A]!. How can we create a value of that type? Our only choices are to create -a \lstinline!Left(x)! with \lstinline!x:Nothing!, or to create a -\lstinline!Right(y)! with \lstinline!y:A!. However, we cannot create -a value \lstinline!x! of type \lstinline!Nothing! because the type -\lstinline!Nothing! has \emph{no} values. We cannot create a \lstinline!Left(x)!. -The only remaining possibility is to create a \lstinline!Right(y)! -with some value \lstinline!y! of type \lstinline!A!. So, any values -of type $\bbnum 0+A$ must be of the form \lstinline!Right(y)!, and -we can extract that \lstinline!y! to obtain a value of type \lstinline!A!: +a \lstinline!Left(x)! with \lstinline!x: Nothing!, or to create +a \lstinline!Right(y)! with \lstinline!y: A!. However, we cannot +create a value \lstinline!x! of type \lstinline!Nothing! because +the type \lstinline!Nothing! has \emph{no} values. We cannot create +a \lstinline!Left(x)!. The only remaining possibility is to create +a \lstinline!Right(y)! with some value \lstinline!y! of type \lstinline!A!. +So, any values of type $\bbnum 0+A$ must be of the form \lstinline!Right(y)!, +and we can extract that \lstinline!y! to obtain a value of type \lstinline!A!: \begin{lstlisting} def f1[A]: Either[Nothing, A] => A = { case Right(y) => y @@ -2632,49 +2819,6 @@ \subsubsection{Example \label{subsec:ch-Example-0-plus-A}\ref{subsec:ch-Example- It is clear from the code that the functions \lstinline!f1! and \lstinline!f2! are inverses of each other. -We have just seen that a value of type $\bbnum 0+A$ is a \lstinline!Right(y)! -with some \lstinline!y: A!. Similarly, a value of type $A+\bbnum 0$ -is always a \lstinline!Left(x)! with some \lstinline!x: A!. So, -we will use the notation $A+\bbnum 0$ and $\bbnum 0+A$ to \emph{denote} -the \lstinline!Left! and the \lstinline!Right! parts of the disjunctive -type \lstinline!Either!. This notation agrees with the behavior of -the Scala compiler, which will infer the types \lstinline!Either[A, Nothing] !or -\lstinline!Either[Nothing, A]! for these parts: -\begin{lstlisting} -def toLeft[A, B]: A => Either[A, B] = x => Left(x) -def toRight[A, B]: B => Either[A, B] = y => Right(y) - -scala> toLeft(123) -res0: Either[Int, Nothing] = Left(123) - -scala> toRight("abc") -res1: Either[Nothing, String] = Right("abc") -\end{lstlisting} -We can write the functions \lstinline!toLeft! and \lstinline!toRight! -in a code notation as: -\[ -\text{toLeft}^{A,B}\triangleq x^{:A}\rightarrow x+\bbnum 0^{:B}\quad,\quad\quad\text{toRight}^{A,B}\triangleq y^{:B}\rightarrow\bbnum 0^{:A}+y\quad. -\] -In this notation, a value of the disjunctive type is shown without -using Scala class names such as \lstinline!Either!, \lstinline!Right!, -and \lstinline!Left!. This shortens the writing and speeds up code -reasoning. - -The type annotation $\bbnum 0^{:A}$ is helpful to remind ourselves -about the type parameter $A$ used, e.g., by the disjunctive value -$\bbnum 0^{:A}+y^{:B}$ in the body of \lstinline!toRight[A, B]!. -Without this type annotation, $\bbnum 0+y^{:B}$ means a value of -type \lstinline!Either[A, B]! where the parameter $A$ should be -determined by matching the types of other expressions. When it is -clear what types are being used, we may omit type annotations and -write simply $\bbnum 0+y$ instead of $\bbnum 0^{:A}+y^{:B}$. - -In the notation $\bbnum 0+y^{:B}$, we use the symbol $\bbnum 0$ -rather than an ordinary zero ($0$), to avoid suggesting that $0$ -is a value of type $\bbnum 0$. The void type $\bbnum 0$ has \emph{no} -values, unlike the \lstinline!Unit! type, $\bbnum 1$, which has -a value denoted by $1$ in the code notation. - \subsubsection{Example \label{subsec:ch-Example-1xA}\ref{subsec:ch-Example-1xA}} Verify the type equivalence $A\times\bbnum 1\cong A$. @@ -2735,7 +2879,7 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} by code that can be derived unambiguously from the type signatures. For instance, the line \lstinline!case Left(a) => ...! is required to return a value of type \lstinline!Either[B, A]! by using a given -value \lstinline!a:A!. The only way of doing that is by returning +value \lstinline!a: A!. The only way of doing that is by returning \lstinline!Right(a)!. It is clear from the code that the functions \lstinline!f1! and \lstinline!f2! @@ -2775,9 +2919,9 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} \end{cases} \] Since both the argument and the result of $f_{1}$ are disjunctive -types with $2$ parts each, it is convenient to write the code of -$f_{1}$ as a $2\times2$ \emph{matrix} that maps the input parts -to the output parts:\index{disjunctive type!in matrix notation}\index{matrix notation} +types with $2$ parts each, the code notation represents $f_{1}$ +as a $2\times2$ \emph{matrix} that maps the input parts to the output +parts:\index{disjunctive type!matrix notation}\index{matrix notation} \begin{lstlisting} def f1[A, B]: Either[A, B] => Either[B, A] = { case Left(a) => Right(a) @@ -2791,19 +2935,16 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} B & b^{:B}\rightarrow b & \bbnum 0 \end{array}\quad. \] -The rows of the matrix correspond to the \lstinline!case! rows in -the Scala code. There is one row for each part of the disjunctive -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 +\index{pattern matching!in matrix notation} The matrix element in +row $A$ and column $A$ is a function $a^{:A}\rightarrow a$ of type $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 all lines of the \lstinline!match!/\lstinline!case! -expression into a code matrix. +The matrix row $B$ contains just the function $b^{:B}\rightarrow b$ +in the first column. In the second column, row~$B$ contains a $\bbnum 0$. The code of $f_{2}$ is written similarly. Let us rename arguments -for clarity:\hfill{} +for clarity: \begin{lstlisting} def f2[A, B]: Either[B, A] => Either[A, B] = { case Left(y) => Right(y) @@ -2872,7 +3013,7 @@ \subsubsection{Example \label{subsec:ch-Example-A+B}\ref{subsec:ch-Example-A+B}} \bbnum 0 & \text{id} \end{array}\,=\text{id}\quad. \end{align*} -The identity function is represented by the diagonal matrix: $\,\begin{array}{||cc|} +The identity function is represented by this diagonal matrix: $\,\begin{array}{||cc|} \text{id} & \bbnum 0\\ \bbnum 0 & \text{id} \end{array}$~. @@ -2904,30 +3045,45 @@ \subsection{Type cardinalities and type equivalence} consider the question of how many different values a given type can have. +For a given type $A$, let us denote by $\left|A\right|$ the number +of distinct values of type $A$. The number $\left|A\right|$ is called +the \index{cardinality}\textbf{cardinality} of type $A$. This is +the same as the number of elements in the set of all values of type +$A$. + Begin by counting the number of distinct values for simple types. -For example, the \lstinline!Unit! type has only one distinct value; +We find that the \lstinline!Unit! type has only one distinct value; the type \lstinline!Nothing! has zero values; the \lstinline!Boolean! type has two distinct values (\lstinline!true! and \lstinline!false!); and the type \lstinline!Int! has $2^{32}$ distinct values. It is more difficult to count the number of distinct values in a type such as \lstinline!String!, which is equivalent to a list of unknown -length, \lstinline!List[Char]!. However, each computer\textsf{'}s memory is -limited, so there will exist a maximum length for values of type \lstinline!String!. -So, the total number of possible different strings will be finite -(but will depend on the computer). - -For a given type $A$, let us denote by $\left|A\right|$ the number -of distinct values of type $A$. The number $\left|A\right|$ is called -the \index{cardinality}\textbf{cardinality} of type $A$. This is -the same as the number of elements in the set of all values of type -$A$. Since any computer\textsf{'}s memory is finite, there will be \emph{finitely} -many different values of a given type $A$ that can exist in the computer. -So, we may assume that $\left|A\right|$ is always a finite integer -value. This assumption will simplify our reasoning. We will not actually -need to compute the precise number of, say, all the different possible -strings. It is sufficient to know that the set of all strings is finite, -so that we can denote its cardinality by $|\text{String}|$. +length, \lstinline!List[Char]!. In practice, each computer\textsf{'}s memory +is limited, so there will exist a maximum length for values of type +\lstinline!String!. So, the total number of possible different strings +will be finite, depending on the computer. Similarly, the set of all +possible values of type \lstinline!List[Int]! will be a finite set. + +But this introduces an arbitrary limit on the total size of data, +which is inconvenient for reasoning about programs. For instance, +string concatenation and list concatenation will become partial functions; +those operations will fail when the total size of the result is larger +than the memory limit. It is more convenient to imagine a computer +with an infinite array of memory locations. On that computer, each +program is still only allowed to use a finite amount of memory, but +that amount is not limited in advance. Then all basic operations on +data types become total functions; for example, the concatenation +of any two strings is always well-defined. + +In the model of an infinite computer, the set of all possible strings +will be a countably infinite set consisting of all possible character +sequences (where characters come from a finite set). Similarly, the +set of all possible values of type \lstinline!List[Int]! will be +a countably infinite set. This makes it difficult to reason about +the total number of values of a given type. So, for the purposes of +this section, we will limit our consideration to types $A$, $B$, +..., that have \emph{finite} cardinalities. The next step is to consider the cardinality of types such as $A\times B$ and $A+B$. If the types $A$ and $B$ have cardinalities $\left|A\right|$ @@ -3064,7 +3220,7 @@ \subsubsection{Example \label{subsec:ch-Example-cardinality-option-either}\ref{s \subsection{Type equivalence involving function types} Until now, we have looked at product types and disjunctive types. -We now turn to type constructions involving function types. +We now turn to type expressions involving function types. Consider two types $A$ and $B$ having known cardinalities $\left|A\right|$ and $\left|B\right|$. How many distinct values does the function @@ -3091,16 +3247,19 @@ \subsection{Type equivalence involving function types} of those functions will be much larger than the available memory of a realistic computer. So, the number of practically implementable functions of type $A\rightarrow B$ can be much smaller than $\left|B\right|^{\left|A\right|}$. -Since the code of a function is a string of bytes that needs to fit +Since the code of a function is a list of bytes that needs to fit into the computer\textsf{'}s memory, the number of implementable functions -is no larger than the number of possible byte strings. +is no larger than the number of possible byte lists. 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, 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. +in principle, on an imaginary computer with infinite memory (although +we still need to limit our consideration to types $A$, $B$ with +finite cardinalities $\left|A\right|$, $\left|B\right|$). When types +$A$ and $B$ have only a small number of 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. Let us now look for logic identities and arithmetic identities involving function types. Table~\ref{tab:Logical-identities-with-function-types} @@ -3180,13 +3339,12 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-f}\ref{subsec:ch-E and then using the code notation. Writing Scala code, compute \lstinline!f1(f2(x))! for an arbitrary -\lstinline!x:A!. Using the code of \lstinline!f1! and \lstinline!f2!, -we get: +\lstinline!x: A!. Use the code of \lstinline!f1! and \lstinline!f2! +and get: \begin{lstlisting} f1(f2(x)) == f1(_ => x) == (_ => x)(()) == x \end{lstlisting} -Now compute \lstinline!f2(f1(h))! for arbitrary \lstinline!h: Unit => A! -in Scala code: +Now compute \lstinline!f2(f1(h))! for arbitrary \lstinline!h: Unit => A!. \begin{lstlisting} f2(f1(h)) == f2(h(())) == { _ => h(()) } \end{lstlisting} @@ -3286,22 +3444,21 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-0-to-A}\ref{subsec \subsubsection{Example \label{subsec:ch-Example-type-identity-A-0}\ref{subsec:ch-Example-type-identity-A-0}} Show that $A\rightarrow\bbnum 0\not\cong\bbnum 0$ and $A\rightarrow\bbnum 0\not\cong\bbnum 1$, -where $A$ is an arbitrary type. +where $A$ is an arbitrary unknown type. \subparagraph{Solution} To prove that two types are \emph{not} equivalent, it is sufficient -to show that their cardinalities are different. Let us determine the -cardinality of the type $A\rightarrow\bbnum 0$, assuming that the -cardinality of $A$ is known. We note that a function of type, say, -$\text{Int}\rightarrow\bbnum 0$ is impossible to implement. (If we -had such a function $f^{:\text{Int}\rightarrow\bbnum 0}$, we could -evaluate, say, $x\triangleq f(123)$ and obtain a value $x$ of type -$\bbnum 0$, which is impossible by definition of the type $\bbnum 0$. -It follows that $\left|\text{Int}\rightarrow\bbnum 0\right|=0$. However, -Example~\ref{subsec:ch-Example-type-identity-0-to-A} shows that -$\bbnum 0\rightarrow\bbnum 0$ has cardinality $1$. So, we find that -$\left|A\rightarrow\bbnum 0\right|=1$ if the type $A$ is itself +to show that their cardinalities are different. Let us determine how +the cardinality of the type $A\rightarrow\bbnum 0$ depends on the +cardinality of $A$. We note that a function of type, say, $\text{Int}\rightarrow\bbnum 0$ +is impossible to implement. (If we had such a function $f^{:\text{Int}\rightarrow\bbnum 0}$, +we could evaluate, say, $x\triangleq f(123)$ and obtain a value $x$ +of type $\bbnum 0$, which is impossible by definition of the type +$\bbnum 0$.) It follows that $\left|\text{Int}\rightarrow\bbnum 0\right|=0$. +However, Example~\ref{subsec:ch-Example-type-identity-0-to-A} shows +that $\bbnum 0\rightarrow\bbnum 0$ has cardinality $1$. So, we find +that $\left|A\rightarrow\bbnum 0\right|=1$ if the type $A$ is itself $\bbnum 0$ but $\left|A\rightarrow\bbnum 0\right|=0$ for all other types $A$. We conclude that the type $A\rightarrow\bbnum 0$ is not equivalent to $\bbnum 0$ or $\bbnum 1$ when $A$ is an unknown type. @@ -3385,12 +3542,12 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E \lstinline!(A => C, B => C)!. Can we produce the first part of that pair? Computing a function of type \lstinline!A => C! means that we need to produce a value of type \lstinline!C! given an arbitrary -value \lstinline!a:A!. The available data is a function of type \lstinline!Either[A, B] => C! -called, say, \lstinline!h!. We can apply that function to \lstinline!Left(a)! -and obtain a value of type \lstinline!C! as required. So, a function -of type \lstinline!A => C! is computed as \lstinline!a => h(Left(a))!. -We can produce a function of type \lstinline!B => C! similarly. The -code is: +value \lstinline!a: A!. The available data is a function of type +\lstinline!Either[A, B] => C! called, say, \lstinline!h!. We can +apply that function to \lstinline!Left(a)! and obtain a value of +type \lstinline!C! as required. So, a function of type \lstinline!A => C! +is computed as \lstinline!a => h(Left(a))!. We can produce a function +of type \lstinline!B => C! similarly. The code is: \begin{lstlisting} def f1[A, B, C]: (Either[A, B] => C) => (A => C, B => C) = (h: Either[A, B] => C) => (a => h(Left(a)), b => h(Right(b))) @@ -3605,9 +3762,9 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-5}\ref{subsec:ch-E on, we will prefer to use the code notation in proofs, keeping in mind that one can always convert the code notation to Scala. -Note that the function arrow ($\rightarrow$) binds weaker than the -pipe operation ($\triangleright$), so the code notation $x\rightarrow y\triangleright z$ -means $x\rightarrow(y\triangleright z)$. We will review the code +The function arrow ($\rightarrow$) binds weaker than the pipe\index{pipe notation!operator precedence} +operation ($\triangleright$), so the formula $x\rightarrow y\triangleright z$ +means $x\rightarrow(y\triangleright z)$. We will review the pipe notation more systematically in Chapter~\ref{chap:Reasoning-about-code}. \subsubsection{Example \label{subsec:ch-Example-type-identity-6}\ref{subsec:ch-Example-type-identity-6}} @@ -3635,9 +3792,9 @@ \subsubsection{Example \label{subsec:ch-Example-type-identity-6}\ref{subsec:ch-E & f_{1}=g^{:A\times B\rightarrow C}\rightarrow a^{:A}\rightarrow b^{:B}\rightarrow g(a\times b)\quad,\\ & f_{2}=h^{:A\rightarrow B\rightarrow C}\rightarrow\left(a\times b\right)^{:A\times B}\rightarrow h(a)(b)\quad. \end{align*} -We denote by $\left(a\times b\right)^{:A\times B}$ the argument of +We denote by $\left(a\times b\right)^{:A\times B}$ an argument of type \lstinline!(A, B)! with pattern matching implied. This notation -allows us to write shorter code formulas involving tupled arguments. +allows us to write shorter code formulas where tuples are destructured. Compute the function composition $f_{1}\bef f_{2}$ and show that it is equal to an identity function: @@ -3679,8 +3836,8 @@ \section{Summary} \item Automatically generate code for \emph{recursive} functions. The CH correspondence is based on propositional logic, which cannot describe recursion. Accordingly, recursion is absent from the eight code constructions -of Section~\ref{subsec:The-rules-of-proof}. Recursive functions -need to be coded by hand. +of Section~\ref{subsec:Short-notation-for-eight-code-constructions}. +Recursive functions need to be coded by hand. \item Automatically generate code satisfying a property (e.g., isomorphism). We may generate some code, but the CH correspondence does not guarantee that properties will hold. We need to verify the required properties @@ -3939,8 +4096,9 @@ \subsubsection{Example \label{subsec:ch-solvedExample-3}\ref{subsec:ch-solvedExa We have implemented all four type signatures as fully parametric functions, which shows that the corresponding logical formulas are all true (i.e., -can be derived using the proof rules). However, the functions cannot -be inverses of each other. So, the type equivalences do not hold. +can be derived using the proof rules). However, the functions $f_{1}$ +and $f_{2}$ are not inverses of each other. So, the type equivalences +do not hold. \subsubsection{Example \label{subsec:ch-solvedExample-4}\ref{subsec:ch-solvedExample-4}} @@ -4520,7 +4678,7 @@ \subsubsection{Exercise \label{subsec:ch-Exercise-1-a}\ref{subsec:ch-Exercise-1- \subsubsection{Exercise \label{subsec:ch-Exercise-1}\ref{subsec:ch-Exercise-1}} -Show that $A\Rightarrow(B\vee C)\neq(A\Rightarrow B)\wedge(A\Rightarrow C)$ +Show that $\alpha\Rightarrow(\beta\vee\gamma)\neq(\alpha\Rightarrow\beta)\wedge(\alpha\Rightarrow\gamma)$ in constructive and Boolean logic. \subsubsection{Exercise \label{subsec:ch-solvedExample-5-1}\ref{subsec:ch-solvedExample-5-1}} @@ -4628,17 +4786,17 @@ \subsubsection{Exercise \label{subsec:ch-Exercise-8}\ref{subsec:ch-Exercise-8}} \textbf{(b)} $\text{flatMap}^{Z,A,B}:\text{Sel}^{Z,A}\rightarrow(A\rightarrow\text{Sel}^{Z,B})\rightarrow\text{Sel}^{Z,B}\quad.$ -\section{Discussion and further developments} +\section{Discussion and further developments\label{sec:Discussion-curry-howard}} \subsection{Using the Curry-Howard correspondence for writing code} -The CH correspondence is used in two practically important reasoning -tasks: checking whether a type signature can be implemented as a fully -parametric function, and determining whether two types are equivalent. -For the first task, we map type expressions into formulas in the constructive -logic and apply the proof rules of that logic. For the second task, -we map type expressions into \emph{arithmetic} formulas and apply -the ordinary rules of arithmetic. +This chapter focuses on two practically important reasoning tasks: +checking if a type signature can be implemented as a fully parametric +function, and determining whether two types are equivalent. For the +first task, we use the CH correspondence to map type expressions into +formulas in the constructive logic and then apply the proof rules +of that logic. For the second task, we map type expressions into \emph{arithmetic} +formulas and apply the ordinary rules of arithmetic. Although tools such as the \lstinline!curryhoward! library can sometimes derive code from types, it is beneficial if a programmer is able to @@ -4652,14 +4810,14 @@ \subsection{Using the Curry-Howard correspondence for writing code} two type signatures have none: \begin{lstlisting} def g[A, B]: A => (B => A) => B -def h[A, B]: ((A => B) => A) => A +def h[A, B]: ((A => B) => A) => B \end{lstlisting} Exercises in this chapter help to build up the required technique and intuition. The two main guidelines for code derivation are: \textsf{``}values of parametric types cannot be constructed from scratch\textsf{''} and \textsf{``}one must hard-code the decision to return a chosen part of a disjunctive type when no other disjunctive value is given\textsf{''}. These guidelines -can be justified by referring to the rigorous rules of proof (Table~\ref{tab:Proof-rules-for-constructive-logic}). +can be justified by referring to the rules of proof in Table~\ref{tab:Proof-rules-for-constructive-logic}. Sequents producing a value of type $A$ can be proved only if there is a premise containing $A$ or a function that returns a value of type $A$.\footnote{This is proved rigorously by R.~Dyckhoff\index{Roy Dyckhoff} as @@ -4676,7 +4834,7 @@ \subsection{Using the Curry-Howard correspondence for writing code} So, the propositions $\mathcal{CH}(\text{Int})$ or $\mathcal{CH}(\text{String})$ are always true. -Consider the function \lstinline!(x:Int) => x + 1!. Its type signature, +Consider the function \lstinline!(x: Int) => x + 1!. Its type signature, \lstinline!Int => Int!, may be implemented by many other functions, such as \lstinline!x => x - 1!, \lstinline!x => x * 2!, etc. So, the type signature \lstinline!Int => Int! is insufficient to specify @@ -4707,8 +4865,7 @@ \subsection{Using the Curry-Howard correspondence for writing code} \[ \bbnum 1\times\left(A+B\right)\times C+D\cong D+A\times C+B\times C\quad. \] -The type notation makes this reasoning more intuitive (for people -familiar with arithmetic). +The type notation makes this reasoning more intuitive. These results apply to all type expressions built up using product types, disjunctive types (also called \textsf{``}sum\textsf{''} types because they @@ -4755,7 +4912,7 @@ \subsection{Implications for designing new programming languages} Today\textsf{'}s functional programming practice assumes, at the minimum, that programmers will use the six standard type constructions (Section~\ref{subsec:Type-notation-and-standard-type-constructions}) -and the eight standard code constructions (Section~\ref{subsec:The-rules-of-proof}). +and the eight standard code constructions (Section~\ref{subsec:Short-notation-for-eight-code-constructions}). 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 all of those constructions cannot be @@ -4898,7 +5055,7 @@ \subsection{Practical uses of the void type (Scala\textsf{'}s \texttt{Nothing})} type parameter $E$ to the void type \lstinline!Nothing! when applying \lstinline!parallel_run!: \begin{lstlisting} -parallel_run[Nothing, A, B](f) // Types match only when values f(a) always are of the form Right(b). +parallel_run[Nothing, A, B](f) // Types match only when values f(a) are always of the form Right(b). \end{lstlisting} Returning an error is now impossible (the type \lstinline!Nothing! has no values). If the function \lstinline!parallel_run! is fully @@ -4912,17 +5069,86 @@ \subsection{Practical uses of the void type (Scala\textsf{'}s \texttt{Nothing})} \neg\alpha\triangleq(\alpha\Rightarrow False)\quad. \] 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. +of $False$ and the void type. (The type corresponding to $\alpha\Rightarrow False$ +is the function type $A\rightarrow\bbnum 0$ or, in Scala, \lstinline!A => Nothing!.) +However, logical negation plays an important role in Boolean logic. \subsection{Relationship between Boolean logic and constructive logic\label{subsec:Relationship-between-Boolean} } We have seen that some true theorems of Boolean logic are not true -in constructive logic. For example, the Boolean identities $\neg\left(\neg\alpha\right)=\alpha$ -and $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$ do -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}) +in constructive logic. Here are some more examples: the Boolean identities +$\neg\left(\neg\alpha\right)=\alpha$ and $\left(\alpha\Rightarrow\beta\right)=(\neg\alpha\vee\beta)$. + +\subsubsection{Example \label{subsec:Example-boolean-implication-not-constructive-1}\ref{subsec:Example-boolean-implication-not-constructive-1}} + +Show that the Boolean identity $\neg\left(\neg\alpha\right)=\alpha$ +does not hold in constructive logic by arguing that there is no fully +parametric function with the type signature $((A\rightarrow\bbnum 0)\rightarrow\bbnum 0)\rightarrow A$, +or in Scala: +\begin{lstlisting} +def bad4[A](f: (A => Nothing) => Nothing): A +\end{lstlisting} + + +\subparagraph{Solution} + +The negation $\neg\alpha$ is translated by the Curry-Howard correspondence +to the type $A\rightarrow\bbnum 0$ (in Scala, \lstinline!A => Nothing!). +If the Boolean identity $\neg\left(\neg\alpha\right)=\alpha$ were +also true in the constructive logic, the formula $\neg(\neg\alpha)\Rightarrow\alpha$ +would be true. The CH correspondence then says that we would be able +to implement a fully parametric function of type $((A\rightarrow\bbnum 0)\rightarrow\bbnum 0)\rightarrow A$. +Can we do that? The result type of \lstinline!bad4! is an arbitrary, +unknown type $A$, so we cannot produce values of type $A$ from scratch. +We also do not have any given arguments of type $A$ or given functions +of type $X\rightarrow A$ for some $X$. The only remaining possibility +of implementing \lstinline!bad4! is by applying the argument \lstinline!f! +to a value of type \lstinline!A => Nothing!. The resulting value +would be of type \lstinline!Nothing!, and we would then use the function +\lstinline!absurd! from Example~\ref{subsec:ch-Example-type-identity-0-to-A} +to obtain a value of type \lstinline!A!. It remains to get a value +of type \lstinline!A => Nothing! from scratch. But we cannot do that: +Example~\ref{subsec:ch-Example-type-identity-A-0}) shows that the +type \lstinline!A => Nothing! is itself void unless \lstinline!A! +is void. So, we cannot compute a value of type \lstinline!A => Nothing! +via fully parametric code that works in the same way for all types +\lstinline!A!. We conclude that \lstinline!bad4! cannot be implemented. +$\square$ + +\subsubsection{Example \label{subsec:Example-boolean-implication-not-constructive}\ref{subsec:Example-boolean-implication-not-constructive}} + +Show that the Boolean identity $\left(\alpha\Rightarrow\beta\right)=\neg\alpha\vee\beta$ +does not hold in constructive logic by arguing that there is no fully +parametric function with the type signature $\left(A\rightarrow B\right)\rightarrow(A\rightarrow\bbnum 0)+B$, +or in Scala: +\begin{lstlisting} +def bad5[A, B](f: A => B): Either[A => Nothing, B] +\end{lstlisting} + + +\subparagraph{Solution} + +The result type of \lstinline!bad5! is a disjunctive type, but the +argument type is not. The code of \lstinline!bad5! cannot pattern-match +on its argument \lstinline!f! to make a decision about returning +a \lstinline!Left! or a \lstinline!Right!. So, \lstinline!bad5! +must hard-code that decision and either always return a value of type +$(A\rightarrow\bbnum 0)+\bbnum 0^{:B}$, or always return a value +of type $\bbnum 0^{:A\rightarrow\bbnum 0}+B$. A value of type $B$ +cannot be computed from scratch because the type $B$ is unknown. +The only way of getting a value of type $B$ would be by computing +\lstinline!f(x)! for some \lstinline!x: A!, but no values of type +$A$ are available. The remaining possibility is to return a value +of type $A\rightarrow\bbnum 0$. But the type $A\rightarrow\bbnum 0$ +is void unless $A=\bbnum 0$ (see Example~\ref{subsec:ch-Example-type-identity-A-0}). +As the type $A$ is unknown, we cannot write code that works in the +same way for all types $A$ and produces a value of type $A\rightarrow\bbnum 0$. +So, the function \lstinline!bad5! cannot be implemented via fully +parametric code. $\square$ + +Nevertheless, 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}) also hold in Boolean logic. To verify that a formula is true in Boolean logic, it is sufficient @@ -4998,25 +5224,32 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs Since each proof rule of the constructive logic is translated into a true formula in Boolean logic, it follows that a proof tree in the constructive logic will be translated into a tree of Boolean formulas -that have value $True$ for each axiom or proof rule. The result is -that any constructive proof for a sequent such as $\emptyset\vdash f(\alpha,\beta,\gamma)$ -is translated into a chain of Boolean implications that look like -this: +that have value $True$ for each axiom or proof rule. So, a proof +tree for a sequent such as $\emptyset\vdash f(\alpha,\beta,\gamma)$ +is translated into a tree of Boolean implications that look like this: \[ -True=(...)\Rightarrow(...)\Rightarrow...\Rightarrow f(\alpha,\beta,\gamma)\quad. +True=(True)\Rightarrow(True)\Rightarrow...\Rightarrow f(\alpha,\beta,\gamma)\quad. \] -Since $\left(True\Rightarrow\alpha\right)=\alpha$, this chain proves -the Boolean formula $f(\alpha,\beta,\gamma)$. +Since $\left(True\Rightarrow x\right)=x$ for any $x$, the Boolean +formula $f(\alpha,\beta,\gamma)$ will be proved $True$. -For example, the proof tree shown in Figure~\ref{fig:Proof-of-the-sequent-example-2} -is translated into: +To see how this works in practice, consider the proof tree shown in +Figure~\ref{fig:Proof-of-the-sequent-example-2} (page~\pageref{fig:Proof-of-the-sequent-example-2}). +Each step in that proof is made via an axiom or via a derivation rule. +Denoting for brevity $\gamma\triangleq\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta$, +let us translate each of those axioms and rules into Boolean formulas +that (as we know) all have value $True$: \begin{align*} -{\color{greenunder}\text{axiom \textsf{``}use valuue\textsf{''}}:}\quad & True=\left(\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\neg\alpha\vee\alpha\right)\\ -{\color{greenunder}\text{rule \textsf{``}create function\textsf{''}}:}\quad & \quad\Rightarrow\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\left(\alpha\Rightarrow\alpha\right)\quad.\\ -{\color{greenunder}\text{axiom \textsf{``}use value\textsf{''}}:}\quad & True=\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\quad.\\ -{\color{greenunder}\text{rule \textsf{``}use function\textsf{''}}:}\quad & True\Rightarrow\left(\neg\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\vee\beta\right)\\ -{\color{greenunder}\text{rule \textsf{``}create function\textsf{''}}:}\quad & \quad\Rightarrow\left(\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\Rightarrow\beta\right)\quad. +{\color{greenunder}\text{\textsf{``}use value\textsf{''}}:}\quad & True=\left(\gamma\wedge\alpha\right)\Rightarrow\alpha\quad.\\ +{\color{greenunder}\text{\textsf{``}create function\textsf{''}}:}\quad & True=\gunderline{\left(\left(\gamma\wedge\alpha\right)\Rightarrow\alpha\right)}\Rightarrow\left(\gamma\Rightarrow\left(\alpha\Rightarrow\alpha\right)\right)\\ + & \quad\quad\quad=(True)\Rightarrow\left(\gamma\Rightarrow\left(\alpha\Rightarrow\alpha\right)\right)\quad.\\ +{\color{greenunder}\text{\textsf{``}use value\textsf{''}}:}\quad & True=\left(\gamma\Rightarrow\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\right)\quad.\\ +{\color{greenunder}\text{\textsf{``}use function\textsf{''}}:}\quad & True=\gunderline{(\gamma\Rightarrow(\alpha\Rightarrow\alpha))}\wedge\gunderline{\left(\gamma\Rightarrow\left(\left(\alpha\Rightarrow\alpha\right)\Rightarrow\beta\right)\right)}\Rightarrow\left(\gamma\Rightarrow\beta\right)\\ + & \quad\quad\quad=(True)\wedge(True)\Rightarrow\left(\gamma\Rightarrow\beta\right)\quad.\\ +{\color{greenunder}\text{\textsf{``}create function\textsf{''}}:}\quad & True=\gunderline{\left(\gamma\Rightarrow\beta\right)}\Rightarrow\left(\gamma\Rightarrow\beta\right)=(True)\Rightarrow\left(\gamma\Rightarrow\beta\right)\quad. \end{align*} +These Boolean implications ultimately show that $\gamma\Rightarrow\beta$ +is $True$. It is easier to check Boolean truth tables than to find a proof tree in constructive logic (or to establish that no proof tree exists). @@ -5034,7 +5267,7 @@ \subsection{Relationship between Boolean logic and constructive logic\label{subs \[ \forall\alpha.\,\alpha\quad,\quad\quad\forall(\alpha,\beta).\,\alpha\Rightarrow\beta\quad,\quad\quad\forall(\alpha,\beta).\,(\alpha\Rightarrow\beta)\Rightarrow\beta\quad. \] -These formulas are also \emph{not} true in the constructive logic. +These formulas are also not true in the constructive logic. \subsection{The constructive logic and the law of excluded middle} @@ -5055,28 +5288,31 @@ \subsection{The constructive logic and the law of excluded middle} 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 value}$\textsf{''} into the Boolean axiom $\neg\alpha\vee\alpha=True$. +axiom \textsf{``}$\text{use value}$\textsf{''} into the Boolean axiom $\neg\alpha\vee\alpha=True$. + The formula $\forall\alpha.\,\neg\alpha\vee\alpha=True$ is known as the \textbf{law of excluded middle}.\footnote{See \texttt{\href{https://en.wikipedia.org/wiki/Law_of_excluded_middle}{https://en.wikipedia.org/wiki/Law\_of\_excluded\_middle}}}\index{law of excluded middle} It is remarkable that the constructive logic \emph{does not have} the law of excluded middle. It is neither an axiom nor a derived theorem in constructive logic. -To see why, translate the constructive logic formula $\forall\alpha.\,\neg\alpha\vee\alpha=True$ +To see why, translate the constructive logic formula $\forall\alpha.\,\neg\alpha\vee\alpha$ into a type. The negation operation ($\neg\alpha$) is defined as the implication $\alpha\Rightarrow False$. So, the formula $\forall\alpha.\,\neg\alpha\vee\alpha$ corresponds to the type $\forall A.\,\left(A\rightarrow\bbnum 0\right)+A$. Can we compute a value of this type via fully parametric code? For that, we need to compute either a value of type $A\rightarrow\bbnum 0$ -or a value of type $A$. This decision needs to be made in advance -independently of $A$, because the code of a fully parametric function -must operate in the same way for all types. As we have seen in Example~\ref{subsec:ch-Example-type-identity-A-0}, -a value of type $A\rightarrow\bbnum 0$ exists if the type $A$ is -itself $\bbnum 0$. But we do not know in advance whether $A=\bbnum 0$. +or a value of type $A$. This decision needs to be made independently +of $A$, because the code of a fully parametric function must operate +in the same way for all types. We cannot compute a value of type $A$ +from scratch, as the type $A$ is unknown. So, the only remaining +possibility is to compute a value of type $A\rightarrow\bbnum 0$. +As we have seen in Example~\ref{subsec:ch-Example-type-identity-A-0}, +a value of type $A\rightarrow\bbnum 0$ exists only if the type $A$ +is 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$. For similar reasons, we cannot compute -a value of type $A$ either. +type $A\rightarrow\bbnum 0$. 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. @@ -5392,7 +5628,7 @@ \subsection{The constructive logic and the law of excluded middle} rules do they do an interesting thing actually each of these rules is either about something in the sequence on the left to the trans time or something in the sequence to the right of the transplant which -I here shown in blue so these are the interesting parts of the sequence +I here shown in red so these are the interesting parts of the sequence that are being worked on or transformed by the rule so here\textsf{'}s an example this rule is actually two rules the eyes the index so I is one or two another two rules just written for gravity like this with index @@ -5505,7 +5741,7 @@ \subsection{The constructive logic and the law of excluded middle} are no more expressions except these four atomic variables conjunctions disjunction and implications and so we have here enumerated all the possibilities for what could be to the left of the implication in -this premise which I have here shown in the blue in blue and so for +this premise which I have here shown in the red in red and so for each of these we do certain things replacing this sequence with one or more other sequence again it\textsf{'}s quite a lot of work to prove that these rules are equivalent to these and also that the new rules are @@ -5639,9 +5875,9 @@ \subsection{The constructive logic and the law of excluded middle} we need a function that takes argument of type A to B to C to D and returns a function of type tuple a B going to C to D so here\textsf{'}s the code we take a function f of type A to B to C to D we return a function -that takes a G of this type shown here in blue and return we need -to return a D so how do we get a deal we apply F to a function of -type A to B to C so we create that function out of G X of type a going +that takes a G of this type shown here in red and return we need to +return a D so how do we get a deal we apply F to a function of type +A to B to C so we create that function out of G X of type a going to Y of type B going to G of x1 so this is a function of type A to B to C which is the argument of F as required and the result is of type D so that is what we write so this kind of code is the proof diff --git a/sofp-src/tex/sofp-disjunctions.tex b/sofp-src/tex/sofp-disjunctions.tex index 951fb7e83..a5aaa0d3a 100644 --- a/sofp-src/tex/sofp-disjunctions.tex +++ b/sofp-src/tex/sofp-disjunctions.tex @@ -173,8 +173,8 @@ \subsection{Case classes with type parameters} in addition to the size and color, an \textsf{``}extended sock\textsf{''} holds another value. We could define several specialized case classes: \begin{lstlisting} -case class MySock_Int(size: Double, color: String, value: Int) -case class MySock_Boolean(size: Double, color: String, value: Boolean) +case class MySockInt(size: Double, color: String, value: Int) +case class MySockBoolean(size: Double, color: String, value: Boolean) \end{lstlisting} but it is better to define a single parameterized case class: \begin{lstlisting} @@ -206,14 +206,14 @@ \subsection{Case classes with type parameters} a sock of type \lstinline!MySockX[A]! fits the author\textsf{'}s foot can be written as: \begin{lstlisting} -def fits[A](sock: MySockX[A]): Boolean = (sock.size >= 10.5 && sock.size <= 11.0) +def fits[A](sock: MySockX[A]): Boolean = sock.size >= 10.5 && sock.size <= 11 \end{lstlisting} This function is defined for all types \lstinline!A! at once, because its code works in the same way regardless of what \lstinline!A! is. Scala will set the type parameter \lstinline!A! automatically when we apply \lstinline!fits! to an argument: \begin{lstlisting} -scala> fits(MySockX(10.5, "blue", List(1, 2, 3))) // Type parameter A = List[Int]. +scala> fits(MySockX(10.5, "blue", List(1, 2, 3))) // Using MySockX[List[Int]]. res0: Boolean = true \end{lstlisting} This code forces the type parameter \lstinline!A! to be \lstinline!List[Int]!, @@ -342,7 +342,7 @@ \subsection{Pattern matching for case classes} \item \lstinline!case! expression: \lstinline[mathescape=true]!case $pattern$ => ...! \end{itemize} In both situations, case classes can be used as patterns. The following -code is an example of a destructuring definition: +code is an example of a destructuring definition with case classes: \begin{lstlisting} case class MySock(size: Double, color: String) case class BagOfSocks(sock: MySock, count: Int) @@ -477,7 +477,7 @@ \subsection{Motivation and first examples\label{subsec:Disjunctive-Motivation-an In the definition of \lstinline!SearchResult!, we have two cases: \begin{lstlisting} sealed trait SearchResult -final case class Index(i: Int) extends SearchResult +final case class Index(x: Int) extends SearchResult final case class NotFound() extends SearchResult \end{lstlisting} The definition of the \lstinline!Result! type is parameterized, so @@ -516,12 +516,11 @@ \subsection{Examples: Pattern matching for disjunctive types\index{examples (wit x: RootsOfQ = OneRoot(2.0) \end{lstlisting} -How can we use a given value, say, \lstinline!x:RootsOfQ!? The main -tool for working with values of disjunctive types is pattern matching. -In Chapter~\ref{chap:2-Mathematical-induction}, we used pattern -matching with syntax such as \lstinline!{ case (x, y) => ... }!. +How can we use a given value, say, \lstinline!x: RootsOfQ!? Disjunctive +types fit well with pattern matching. In Chapter~\ref{chap:2-Mathematical-induction}, +we used pattern matching with syntax such as \lstinline!{ case (x, y) => ... }!. To use pattern matching with disjunctive types, we write \emph{several} -\lstinline!case! patterns because we need to match several possible +\lstinline!case! patterns because we need to detect several possible cases of the disjunctive type: \begin{lstlisting} def print(r: RootsOfQ): String = r match { @@ -635,12 +634,12 @@ \subsubsection{Example \label{subsec:disj-Example-rootsofq-1}\ref{subsec:disj-Ex } \end{lstlisting} This code depends on some features of Scala syntax. We can use the -partial function \lstinline!{ case QEqu(b, c) => ... }! directly +function expression \lstinline!{ case QEqu(b, c) => ... }! directly as the argument of \lstinline!map!, destructuring \lstinline!QEqu! at the same time. The \lstinline!if!/\lstinline!else! expression is replaced by an \textsf{``}embedded\textsf{''}\index{embedded if@embedded \texttt{if}} -\lstinline!if! within the \lstinline!case! expression, which is -easier to read. +\lstinline!if! within a \lstinline!case! expression, which is easier +to read. Test the final code: \begin{lstlisting} @@ -755,8 +754,9 @@ \subsubsection{Example \label{subsec:disj-Example-resultA}\ref{subsec:disj-Examp } \end{lstlisting} This code illustrates nested patterns that match the tuple \lstinline!(rx, ry)! -against various possibilities. In this way, the code is clearer than -code written with nested \lstinline!if!/\lstinline!else! expressions. +against various possibilities. When written in this way, the code +is clearer than code written with nested \lstinline!if!/\lstinline!else! +expressions. Implementing the multiplication operation results in almost the same code: @@ -780,9 +780,10 @@ \subsubsection{Example \label{subsec:disj-Example-resultA}\ref{subsec:disj-Examp \end{lstlisting} Now we can easily \textsf{``}map\textsf{''} any binary operation on integers to a binary operation on \lstinline!Result[Int]!, assuming that the operation -never generates an error: +itself never generates an error: \begin{lstlisting} -def sub(rx: Result[Int], ry: Result[Int]): Result[Int] = map2(rx, ry){ (x, y) => x - y } +def sub(rx: Result[Int], ry: Result[Int]): Result[Int] = + map2(rx, ry) { (x, y) => x - y } \end{lstlisting} Custom code is still needed for operations that \emph{may} generate errors: @@ -803,10 +804,9 @@ \subsubsection{Example \label{subsec:disj-Example-resultA}\ref{subsec:disj-Examp scala> div(add(Value(1), Value(2)), Value(0)) res11: Result[Int] = Error(error: 3 / 0) \end{lstlisting} -Indeed, all further computations are abandoned once an error occurs. -An error message shows only the immediate calculation that generated -the error. For instance, the error message for $20+1/0$ never mentions -$20$: +Let us check that all further computations are abandoned once an error +occurs. Indeed, the following example shows that the error message +for $20+1/0$ never mentions $20$: \begin{lstlisting} scala> add(Value(20), div(Value(1), Value(0))) res12: Result[Int] = Error(error: 1 / 0) @@ -820,7 +820,8 @@ \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. +\lstinline!Either!, and \lstinline!Try!. These types are used often +in Scala programs. \paragraph{The \texttt{Option} type} @@ -856,10 +857,9 @@ \subsection{\label{subsec:Standard-disjunctive-types:}Standard disjunctive types In that implementation, the empty option \lstinline!None[T]()! has a type parameter. -Several consequences follow from the Scala library\textsf{'}s decision to define -\lstinline!None! without a type parameter. One consequence is that -\lstinline!None! can be reused as a value of type \lstinline!Option[A]! -for any type \lstinline!A!: +The Scala library\textsf{'}s decision to define \lstinline!None! without a +type parameter means that \lstinline!None! can be reused as a value +of type \lstinline!Option[A]! for any type \lstinline!A!: \begin{lstlisting} scala> val y: Option[Int] = None y: Option[Int] = None @@ -979,16 +979,17 @@ \subsubsection{Example \label{subsec:Disjunctive-Example-option-1}\ref{subsec:Di \subsubsection{Example \label{subsec:Disjunction-Example-Option-flatMap}\ref{subsec:Disjunction-Example-Option-flatMap}} Given a phone number as \lstinline!Option[Long]!, extract the country -code if it is present. (Assume that the country code is any digits -in front of the $10$-digit number; for the phone number $18004151212$, -the country code is $1$.) The result must be again of type \lstinline!Option[Long]!. +code if it is present. The result must be again of type \lstinline!Option[Long]!. +Assume that the country code is the digits in front of a $10$-digit +phone number; for the phone number $18004151212$, the country code +is $1$. \subparagraph{Solution} If the phone number is a positive integer $n$, we may compute the country code simply as \lstinline!n / 10000000000L!. However, if the result of that division is zero, we should return an empty \lstinline!Option! -(i.e.~the value \lstinline!None!) rather than \lstinline!0!: +(i.e., the value \lstinline!None!) rather than \lstinline!0!: \begin{lstlisting} def countryCode(phone: Option[Long]): Option[Long] = phone match { case None => None @@ -1072,7 +1073,7 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s 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. +for sequences, as well as \lstinline!get! for dictionaries. The \lstinline!find! method returns the first element satisfying a predicate: @@ -1117,7 +1118,7 @@ \subsubsection{Example \label{subsec:Disjunction-Example-Option-getOrElse}\ref{s res7: Option[String] = None \end{lstlisting} The \lstinline!get! method is a safe by-key access to dictionaries, -unlike the direct access that may fail: +unlike the direct access that may fail with an exception: \begin{lstlisting} scala> Map(10 -> "a", 20 -> "b")(10) res8: String = a @@ -1381,14 +1382,13 @@ \subsection{\label{subsec:The-recursive-type-List}The recursive type \texttt{Lis case class for \emph{each} possible length. Instead, we define the type \lstinline!List[A]! via mathematical induction on the length of the list: - -$\bullet$ Base case: empty list, \lstinline!case class List0[A]()!. - -$\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, -we could define \lstinline!List!$_{n}=\,$\lstinline!(A, List!$_{n-1}$\lstinline!)!. - +\begin{itemize} +\item Base case: empty list, \lstinline!case class List0[A]()!. +\item 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, we could define +\lstinline!List!$_{n}=\,$\lstinline!(A, List!$_{n-1}$\lstinline!)!. +\end{itemize} Let us try to write this inductive definition as code: \begin{lstlisting} sealed trait ListI[A] // Inductive definition of a list. @@ -1449,8 +1449,8 @@ \subsection{\label{subsec:The-recursive-type-List}The recursive type \texttt{Lis } \end{lstlisting} -The Scala library defines the type \lstinline!List[A]! in a slightly -different way: +The Scala library defines the type \lstinline!List[A]! in a different +way: \begin{lstlisting} sealed trait List[A] final case object Nil extends List[Nothing] @@ -1517,16 +1517,14 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l \begin{lstlisting} def map[A, B](xs: List[A])(f: A => B): List[B] = xs match { case Nil => Nil - case head :: tail => f(head) :: map(tail)(f) // Not tail-recursive. + case head :: tail => f(head) :: map(tail)(f) \end{lstlisting} While this implementation is straightforward and concise, it is not tail-recursive. This will be a problem for large enough lists. -Instead of implementing the often-used methods such as \lstinline!map! -or \lstinline!filter! one by one, let us implement \lstinline!foldLeft!, -because most of the other methods can be expressed via \lstinline!foldLeft!. - -The required type signature is: +To resolve this issue, let us implement a tail-recursive \lstinline!foldLeft!, +because many methods can be expressed via \lstinline!foldLeft!. The +required type signature is: \begin{lstlisting} def foldLeft[A, R](xs: List[A])(init: R)(f: (R, A) => R): R = ??? \end{lstlisting} @@ -1538,7 +1536,7 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l ... \end{lstlisting} The inductive step for \lstinline!foldLeft! says that, given the -values \lstinline!head:A! and \lstinline!tail:List[A]!, we need +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 to the tail of the list once we have the updated accumulator value: @@ -1566,11 +1564,10 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l scala> reverse(List(1, 2, 3)) res0: List[Int] = List(3, 2, 1) \end{lstlisting} -Without the explicit type annotation \lstinline!Nil:List[A]!, the -Scala compiler will decide that \lstinline!Nil! has type \lstinline!List[Nothing]!, -and the types will not match later in the code. In Scala, one often -finds that the initial value for \lstinline!foldLeft! needs an explicit -type annotation. +Without the explicit type annotation (\lstinline!Nil: List[A]!), +the Scala compiler will decide that \lstinline!Nil! has type \lstinline!List[Nothing]!, +and the types will not match later in the code. In Scala, the initial +value for \lstinline!foldLeft! often needs an explicit type annotation. The \lstinline!reverse! function can be used to obtain a tail-recursive implementation of \lstinline!map! for \lstinline!List!. The idea @@ -1590,7 +1587,7 @@ \subsection{Tail recursion with \texttt{List}\label{subsec:Tail-recursion-with-l \end{lstlisting} This achieves stack safety at the cost of traversing the list twice. (This code is shown only as an example. The Scala library implements -\lstinline!List!\textsf{'}s \lstinline!map! using low-level tricks for better +\lstinline!List!\textsf{'}s \lstinline!map! using mutable variables to improve performance.) \subsubsection{Example \label{subsec:Disjunctive-Example-non-empty-list-foldLeft}\ref{subsec:Disjunctive-Example-non-empty-list-foldLeft}\index{examples (with code)}} @@ -1723,9 +1720,9 @@ \subsubsection{Exercise \label{subsec:Disjunctive-Exercise-map-for-NEL}\ref{subs Implement a \lstinline!map! function for the type \lstinline!NEL!. Type signature and a sample test: \begin{lstlisting} -def map[A,B](xs: NEL[A])(f: A => B): NEL[B] = ??? +def mapNEL[A,B](xs: NEL[A])(f: A => B): NEL[B] = ??? -scala> map[Int, Int](toNEL(10, List(20, 30)))(_ + 5) +scala> mapNEL[Int, Int](toNEL(10, List(20, 30)))(_ + 5) res7: NEL[Int] = More(15,More(25,Last(35))) \end{lstlisting} @@ -1741,6 +1738,17 @@ \subsubsection{Exercise \label{subsec:Disjunctive-Exercise-non-empty-list-2}\ref \end{lstlisting} +\subsubsection{Exercise \label{subsec:Disjunctive-Exercise-non-empty-list-2-1}\ref{subsec:Disjunctive-Exercise-non-empty-list-2-1}} + +Implement \lstinline!flatten! for non-empty lists: +\begin{lstlisting} +def flattenNEL[A](xs: NEL[Nel[A]]): NEL[A] = ??? + +scala> flattenNEL(More(More(1, Last(2)), More(More(3, Last(4)), Last(More(5, Last(6)))))) +res9: NEL[Int] = More(1,More(2,More(3,More(4,More(5,Last(6)))))) +\end{lstlisting} + + \subsection{Binary trees\label{subsec:Binary-trees}} We will consider four kinds of trees defined as recursive disjunctive @@ -1942,7 +1950,7 @@ \subsubsection{Example \label{subsec:Disjunctive-Example-map-regular-tree}\ref{s case Branch(xs) => ??? } \end{lstlisting} -In the inductive step, we are given a previous tree value \lstinline!xs:PTree[(A, A)]!. +In the inductive step, we are given a previous tree value \lstinline!xs: PTree[(A, A)]!. It is clear that we need to apply \lstinline!map! recursively to \lstinline!xs!. Let us try: \begin{lstlisting} @@ -2225,6 +2233,8 @@ \subsubsection{Example \label{subsec:disj-Example-rootsofq-2}\ref{subsec:disj-Ex Define a disjunctive type that describes the real roots of the equation $ax^{2}+bx+c=0$, where $a$, $b$, $c$ are arbitrary real numbers. +Write a function that returns a value of that type and solves a given +equation of the form $ax^{2}+bx+c=0$. \subparagraph{Solution} @@ -2252,6 +2262,34 @@ \subsubsection{Example \label{subsec:disj-Example-rootsofq-2}\ref{subsec:disj-Ex or if we reused \lstinline!NoRoots()! for all three different no-roots cases. +To solve a given equation, we need to decide which part of the disjunctive +type to return. The code is: +\begin{lstlisting} +def solveQ2(a: Double, b: Double, c: Double) : RootsOfQ2 = (a, b, c) match { + case (0.0, 0.0, 0.0) => AllRoots() + case (0.0, 0.0, _) => NoRealRoots() + case (0.0, _, _) => Linear(-c / b) + case _ => // We match here only if `a` is nonzero. + val d = b * b - 4 * a * c + val p = - b / (2.0 * a) + if (d < 0.0) NoRealRoots() + else if (d == 0.0) OneRootQ(p) + else { + val s = math.sqrt(d) / (2.0 * a) + TwoRootsQ(p - s, p + s) + } +} +\end{lstlisting} +Let us test this code with various input parameters: +\begin{lstlisting} +scala> solveQ2(1, 1, 1) +res0: RootsOfQ2 = NoRealRoots() + +scala> solveQ2(1, 0, -4) +res1: RootsOfQ2 = TwoRootsQ(-2.0, 2.0) +\end{lstlisting} + + \subsubsection{Example \label{subsec:Example-disjunctive-3}\ref{subsec:Example-disjunctive-3}} Define a function \lstinline!rootAverage! that computes the average @@ -2262,7 +2300,8 @@ \subsubsection{Example \label{subsec:Example-disjunctive-3}\ref{subsec:Example-d \begin{lstlisting} val rootAverage: RootsOfQ2 => Option[Double] = ??? \end{lstlisting} -The function should return \lstinline!None! if the average is undefined. +Return \lstinline!None! if the average is undefined (no roots or +all values are roots). \subparagraph{Solution} @@ -2400,7 +2439,7 @@ \subsubsection{Example \label{subsec:Example-disjunctive-5}\ref{subsec:Example-d It remains to figure out what expressions to write in each case. In the case \lstinline!Left(a) => ???!, we have a value of type \lstinline!A!, and we need to compute a value of type \lstinline!Either[A, Option[B]]!. -We execute the same argument as before: The return value must be \lstinline!Left(x)! +We use 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)! @@ -2408,17 +2447,17 @@ \subsubsection{Example \label{subsec:Example-disjunctive-5}\ref{subsec:Example-d the code is: \begin{lstlisting}[numbers=left] def f1[A, B]: Option[Either[A, B]] => Either[A, Option[B]] = { - case None => Right(None) // No other choice here. + case None => Right(None) // No other choice here. case Some(eab) => eab match { - case Left(a) => Left(a) // Could return Right(None) here. + case Left(a) => Left(a) // Could return Right(None) here. case Right(b) => ??? } } \end{lstlisting} -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]]!. +Should we 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!, which loses information.\index{information loss} +ignore the given value \lstinline!a: A!, losing 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)! @@ -2532,11 +2571,18 @@ \subsubsection{Exercise \label{subsec:Exercise-disjunctive-3}\ref{subsec:Exercis \subsubsection{Exercise \label{subsec:Exercise-disjunctive-4}\ref{subsec:Exercise-disjunctive-4}} Given a \lstinline!Seq[(Double, Double)]! containing pairs $\left(a,b\right)$ -of the coefficients of $ax+b=0$, compute a \lstinline!Seq[Double]! +of coefficients of $ax+b=0$, compute a \lstinline!Seq[Double]! containing the roots of that equation when a unique root exists. Use the type \lstinline!RootOfLinear! and the function \lstinline!solve1! defined in Exercise~\ref{subsec:Exercise-disjunctive-3}. +\subsubsection{Exercise \label{subsec:Exercise-disjunctive-4-1}\ref{subsec:Exercise-disjunctive-4-1}} + +Use the function \lstinline!rootAverage! from Example~\ref{subsec:Example-disjunctive-3} +to compute the average root of $100$ equations whose coefficients +($a$, $b$, $c$) are chosen randomly between $0$ and $1$. Ignore +equations for which the average root value is undefined. + \subsubsection{Exercise \label{subsec:Exercise-disjunctive-4-1-1}\ref{subsec:Exercise-disjunctive-4-1-1}} The case class \lstinline!Subscriber! was defined in Example~\ref{subsec:Disjunctive-Example-option-1}. @@ -2550,16 +2596,18 @@ \subsubsection{Exercise \label{subsec:Exercise-disjunctive-Procedure-DSL}\ref{su of type \lstinline!Unit => Unit!. An example of a procedure is \lstinline!{ _ => println("hello") }!. Define a disjunctive type \lstinline!Proc! for an abstract syntax tree representing three operations on procedures: 1) \lstinline!Func[A](f)!, -create a procedure from a function \lstinline!f! of type \lstinline!Unit => A!, +to create a procedure from a function \lstinline!f! of type \lstinline!Unit => A!, where \lstinline!A! is a type parameter. (Note that the type \lstinline!Proc! does not have any type parameters.) 2) \lstinline!Sequ(p1, p2)!, -execute two procedures sequentially. 3) \lstinline!Para(p1, p2)!, -execute two procedures in parallel. Then implement a \textsf{``}runner\textsf{''} +to execute two procedures sequentially. 3) \lstinline!Para(p1, p2)!, +to execute two procedures in parallel. Then implement a \textsf{``}runner\textsf{''} that converts a \lstinline!Proc! into a \lstinline!Future[Unit]!, running the computations either sequentially or in parallel as appropriate. Test with this code: \begin{lstlisting} -sealed trait Proc; final case class Func[A](???) // And so on. +sealed trait Proc +final case class Func[A](???) extends Proc // And so on. + def runner: Proc => Future[Unit] = ??? val proc1: Proc = Func{_ => Thread.sleep(200); println("hello1")} val proc2: Proc = Func{_ => Thread.sleep(400); println("hello2")} @@ -2578,7 +2626,7 @@ \subsubsection{Exercise \label{subsec:Exercise-disjunctive-5}\ref{subsec:Exercis \begin{lstlisting} def f1[A, B]: Option[(A, B)] => (Option[A], Option[B]) = ??? def f2[A, B]: Either[A, B] => (Option[A], Option[B]) = ??? -def f3[A,B,C]: Either[A, Either[B,C]] => Either[Either[A,B], C] = ??? +def f3[A, B, C]: Either[A, Either[B, C]] => Either[Either[A, B], C] = ??? \end{lstlisting} @@ -2617,16 +2665,17 @@ \subsection{Disjunctive types as mathematical sets} \begin{lstlisting} def isDoubleRoot(r: RootsOfQ) = ... \end{lstlisting} -The type of the argument \lstinline!r:RootsOfQ! represents the mathematical -domain of the function, that is, the set of admissible values of the -argument \lstinline!r!. What kind of domain is that? The set of real -roots of a quadratic equation $x^{2}+bx+c=0$ can be empty, or it -can contain a single real number $x$, or a pair of real numbers $\left(x,y\right)$. -Geometrically, a number $x$ is pictured as a point on a line (a one-dimensional -space), and pair of numbers $\left(x,y\right)$ is pictured as a point -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 +The type \lstinline!RootsOfQ! represents the set of admissible values +of the argument \lstinline!r!, that is, the mathematical \textbf{domain} +of the function \lstinline!isDoubleRoot!. What kind of domain is +that? The set of real roots of a quadratic equation $x^{2}+bx+c=0$ +can be empty, or it can contain a single real number $x$, or a pair +of real numbers $\left(x,y\right)$. Geometrically, a number $x$ +is pictured as a point in a line (a one-dimensional space), and pair +of numbers $\left(x,y\right)$ is pictured as a point in a Cartesian +plane (a two-dimensional space). The no-roots case corresponds to +a zero-dimensional space, which can be pictured as a single point +(see Figure~\ref{fig:RootsOfQ-disjoint-domain}). The point, the 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$. @@ -2660,10 +2709,10 @@ \subsection{Disjunctive types as mathematical sets} 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 +In 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 +and \lstinline!TwoRoots!. To represent this mathematically, we need +to attach a distinct label to each part of the union. 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 $(\text{\texttt{OneRoot}},x)_{x\in\mathbb{R}^{1}}$. @@ -2674,7 +2723,7 @@ \subsection{Disjunctive types as mathematical sets} This is an ordinary union of mathematical sets, but each of the sets has a unique label, so no two values from different parts of the union could possibly be equal. This kind of set is called a \index{labeled union}\textbf{labeled -union} (it is also called tagged union or disjoint union\index{disjoint union!see \textsf{``}labeled union\textsf{''}}). +union} (also a tagged union or a disjoint union\index{disjoint union!see \textsf{``}labeled union\textsf{''}}). Each element of a labeled union is a pair of the form \lstinline!(label, data)!, where the label uniquely identifies the part of the union, and the data can have any chosen type such as $\mathbb{R}^{1}$. If we use @@ -2695,10 +2744,10 @@ \subsection{Disjunctive types as mathematical sets} we are required to represent not only the values of the roots but also the information \emph{about} the existence of the roots. The case with no real roots needs to be represented by some \emph{value} -of type \lstinline!RootsOfQ!. This value cannot be missing, which +of type \lstinline!RootsOfQ!. That value cannot be missing, which would happen if we used an empty set to represent the no-roots case. It is natural to use the named empty tuple \lstinline!NoRoots()! -to represent this case, just as we used a named $2$-tuple \lstinline!TwoRoots(x, y)! +to represent that case, just as we used a named $2$-tuple \lstinline!TwoRoots(x, y)! to represent the case of two roots. Consider the value $u$ used by the mathematical set $\left(\text{\texttt{NoRoots}},u\right)_{u\in\mathbb{R}^{0}}$. @@ -2706,21 +2755,22 @@ \subsection{Disjunctive types as mathematical sets} \emph{one} possible value of $u$. Similarly, the \lstinline!Unit! type in Scala has only one distinct value, written as \lstinline!()!. A case class with no parts, such as \lstinline!NoRoots!, has only -one distinct value, written as \lstinline!NoRoots()!. This Scala -value is fully analogous to the mathematical notation $\left(\text{\texttt{NoRoots}},u\right)_{u\in\mathbb{R}^{0}}$. +one distinct value, written as \lstinline!NoRoots()!. The Scala value +\lstinline!NoRoots()! is fully analogous to the mathematical notation +$\left(\text{\texttt{NoRoots}},u\right)_{u\in\mathbb{R}^{0}}$. 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, -this book calls them \textsf{``}named unit\textsf{''} types.\index{unit type!named} +for an added name. For instance, \lstinline!NoRoots()! can be regarded +as the \lstinline!Unit! value \lstinline!()! with name \lstinline!NoRoots!. +For this reason, this book calls them \textsf{``}named unit\textsf{''} types.\index{unit type!named} \subsection{Disjunctive types in other programming languages} Disjunctive types and pattern matching turns out to be one of the defining features of FP languages. Languages that were not designed -for functional programming do not support these features, while ML, -OCaml, Haskell, F\#, Scala, Swift, Elm, PureScript, and Rust support -disjunctive types and pattern matching as part of the language design. +for functional programming do not support these features, while OCaml, +Haskell, F\#, Scala, Swift, and Rust support disjunctive types and +pattern matching as part of the language design. It is remarkable that named tuple types (also called \textsf{``}structs\textsf{''} or \textsf{``}records\textsf{''}) are provided in almost every programming language, @@ -2780,7 +2830,7 @@ \subsection{Disjunctive types in other programming languages} in OCaml and Haskell is: \begin{lstlisting}[language=Caml] (* OCaml *) -type RootsOfQ = NoRoots | OneRoot of float | TwoRoots of float*float +type RootsOfQ = NoRoots | OneRoot of float | TwoRoots of float * float \end{lstlisting} \begin{lstlisting}[language=Haskell] -- Haskell diff --git a/sofp-src/tex/sofp-essay1.tex b/sofp-src/tex/sofp-essay1.tex index a666daa12..fb76f9322 100644 --- a/sofp-src/tex/sofp-essay1.tex +++ b/sofp-src/tex/sofp-essay1.tex @@ -52,10 +52,10 @@ expressions, and each type of data is required to match correctly during the computations. The type-checking process automatically prevents programmers from making many kinds of coding errors. In addition, -programming languages such as Scala and Haskell have a set of features -adapted to building powerful abstractions and domain-specific languages. -This power of abstraction is not accidental. Since mathematics is -the ultimate art of building abstractions, math-based functional programming +programming languages such as Scala and Haskell have features intended +for building powerful abstractions and domain-specific languages. +This power of abstraction is not accidental. Mathematics is the ultimate +art of building formal abstractions, and math-based functional programming languages capitalize on several millennia of mathematical experience. A prominent example of how mathematics informs the design of programming @@ -84,9 +84,9 @@ $B$\textsf{''}. In Scala, these composite types are \lstinline!Either[A, B]!, the tuple \lstinline!(A, B)!, and the function type \lstinline!A => B!. All modern functional languages such as OCaml, Haskell, Scala, F\#, -and Swift support these three type constructions and thus obey the -CH correspondence. Having a \emph{complete} logic in a language\textsf{'}s -type system enables declarative domain-driven code design.\footnote{\texttt{\href{https://fsharpforfunandprofit.com/ddd/}{https://fsharpforfunandprofit.com/ddd/}}} +Swift, and Rust support these type constructions and obey the CH correspondence. +Having a \emph{complete} logic in a language\textsf{'}s type system enables +declarative domain-driven code design.\footnote{\texttt{\href{https://fsharpforfunandprofit.com/ddd/}{https://fsharpforfunandprofit.com/ddd/}}} \begin{wrapfigure}{I}{0.5\columnwidth}% \begin{centering} @@ -114,10 +114,11 @@ \addsec{The power of abstraction} Early adopters of Scala, such as Netflix, LinkedIn, and Twitter, were -implementing what is now called \textsf{``}big data engineering\textsf{''}. The required -software needs to be highly concurrent, distributed, and resilient -to failure. Those software companies used Scala as their main implementation -language and reaped the benefits of functional programming. +implementing what was then called \textsf{``}big data engineering\textsf{''}. The +required software needs to be highly concurrent, distributed, and +resilient to failure. Those software companies used Scala as their +main implementation language and reaped the benefits of functional +programming. What makes Scala suitable for big data tasks? The only reliable way of managing massively concurrent code is to use sufficiently high-level diff --git a/sofp-src/tex/sofp-essay3.tex b/sofp-src/tex/sofp-essay3.tex index 482dcc6dd..63c6a3c45 100644 --- a/sofp-src/tex/sofp-essay3.tex +++ b/sofp-src/tex/sofp-essay3.tex @@ -365,7 +365,7 @@ To each programming language of that kind, there corresponds\footnote{Academically minded computer scientists say that this definition of a \textsf{``}types/functions\textsf{''} category is insufficiently rigorous. See the -discussion in \texttt{\href{https://cstheory.stackexchange.com/questions/53389}{https://cstheory.stackexchange.com/questions/53389}}} a \textsf{``}types/functions\textsf{''} category: +discussion in \texttt{\href{https://math.andrej.com/2016/08/06/hask-is-not-a-category/}{https://math.andrej.com/2016/08/06/hask-is-not-a-category/}}} a \textsf{``}types/functions\textsf{''} category: \begin{itemize} \item The objects of the category are all the data types supported by the language (including user-defined data types). As an example, for Scala diff --git a/sofp-src/tex/sofp-filterable.tex b/sofp-src/tex/sofp-filterable.tex index 3de7a1f57..129b9b3b8 100644 --- a/sofp-src/tex/sofp-filterable.tex +++ b/sofp-src/tex/sofp-filterable.tex @@ -1316,7 +1316,7 @@ \subsubsection{Statement \label{subsec:Statement-filter-to-deflate-equivalence}\ \end{array}\quad.\label{eq:def-of-get-option} \end{align} These methods are fully parametric since their code uses only the -eight standard code constructions (see Section~\ref{subsec:The-rules-of-proof}). +eight standard code constructions (see Section~\ref{subsec:Short-notation-for-eight-code-constructions}). The function $\psi$ is also fully parametric because we can implement using the type \lstinline!Option[Unit]!: \begin{lstlisting}[mathescape=true] @@ -4490,7 +4490,7 @@ \subsection{Naturality laws and natural transformations\label{subsec:Naturality- It turns out that the naturality law of a natural transformation $t:F^{A}\rightarrow G^{A}$ will \emph{always hold} if the code of the function $t$ is fully parametric. More precisely, naturality holds if the code of $t$ is -a combination of the eight standard code constructions (shown in Section~\ref{subsec:The-rules-of-proof}) +a combination of the eight standard code constructions (shown in Section~\ref{subsec:Short-notation-for-eight-code-constructions}) together with recursion. This is a consequence of the \textsf{``}parametricity theorem\textsf{''}\index{parametricity theorem}, which is beyond the scope of this chapter.\footnote{Formulations and proofs sufficient for the scope of this book are diff --git a/sofp-src/tex/sofp-free-type.tex b/sofp-src/tex/sofp-free-type.tex index 0b0311fe9..69cd37989 100644 --- a/sofp-src/tex/sofp-free-type.tex +++ b/sofp-src/tex/sofp-free-type.tex @@ -202,7 +202,7 @@ \subsection{Stage 2: implementing type safety in the DSLs} type mismatch; found : Val required: PrgFile[java.nio.file.Path] -val res4 = runFile(Read(Read(Val("file")))) +res4 = runFile(Read(Read(Val("file")))) ^ Compilation Failed \end{lstlisting} @@ -220,7 +220,7 @@ \subsection{Stage 2: implementing type safety in the DSLs} val prgComplex3: PrgComplex = Rotate(prgComplex1, Val(Complex(0, 1))) // Forgot Phase()! scala> runComplex(prgComplex3) // The result is incorrect, but there is no error message! -val res5: Complex = Complex(11.0, -2.0) +res5: Complex = Complex(11.0, -2.0) \end{lstlisting} To achieve type safety, we add a type parameter to \lstinline!PrgComplex!. diff --git a/sofp-src/tex/sofp-higher-order-functions.tex b/sofp-src/tex/sofp-higher-order-functions.tex index 2ee9b310c..145b7263a 100644 --- a/sofp-src/tex/sofp-higher-order-functions.tex +++ b/sofp-src/tex/sofp-higher-order-functions.tex @@ -75,25 +75,46 @@ \subsection{Motivation and first examples} { val prefix = "WARN"; (message => s"$prefix: $message") } \end{lstlisting} Whenever a new function is created using \lstinline!logWith(prefix)!, -the (immutable) value of \lstinline!prefix! is stored within the -body of the newly created function. This is a general feature of nameless -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{''}. 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} -val f: (Int => Int) = { // Parentheses around (Int => Int) are optional. +the (immutable) reference to \lstinline!prefix! is stored within +the body of the newly created function. This is a general feature +of nameless functions: the function\textsf{'}s body captures references to +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{''}. + +However, nameless functions do not \emph{copy} values from outer scopes. +Those values are captured by reference. This distinction is important +in Scala as it supports mutable values (as well as classes that encapsulate +mutable values). + +Here is an example of a function body capturing references to variables: +\begin{lstlisting} +var c: Int = 10 // Mutable variable! +val f: Int => Int = { val p = 10 val q = 20 - x => p + q * x + x => p + q * x + c } \end{lstlisting} -The body of the function \lstinline!f! is equivalent to \lstinline!{ x => 10 + 20 * x }! -because the values \lstinline!p = 10! and \lstinline!q = 20! are -captured. +The body of the function \lstinline!f! is equivalent to \lstinline!{ x => 10 + 20 * x + c }!. +The values \lstinline!p = 10! and \lstinline!q = 20! are local constants +captured in the function\textsf{'}s body. However, the value \lstinline!c! +is captured by reference. If we change \lstinline!c!, the behavior +of \lstinline!f! will also change: +\begin{lstlisting} +scala> f(10) +res0: Int = 220 + +scala> c = 1000 +c: Int = 1000 + +scala> f(10) +res1: Int = 1210 +\end{lstlisting} +A captured reference to a mutable external variable \lstinline!c! +makes the function \lstinline!f! itself mutable, even though \lstinline!f! +was defined as a \lstinline!val!. We will avoid such code in this +book and instead use immutable values. \subsection{Curried and uncurried functions} @@ -155,7 +176,7 @@ \subsection{Curried and uncurried functions} of curried arguments, and \lstinline!D! is the final result type. It takes time to get used to reading this kind of syntax. -In Scala, functions defined with multiple argument groups (enclosed +In Scala, functions defined with multiple argument lists (enclosed in multiple pairs of parentheses) are curried functions. We have seen examples of curried functions before: \begin{lstlisting} @@ -274,12 +295,11 @@ \subsection{Equivalence of curried and uncurried functions} res3: Int = 16 \end{lstlisting} (The type annotation \lstinline!Int => Int! is required in line 1.) -This code creates a function \lstinline!r2! by partially applying -\lstinline!f2! to the first argument but not to the second. Other -than that, \lstinline!r2! is the same function as \lstinline!r1! -defined above; i.e., \lstinline!r2! returns the same values for the -same arguments as \lstinline!r1!. A more verbose syntax for a partial -application is: +This code creates a function \lstinline!r2! by applying \lstinline!f2! +to the first argument but not to the second. Then \lstinline!r2! +is the same function as \lstinline!r1! defined above; i.e., \lstinline!r2! +returns the same values for the same arguments as \lstinline!r1!. +A more verbose syntax for a partial application is: \begin{lstlisting} scala> val r3: Int => Int = { x => f2(20, x) } // Same as r2 above. r3: Int => Int = @@ -290,10 +310,11 @@ \subsection{Equivalence of curried and uncurried functions} We can see that a curried function, such as \lstinline!f1!, is better adapted for partial application than \lstinline!f2!, because the -syntax is shorter. However, the types of functions \lstinline!f1! +syntax is shorter. However, the \emph{types} of functions \lstinline!f1! and \lstinline!f2! are\textbf{ equivalent}\index{type equivalence}: -for any \lstinline!f1! we can reconstruct \lstinline!f2! and vice -versa, without loss of information: +for any \lstinline!f1! of type \lstinline!Int => Int => Int! we +can reconstruct \lstinline!f2! of type \lstinline!(Int, Int) => Int! +and vice versa, without loss of information: \begin{lstlisting} def f2new(x: Int, y: Int): Int = f1(x)(y) // f2new is equal to f2 def f1new: Int => Int => Int = { x => y => f2(x, y) } // f1new is equal to f1 @@ -303,7 +324,10 @@ \subsection{Equivalence of curried and uncurried functions} computes the same results as \lstinline!f2!. The equivalence of the functions \lstinline!f1! and \lstinline!f2! is not \emph{equality} \textemdash{} these functions are \emph{different}; but each of them -can be reconstructed from the other. +can be reconstructed from the other. The one-to-one correspondence +between all functions of type \lstinline!Int => Int => Int! and all +functions of type \lstinline!(Int, Int) => Int! is what we call the +\textsf{``}equivalence of types\textsf{''}. More generally, a curried function has a type signature of the form \lstinline!A => B => C => ... => R => S!, where \lstinline!A!, \lstinline!B!, @@ -432,10 +456,10 @@ \section{Fully parametric functions\label{sec:Fully-parametric-functions}} } \end{lstlisting} -Typically, a fully parametric function has all its arguments typed -with type parameters or with some combinations of type parameters, -i.e., \textbf{type expressions}\index{type expression} such as \lstinline!(A, B)! -or \lstinline!X => Either[X, Y]!. +A fully parametric function has all its arguments typed with type +parameters or with some combinations of type parameters, i.e., \textbf{type +expressions}\index{type expression} such as \lstinline!(A, B)! or +\lstinline!X => Either[X, Y]!. The \lstinline!swap! operation for pairs is already defined in the Scala library: @@ -552,7 +576,7 @@ \subsection{Function composition\label{subsec:Examples-of-fully-parametric}} parametric functions do not use values of specific types such as \lstinline!Int! or \lstinline!String!. -Functions with type parameters are sometimes called \textsf{``}generic\index{generic functions}\textsf{''}. +Functions with type parameters are often called \textsf{``}generic\index{generic functions}\textsf{''}. This book uses the term \textsf{``}\index{fully parametric!function}\textbf{fully parametric}\textsf{''} to designate a certain restricted kind of generic functions. @@ -562,7 +586,7 @@ \subsection{Laws of function composition\label{subsec:Laws-of-function-compositi 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]!) +the composition of any function $f$ with an identity function (\lstinline!identity[A]!) will give again the function $f$. \item The \textbf{associativity law}\index{associativity law!of function composition}: the consecutive composition of three functions $f$, $g$, $h$ does @@ -580,8 +604,8 @@ \subsection{Laws of function composition\label{subsec:Laws-of-function-compositi In both cases, the result must be equal to the function $f$. The resulting two laws are: \begin{align*} -{\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. +{\color{greenunder}\text{left identity law of function composition}:}\quad & \text{id}\bef f=f\quad,\\ +{\color{greenunder}\text{right identity law of function composition}:}\quad & f\bef\text{id}=f\quad. \end{align*} 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 @@ -631,7 +655,7 @@ \subsection{Laws of function composition\label{subsec:Laws-of-function-compositi takes an argument $x$ and applies $f$ to that argument. This is the same function as $f$. We say that $x\rightarrow f(x)$ is an \textbf{expanded form}\index{expanded form of a function} of the -same function $f$. +function $f$. We turn to the right identity law, $f\bef\text{id}=f$. Write out the left-hand side: @@ -817,7 +841,7 @@ \subsection{Example: A function that is \emph{not} fully parametric} are \textbf{symbolic} in the sense that we are manipulating symbols (such as $x$, $f$, $g$, $h$) without substituting any specific values for these symbols but only using some general rules and properties. -This is similar to symbolic calculations in mathematics, such as $\left(x-y\right)\left(x^{2}+xy+y^{2}\right)=x^{3}-y^{3}$. +This is similar to symbolic calculations in mathematics, such as $\left(x-y\right)(x^{2}+xy+y^{2})=x^{3}-y^{3}$. In the next section, we will get more experience with symbolic calculations relevant to functional programming. @@ -858,7 +882,7 @@ \subsection{Calculations with curried functions} 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: +which equals \lstinline!16!. Test in Scala: \begin{lstlisting} scala> ((x: Int) => (y: Int) => x - y)(20)(4) res1: Int = 16 @@ -867,10 +891,9 @@ \subsection{Calculations with curried functions} Applying a curried function such as \lstinline!x => y => z => expr(x,y,z)! to three curried arguments \lstinline!10!, \lstinline!20!, and \lstinline!30! means substituting \lstinline!x = 10!, \lstinline!y = 20!, and \lstinline!z = 30! -into the expression \lstinline!expr(x,y,z)!. In this way, we can -easily apply a curried function to any number of curried arguments. +into the expression \lstinline!expr(x,y,z)!. -This calculation is helped by the convention that \lstinline!f(g)(h)! +This calculation is made easier by the convention that \lstinline!f(g)(h)! means first applying \lstinline!f! to \lstinline!g! and then applying the result to \lstinline!h!. In other words, function application groups to the \emph{left}: \lstinline!f(g)(h) = (f(g))(h)!. It would @@ -886,8 +909,8 @@ \subsection{Calculations with curried functions} To make calculations shorter, we will write code in a mathematical notation rather than in the Scala syntax. Type annotations are written -with a colon in the superscript, for example: $x^{:\text{Int}}\rightarrow x+10$ -instead of the Scala expression \lstinline!((x: Int) => x + 10)!. +with a \emph{colon} in the superscript. For example, $x^{:\text{Int}}\rightarrow x+10$ +is the code notation corresponding to the Scala expression \lstinline!(x: Int) => x + 10!. The symbolic evaluation of the Scala code \lstinline!((x: Int) => (y: Int) => x - y)(20)(4)! can be written as: @@ -960,7 +983,7 @@ \subsection{Calculations with curried functions} scala> ((p: Int) => (z: Int) => z * p)(10) res4: Int => Int = -scala> ((p:I nt) => (z: Int) => z * p)(10)(4) +scala> ((p: Int) => (z: Int) => z * p)(10)(4) res5: Int = 40 \end{lstlisting} @@ -972,10 +995,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 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}) +The final result, $p\rightarrow p(2)$, cannot be simplified any more. + +The function $p\rightarrow p(2)$ applies \emph{its} argument ($p$) +to the value $2$. A possible value for $p$ is the function $x\rightarrow x+4$. +Let us apply expression~(\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)\\ @@ -1000,7 +1024,7 @@ \subsection{Calculations with curried functions} 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 of $f$\textsf{'}s argument is the same as the type of $p$, which is $\text{Int}\rightarrow\text{Int}$. -So $f$\textsf{'}s type must be $\left(\text{Int}\rightarrow\text{Int}\right)\rightarrow A$ +So, $f$\textsf{'}s type must be $\left(\text{Int}\rightarrow\text{Int}\right)\rightarrow A$ for some type $A$. Since in our example $f=\left(g\rightarrow g(2)\right)$, types match only if $g$ has type $\text{Int}\rightarrow\text{Int}$. But then $g(2)$ has type $\text{Int}$, and so we must have $A=\text{Int}$. @@ -1260,7 +1284,7 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-4}\ref{subsec:Exam of \lstinline!p[A]!, which is \lstinline!Int => A!, with some choice of \lstinline!A! and \lstinline!B!? A function type \lstinline!P => Q! matches \lstinline!X => Y! only if \lstinline!P = X! and \lstinline!Q = Y!. -So \lstinline!(Int => B) => B! can match \lstinline!Int => A! only +So, \lstinline!(Int => B) => B! can match \lstinline!Int => A! only if \lstinline!Int => B! matches \lstinline!Int! and if \lstinline!B = A!. But it is impossible for \lstinline!Int => B! to match \lstinline!Int!, no matter how we choose \lstinline!B!. @@ -1291,9 +1315,9 @@ \section{Summary} \hline {\small{}$f^{:A\rightarrow B}$} & {\small{}}\lstinline!f: A => B! & {\small{}a function of type }\lstinline!A => B!\tabularnewline \hline -{\small{}$x^{:\text{Int}}\rightarrow f(x)$} & {\small{}}\lstinline!{ x: Int => f(x) }! & {\small{}a nameless function with argument }\lstinline!x!\tabularnewline +{\small{}$x^{:\text{Int}}\rightarrow x+1$} & {\small{}}\lstinline!(x: Int) => x + 1! & {\small{}a nameless function of type }\lstinline!Int => Int!\tabularnewline \hline -{\small{}$f^{A,B}\triangleq...$} & {\small{}}\lstinline!def f[A, B] = ...! & {\small{}define a function with type parameters}\tabularnewline +{\small{}$f^{A,B}\triangleq...$} & {\small{}}\lstinline!def f[A, B] = ...! & {\small{}a function with type parameters}\tabularnewline \hline {\small{}$\text{id}^{A}$, also $\text{id}^{:A\rightarrow A}$} & {\small{}}\lstinline!identity[A]! & {\small{}the standard \textsf{``}identity\textsf{''} function}\tabularnewline \hline @@ -1348,7 +1372,7 @@ \subsubsection{Example \label{subsec:Example-hof-simple-1}\ref{subsec:Example-ho is unbounded and, if the condition \lstinline!cond! never becomes \lstinline!true!, the program will run out of memory (since \lstinline!Stream.iterate! keeps all computed values in memory) or the user will run out of patience. -So \lstinline!.find(cond)! can never return an empty \lstinline!Option! +So, \lstinline!_.find(cond)! can never return an empty \lstinline!Option! value. Of course, it is not satisfactory that the program crashes when the sequence does not converge. Exercise~\ref{subsec:Exercise-hof-simple-8} will implement a safer version of this function by limiting the allowed @@ -1359,7 +1383,7 @@ \subsubsection{Example \label{subsec:Example-hof-simple-1}\ref{subsec:Example-ho @tailrec def converge[X](f: X => X, x0: X, cond: X => Boolean): X = if (cond(x0)) x0 else converge(f, f(x0), cond) \end{lstlisting} -To test this code, compute an approximation to $\sqrt{q}$ by Newton\textsf{'}s +To test this code, compute an approximation to $\sqrt{q}\,$ by Newton\textsf{'}s method\index{Newton\textsf{'}s method} with the iteration function $f(x)=\frac{1}{2}\left(x+\frac{q}{x}\right)$. We iterate $f(x)$ starting with $x_{0}=q/2$ until a given precision is obtained: @@ -1370,7 +1394,7 @@ \subsubsection{Example \label{subsec:Example-hof-simple-1}\ref{subsec:Example-ho converge(iterate_sqrt, q / 2, cond) } \end{lstlisting} -Newton\textsf{'}s method for $\sqrt{q}$ is guaranteed to converge when $q\geq0$. +Newton\textsf{'}s method for $\sqrt{q}\,$ is guaranteed to converge when $q\geq0$. Test it: \begin{lstlisting} scala> approx_sqrt(25, 1.0e-8) @@ -1386,7 +1410,7 @@ \subsubsection{Example \label{subsec:Example-hof-simple-2}\ref{subsec:Example-ho \subparagraph{Solution} -Let us first write down the required type signature: the function +Let us first write down the required type signature. The function must take an integer argument \lstinline!x: Int!, and the return value must be a function of type \lstinline!Int => Int!: \begin{lstlisting} @@ -1527,7 +1551,7 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-5}\ref{subsec:Exam To match types in the expression \lstinline!q(q)!, we first assume arbitrary type parameters and write \lstinline!q[A, B](q[C, D])!. -We need to introduce new type parameters $C$, $D$ because these +We need to introduce new type parameters $C$, $D$ because those type parameters may need to be set differently from $A$, $B$ when we try to match the types in the expression \lstinline!q(q)!. @@ -1584,8 +1608,8 @@ \subsubsection{Example \label{subsec:Example-hof-derive-types-5}\ref{subsec:Exam \subsubsection{Example \label{subsec:Example-not-typeable}\ref{subsec:Example-not-typeable}} -For the following expressions, infer the most general types or determine -that the expression is not well-typed using simple type parameters: +For the following expressions, infer the most general types or show +that the expression is not well-typed with simple types: \textbf{(a)} $f\rightarrow f(f)\quad.$ @@ -1593,6 +1617,9 @@ \subsubsection{Example \label{subsec:Example-not-typeable}\ref{subsec:Example-no \textbf{(c)} $f\rightarrow g\rightarrow f(h\rightarrow h(g))\quad.$ +By \textsf{``}simple types\textsf{''} we mean that $f$, $g$, $h$ cannot have \emph{their +own} type parameters. + \subparagraph{Solution} \textbf{(a)} The type of $f$ is unknown, so we begin by assigning @@ -1604,6 +1631,11 @@ \subsubsection{Example \label{subsec:Example-not-typeable}\ref{subsec:Example-no are no simple types $A$ and $B$ such that $A=A\rightarrow B$. So, the expression $f\rightarrow f(f)$ is not well-typed. +This conclusion holds only because we do not allow the function $f$ +to have its own type parameters. Otherwise, the expression $f(f)$ +could be well-typed. See, for instance, Example~\ref{subsec:Example-hof-derive-types-3} +showing that the expression \lstinline!twice(twice)! is well-typed. + \textbf{(b)} Begin by assigning type parameters as $f^{:A}$ and $h^{:B}$, where $A$ and $B$ are unknown. To match types in $h(f)$, the type of $h$ must be a function type with an argument of type $A$. So, @@ -1624,7 +1656,7 @@ \subsubsection{Example \label{subsec:Example-not-typeable}\ref{subsec:Example-no \] There are no other restrictions. We have found the most general type: \[ -\big(f^{:((B\rightarrow D)\rightarrow D)\rightarrow E}\rightarrow g^{:B}\rightarrow f(h^{:B\rightarrow D}\rightarrow h(g))\big):((B\rightarrow D)\rightarrow D)\rightarrow E)\rightarrow B\rightarrow E\quad. +\big(f^{:((B\rightarrow D)\rightarrow D)\rightarrow E}\rightarrow g^{:B}\rightarrow f(h^{:B\rightarrow D}\rightarrow h(g))\big):(((B\rightarrow D)\rightarrow D)\rightarrow E)\rightarrow B\rightarrow E\quad. \] The type parameters $B$, $D$, $E$ remain arbitrary. @@ -1702,7 +1734,7 @@ \subsubsection{Example \label{subsec:Example-hof-curried}\ref{subsec:Example-hof The type of this expression is $\left(\text{Int}\rightarrow D\right)\rightarrow D$ with a type parameter $D$. Since the argument $y$ is an arbitrary function, we cannot simplify either $y(10)$ or $y\rightarrow y(10)$ -any further. We conclude that the final simplified form of Eq.~(\ref{eq:example-hof-curried-function-solved1}) +any further. So, the final simplified form of Eq.~(\ref{eq:example-hof-curried-function-solved1}) is $y^{:\text{Int}\rightarrow D}\rightarrow y(10)$. To test this, we first define the function $f\rightarrow g\rightarrow g(f)$ @@ -1819,8 +1851,8 @@ \subsubsection{Exercise \label{subsec:Exercise-hof-simple-8}\ref{subsec:Exercise \subsubsection{Exercise \label{subsec:Exercise-hof-simple-7-1}\ref{subsec:Exercise-hof-simple-7-1}} Implement a fully parametric, information-preserving, curried function -that recovers an error using a given function argument. The type signature -and an example test: +that recovers from an error using a given function argument. The type +signature and an example test: \begin{lstlisting} def recover[E, A]: Option[Either[E, A]] => (E => A) => Option[A] = ??? @@ -1876,9 +1908,9 @@ \subsubsection{Exercise \label{subsec:Exercise-hof-simple-6}\ref{subsec:Exercise \subsubsection{Exercise \label{subsec:Exercise-hof-simple-8-1}\ref{subsec:Exercise-hof-simple-8-1}} -Write a function \lstinline!curry2! converting an uncurried function -of type \texttt{}\lstinline!(A, A) => A! into an equivalent curried -function of type \texttt{}\lstinline!A => A => A!. +Write a function \lstinline!curry2! converting a function of type +\texttt{}\lstinline!(A, A) => A! into an equivalent curried function +of type \texttt{}\lstinline!A => A => A!. \subsubsection{Exercise \label{subsec:Exercise-hof-curried-1}\ref{subsec:Exercise-hof-curried-1}} @@ -2078,20 +2110,19 @@ \subsection{Operator syntax for function applications} In mathematics, function applications are sometimes written without parentheses, for instance: $\cos x$ or $\log z$. Commonly used formulas -such as $2\sin x\cos x$ imply parentheses as $2\cdot\sin\left(x\right)\cdot\cos\left(x\right)$. +such as $2\sin x\cos x$ imply parentheses as $2\cdot(\sin\left(x\right))\cdot(\cos\left(x\right))$. This convention allows us to treat certain functions as \textsf{``}operators\textsf{''} that are written without parentheses, similar to the operators of summation, $\sum_{k}f(k)$, or differentiation, $\frac{d}{dx}f(x)$. -Some programming languages (such as ML, OCaml, Haskell, and F\#) have +Some programming languages (such as OCaml, Haskell, and F\#) have adopted this \textsf{``}operator syntax\index{operator syntax}\textsf{''}, making -parentheses optional for function arguments. In those languages, \lstinline!f x! -means the same as \lstinline!f(x)!.\footnote{The operator syntax has a long history in programming. It is used -in Unix shell commands, for example \lstinline!cp file1 file2!. In -LISP-like languages, function applications are enclosed in parentheses -but the arguments are space-separated, for example \lstinline!(f 10 20)!. -Operator syntax is also used in some programming languages such as -Tcl, Groovy, and Coffeescript.} Parentheses are still used, for example, in expressions such as \lstinline!f(g x)!. +parentheses optional for all function arguments. In those languages, +\lstinline!f x! means the same as \lstinline!f(x)!.\footnote{The operator syntax has a long history in programming. It is used +in Unix shell commands, for example \lstinline!cp file1 file2!, and +also in the language \lstinline!Tcl!. In LISP-like languages, function +applications are enclosed in parentheses but the arguments are space-separated, +for example \lstinline!(f 10 20)!.} Parentheses are still used, for example, in expressions such as \lstinline!f(g x)!. For curried functions, function applications group to the left, so \lstinline!f x y z! means \lstinline!((f x) y) z!. Function applications group stronger than infix operations, so \lstinline!f x + y! means @@ -2128,17 +2159,17 @@ \subsection{Operator syntax for function applications} argument using the curly brace syntax. Compare the two definitions of the function \lstinline!summation! described in Section~\ref{subsec:Nameless-functions-in-mathematical-notation}: \begin{lstlisting} -def summation1(a: Int, b: Int, g: Int => Int): Int = (a to b).map(g).sum +def summation1(a: Int, b: Int, g: Int => Double): Double = (a to b).map(g).sum -def summation2(a: Int, b: Int)(g: Int => Int): Int = (a to b).map(g).sum +def summation2(a: Int, b: Int)(g: Int => Double): Double = (a to b).map(g).sum \end{lstlisting} These functions are applied to arguments like this: \begin{lstlisting} scala> summation1(1, 10, { x => x * x * x + 2 * x }) -res0: Int = 3135 +res0: Double = 3135.0 scala> summation2(1, 10) { x => x * x * x + 2 * x } -res1: Int = 3135 +res1: Double = 3135.0 \end{lstlisting} The code that calls \lstinline!summation2! is easier to read because the curried argument is syntactically separated from the rest of the diff --git a/sofp-src/tex/sofp-induction.tex b/sofp-src/tex/sofp-induction.tex index 5e110d26c..bd90069b6 100644 --- a/sofp-src/tex/sofp-induction.tex +++ b/sofp-src/tex/sofp-induction.tex @@ -33,8 +33,7 @@ \subsection{Examples: Using tuples} of\index{tuples!fields} a tuple. A tuple\textsf{'}s parts can have different types, but the type of each part (and the number of parts) is fixed once and for all. It is a \textbf{type error}\index{type error} to -use incorrect types in a tuple, or an incorrect number of parts of -a tuple: +use incorrect types in a tuple, or an incorrect number of parts: \begin{lstlisting} scala> val bad: (Int, String) = (1, 2) :11: error: type mismatch; @@ -88,6 +87,9 @@ \subsection{Examples: Using tuples} scala> c._2 res1: (String, Int) = (abc,3) + +scala> c._2._1 +res2: String = abc \end{lstlisting} To define functions whose arguments are tuples, we could use the tuple @@ -110,10 +112,10 @@ \subsection{Pattern matching for tuples} Instead of using accessor methods when working with tuples, it is often convenient to use \textbf{pattern matching\index{pattern matching}}. -Pattern matching occurs in two situations in Scala: +Pattern matching occurs in Scala as: \begin{itemize} -\item destructuring definition: \lstinline[mathescape=true]!val $pattern$ = ...! -\item \lstinline!case! expression: \lstinline[mathescape=true]!case $pattern$ => ...! +\item a destructuring definition: \lstinline[mathescape=true]!val $pattern$ = ...! +\item a \lstinline!case! expression: \lstinline[mathescape=true]!case $pattern$ => ...! \end{itemize} Here is an example of a \textbf{destructuring\index{destructuring} definition}: @@ -136,8 +138,8 @@ \subsection{Pattern matching for tuples} are also assigned automatically. In the example above, the left-hand side of the destructuring definition -contains a tuple pattern \lstinline!(x, y, z)! that looks like a -tuple, except that its parts are names \lstinline!x!, \lstinline!y!, +contains the tuple pattern \lstinline!(x, y, z)! that looks like +a tuple, except that its parts are names \lstinline!x!, \lstinline!y!, \lstinline!z! that are so far \emph{undefined}. These names are called \index{pattern variables}\textbf{pattern variables}. The destructuring definition checks whether the structure of the value of \lstinline!g! @@ -157,8 +159,8 @@ \subsection{Pattern matching for tuples} 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 +\textemdash{} they are called \index{pattern variables}\textbf{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!, @@ -274,8 +276,8 @@ \subsection{Using tuples with collections} \end{lstlisting} In this way, we can use the standard methods such as \lstinline!map!, \lstinline!filter!, \lstinline!max!, \lstinline!sum! to manipulate -sequences of tuples. The names of the pattern variables \textsf{``}\lstinline!fruit!\textsf{''}, -\textsf{``}\lstinline!count!\textsf{''} are chosen to help us remember the meaning +sequences of tuples. The names of the pattern variables (\textsf{``}\lstinline!fruit!\textsf{''}, +\textsf{``}\lstinline!count!\textsf{''}) are chosen to help us remember the meaning of the parts of tuples. We can easily transform a list of tuples into a list of values of @@ -446,8 +448,8 @@ \subsection{Treating dictionaries as collections} So, one can say that the \lstinline!flatten! method inserts the operation \lstinline!++! between all the inner sequences. -By definition, \lstinline!flatten! removes \emph{only one} level -of nesting at the \emph{top} of the data type. If applied to a \lstinline!List[List[List[Int]]]!, +Note that \lstinline!flatten! removes \emph{only one} level of nesting +at the \emph{top} of the data type. If applied to a \lstinline!List[List[List[Int]]]!, the \lstinline!flatten! method returns a \lstinline!List[List[Int]]! with inner lists unchanged: \begin{lstlisting} @@ -532,7 +534,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. This gives us flexibility to elements in a custom way: +element. This gives us flexibility to sort elements in a custom way: \begin{lstlisting} scala> Seq(1, 2, 3).sortBy(x => -x) res0: Seq[Int] = List(3, 2, 1) @@ -730,8 +732,7 @@ \subsubsection{Example \label{subsec:tuples-Example6}\ref{subsec:tuples-Example6 Now, we need to have \lstinline!(x, y)! instead of \lstinline!(1, y)! in the argument of \lstinline!map!, where \lstinline!x! iterates -over \lstinline!List(1, 2, 3)! in the outside scope. Using this \lstinline!map! -operation, we obtain: +over \lstinline!List(1, 2, 3)! in the outside scope: \begin{lstlisting} scala> val s = List(1, 2, 3).map(x => List(1, 2, 3).map { y => (x, y) }) s: List[List[(Int, Int)]] = List(List((1,1), (1,2), (1,3)), List((2,1), (2,2), (2,3)), List((3,1), (3,2), (3,3))) @@ -753,15 +754,15 @@ \subsubsection{Example \label{subsec:tuples-Example6}\ref{subsec:tuples-Example6 To create that dictionary, we will apply \lstinline!toMap! to a sequence of pairs \lstinline!(key, value)!, which in our case needs to be of the form of a nested tuple \lstinline!((x, y), x * y)!. To achieve -this, we use \lstinline!map! with a function that computes the product -and creates these nested tuples: +that, we use \lstinline!map! with a function that computes the product +and creates those nested tuples: \begin{lstlisting} scala> val s = List(1, 2, 3).flatMap(x => List(1, 2, 3).map { y => (x, y) }). map { case (x, 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} We can simplify this code if we notice that we are first mapping each -\lstinline!y! to a tuple \lstinline!(x, y)!, and later map each +\lstinline!y! to a tuple \lstinline!(x, y)!, and later mapping each tuple \lstinline!(x, y)! to a nested tuple \lstinline!((x, y), x * y)!. Instead, the entire computation can be done in the inner \lstinline!map! operation: @@ -1047,10 +1048,10 @@ \subsubsection{Exercise \label{tuples-Exercise-8}\ref{tuples-Exercise-8}} \subsubsection{Exercise \label{tuples-Exercise-5}\ref{tuples-Exercise-5}} -Given \lstinline!p:Seq[String]! and \lstinline!q:Seq[Int]! of \emph{equal} -length and assuming that values in \lstinline!q! do not repeat, compute -a \lstinline!Map[Int, String]! mapping numbers from \lstinline!q! -to the corresponding strings from \lstinline!p!. +Given \lstinline!p: Seq[String]! and \lstinline!q: Seq[Int]! of +\emph{equal} length and assuming that values in \lstinline!q! do +not repeat, compute a \lstinline!Map[Int, String]! mapping numbers +from \lstinline!q! to the corresponding strings from \lstinline!p!. \subsubsection{Exercise \label{tuples-Exercise-6}\ref{tuples-Exercise-6}} @@ -1170,7 +1171,7 @@ \section{Converting a sequence into a single value} (ds zip powers).map { case (d, p) => d * p }.sum } -scala> digitsToInt(Seq(2,4,0,5)) +scala> digitsToInt(Seq(2, 4, 0, 5)) res0: Int = 2405 \end{lstlisting} For this task, the required computation can be written as the formula: @@ -1196,7 +1197,7 @@ \subsection{Inductive definitions of aggregation functions\label{subsec:Inductiv case} of the induction: We need to specify what value the function \lstinline!f! returns for an empty sequence, \lstinline!Seq()!. The standard method \lstinline!isEmpty! can be used to detect empty -sequences. In case the function \lstinline!f! is only defined for +sequences. In case the function \lstinline!f! is defined only for non-empty sequences, we need to specify what the function \lstinline!f! returns for a one-element sequence such as \lstinline!Seq(x)!, with any \lstinline!x!. @@ -1267,17 +1268,15 @@ \subsection{Inductive definitions of aggregation functions\label{subsec:Inductiv When a function is defined by induction, proving a property of that function will usually involve a \textsf{``}proof by induction\textsf{''}.\index{proof by induction} As an example, let us prove that \lstinline!(xs ++ ys).length = xs.length + ys.length!. -We use induction on the length of the sequence \lstinline!xs!. In -the base case, we need to prove that the property holds for the base -case of the function\textsf{'}s definition. In the base case, we need to prove -that the property holds for an empty sequence \lstinline!xs! (and -an arbitrary sequence \lstinline!ys!). To verify the base case, we -write: \lstinline!(Seq() ++ ys).length == ys.length!. In the inductive -step of the proof, we assume that the property already holds for some -\lstinline!xs! and \lstinline!ys! and prove that the property will -then hold for \lstinline!x +: xs! instead of \lstinline!xs!. To -verify that, we use the associativity law of the concatenation operation -(to be proved in Statement~\ref{subsec:Statement-concat-array-associativity}), +We use induction on the length of the sequence \lstinline!xs!. In +the base case, we need to prove that the property holds for an empty +sequence \lstinline!xs! (and an arbitrary sequence \lstinline!ys!). +To verify the base case, we write: \lstinline!(Seq() ++ ys).length == ys.length!. +In the inductive step of the proof, we assume that the property already +holds for some \lstinline!xs! and \lstinline!ys! and prove that +the property will then hold for \lstinline!x +: xs! instead of \lstinline!xs!. +To verify that, we use the associativity law of the concatenation +operation (to be proved in Statement~\ref{subsec:Statement-concat-array-associativity}), which allows us to write: \lstinline!(x +: xs) ++ ys == x +: (xs ++ ys)!. Then: \begin{lstlisting} @@ -1292,10 +1291,9 @@ \subsection{Inductive definitions of aggregation functions\label{subsec:Inductiv There are two main ways of translating mathematical induction into code. The first way is to write a recursive function. The second way is to use a standard library function, such as \lstinline!foldLeft! -or \lstinline!reduce!. Most often it is better to use the standard -library functions, but sometimes the code is more transparent when -using explicit recursion. So, let us consider each of these ways in -turn. +or \lstinline!reduce!. Often it is better to use library functions, +but sometimes the code is more transparent when recursion is explicit. +So, let us consider each of these ways in turn. \subsection{Implementing functions by recursion} @@ -1314,7 +1312,7 @@ \subsection{Implementing functions by recursion} scala> def infiniteLoop(x: Int): Int = infiniteLoop(x + 1) infiniteLoop: (x: Int)Int -scala> infiniteLoop(2) // You will need to press Ctrl-C to stop this. +scala> infiniteLoop(0) // You will need to press Ctrl-C to stop this. \end{lstlisting} We translate mathematical induction into code by first writing a condition @@ -1340,8 +1338,8 @@ \subsection{Implementing functions by recursion} to a single element (\lstinline!x!) that is being added.} For computing the sum of a numerical sequence, the order of summation -does not matter. However, the order of operations \emph{will} matter -for many other computational tasks. We need to choose whether the +does not matter. But the order of operations \emph{will} matter for +many other computational tasks. We will need to choose whether the inductive step should split the sequence as \lstinline!s = x +: xs! or as \lstinline!s = xs :+ x!, depending on the task at hand. @@ -1350,16 +1348,16 @@ \subsection{Implementing functions by recursion} \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 xs = s.take(s.length - 1) // and xs. + val xs = s.init // and xs. digitsToInt(xs) * 10 + x // Call digitsToInt(...) recursively. } \end{lstlisting} In this example, it is important to split the sequence \lstinline!s! into \lstinline!xs :+ x! and not into \lstinline!x +: xs!. The reason is that digits increase their numerical value from right to left, -so the correct result is computed if we split \lstinline!s! into -\lstinline!xs :+ x! and multiply \lstinline!digitsToInt(xs)! by -$10$ before adding \lstinline!x!. +so the correct result is computed as \lstinline!digitsToInt(xs) * 10 + x! +if we split \lstinline!s! into \lstinline!xs :+ x!. For that splitting, +we use the standard library methods \lstinline!init! and \lstinline!last!. These examples show how mathematical induction is converted into recursive code. This approach often works but has two technical problems. The @@ -1436,9 +1434,7 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} \end{lstlisting} In this code, one of the branches of the \lstinline!if/else! returns a fixed value without doing any recursive calls, while the other branch -returns the result of a recursive call to \lstinline!lengthT(...)!. -In the code of \lstinline!lengthT!, recursive calls never occur within -any sub-expressions. +returns the result of a recursive call to \lstinline!lengthT(...)!. It is not a problem that the recursive call to \lstinline!lengthT! has some sub-expressions such as \lstinline!res + 1! as its arguments, @@ -1480,13 +1476,13 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} How did we rewrite the code of \lstinline!lengthS! into the tail-recursive code of \lstinline!lengthT!? An important difference between \lstinline!lengthS! -and \lstinline!lengthT! is the additional argument, \lstinline!res!, +and \lstinline!lengthT! is the additional argument (\lstinline!res!), called the \textbf{accumulator}\index{accumulator argument}\index{recursive function!accumulator argument} \textbf{argument}. This argument is equal to an intermediate result of the computation. The next intermediate result (\lstinline!res + 1!) is computed and passed on to the next recursive call via the accumulator argument. In the base case of the recursion, the function now returns -the accumulated result, \lstinline!res!, rather than \lstinline!0!, +the accumulated result (\lstinline!res!) rather than \lstinline!0!, because at that time the computation is finished. Rewriting code by adding an accumulator argument to achieve tail recursion @@ -1555,12 +1551,13 @@ \subsection{Tail recursion\label{subsec:Tail-recursion}} \] This equation follows from the \textbf{\index{associativity law!of addition}associativity law} of addition. So, the computation can be rearranged to group all -additions to the left. The accumulator value is the result of adding -up to some number of parentheses. In code, it means that intermediate -expressions are fully computed before making recursive calls. So, -recursive calls always occur outside all other sub-expressions \textemdash{} -that is, in tail positions. There are no sub-expressions that need -to be stored on the stack until all the recursive calls are complete. +additions to the left. During the evaluation, the accumulator\textsf{'}s value +corresponds to a certain number of left-grouped parentheses, $\left(\left(0+1\right)...\right)+1$. +In code, it means that intermediate expressions are fully computed +before making recursive calls. So, recursive calls always occur outside +all other sub-expressions \textemdash{} that is, in tail positions. +There are no sub-expressions that need to be stored on the stack until +all the recursive calls are complete. However, not all computations can be rearranged in that way. Even if a code rearrangement exists, it may not be immediately obvious @@ -1629,24 +1626,25 @@ \subsubsection{Statement \label{subsec:Statement-fromdigitsT-equals-fromdigits}\ case. To prove the inductive step, we assume that Eq.~(\ref{eq:stmt-fromdigitsT-reformulated}) -holds for a given sequence $s$. Then write the inductive step (we -will use the symbol $\overset{?}{=}$ to denote equations we still -need to prove): +holds for a given sequence $s$. Then write the inductive step. We +use the symbol $\overset{?}{=}$ to denote equations we still need +to prove: \begin{equation} f([x]\pplus s,r)\overset{?}{=}d([x]\pplus s)+r*10^{\left|s\right|+1}\quad.\label{eq:stmt-need-to-prove-step} \end{equation} We will transform the left-hand side and the right-hand side separately, -hoping to obtain the same expression. The left-hand side of Eq.~(\ref{eq:stmt-need-to-prove-step}): +hoping to obtain the same expression. The left-hand side of Eq.~(\ref{eq:stmt-need-to-prove-step}) +is: \begin{align*} & f([x]\pplus s,r)\\ {\color{greenunder}\text{use Eq.~(\ref{eq:stmt-fromdigitsT-expand-f})}:}\quad & =f(s,10*r+x)\\ {\color{greenunder}\text{use Eq.~(\ref{eq:stmt-fromdigitsT-reformulated})}:}\quad & =d(s)+\left(10*r+x\right)*10^{\left|s\right|}\quad. \end{align*} The right-hand side of Eq.~(\ref{eq:stmt-need-to-prove-step}) contains -$d([x]\pplus s)$, which we somehow need to simplify. Assuming that -$d(s)$ correctly calculates a number from its digits, we use a property -of decimal notation: a digit $x$ in front of $n$ other digits has -the value $x*10^{n}$. This property can be formulated as an equation: +$d([x]\pplus s)$, which we now need to rewrite. Assuming that $d(s)$ +correctly calculates a number from its digits, we use a property of +decimal notation: a digit $x$ in front of $n$ other digits has the +value $x*10^{n}$. This property can be formulated as an equation: \begin{equation} d([x]\pplus s)=x*10^{\left|s\right|}+d(s)\quad.\label{stmt-from-digits-property} \end{equation} @@ -1687,7 +1685,7 @@ \subsubsection{Statement \label{subsec:Statement-fromdigitsT-equals-fromdigits}\ {\color{greenunder}\text{expand parentheses}:}\quad & =x*10^{\left|s\right|+1}+d(s)*10+y\\ {\color{greenunder}\text{use Eq.~(\ref{eq:stmt-fromdigits-code-of-d})}:}\quad & =x*10^{\left|s\right|+1}+d(s\pplus[y])\quad. \end{align*} -This demonstrates Eq.~(\ref{eq:stmt-from-digits-induction-step}) +This establishes Eq.~(\ref{eq:stmt-from-digits-induction-step}) and concludes the proof. \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:implementing-general-aggregation-foldleft}} @@ -1695,7 +1693,7 @@ \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:im An \textbf{aggregation}\index{aggregation} converts a sequence of values into a single value. In general, the type of the result may be different from the type of sequence elements. To describe that -general situation, we introduce type parameters, \lstinline!A! and +general situation, we introduce type parameters \lstinline!A! and \lstinline!B!, so that the input sequence is of type \lstinline!Seq[A]! and the aggregated value is of type \lstinline!B!. Then an inductive definition of any aggregation function \lstinline!f: Seq[A] => B! @@ -1704,14 +1702,15 @@ \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:im \item (Base case.) For an empty sequence, we have \lstinline!f(Seq()) = b0!, where \lstinline!b0: B! is a given value. \item (Inductive step.) Assuming that \lstinline!f(xs) = b! is already -computed, we define \lstinline!f(xs :+ x) = g(x, b)! where \lstinline!g! -is a given function with type signature \lstinline!g: (A, B) => B!. +computed, we define \lstinline!f(xs :+ x) = g(x, b)!, where \lstinline!g! +is a given function, \lstinline!g: (A, B) => B!. \end{itemize} -The code implementing \lstinline!f! is written using recursion: +The code for \lstinline!f! is written using recursion and the methods +\lstinline!init! and \lstinline!last!: \begin{lstlisting} def f[A, B](s: Seq[A]): B = if (s.isEmpty) b0 - else g(s.last, f(s.take(s.length - 1))) + else g(s.last, f(s.init)) \end{lstlisting} We can now refactor this code into a generic utility function, by turning \lstinline!b0! and \lstinline!g! into parameters. A possible @@ -1719,7 +1718,7 @@ \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:im \begin{lstlisting} def f[A, B](s: Seq[A], b: B, g: (A, B) => B): B = if (s.isEmpty) b - else g(s.last, f(s.take(s.length - 1), b, g) + else g(s.last, f(s.init, b, g) \end{lstlisting} However, this implementation is not tail-recursive. Applying \lstinline!f! to a sequence of, say, three elements, \lstinline!Seq(x, y, z)!, @@ -1730,7 +1729,7 @@ \subsection{Implementing general aggregation (\texttt{foldLeft})\label{subsec:im then compute \lstinline!g(y, g(x, b))! and continue. In other words, we need to traverse the sequence starting from its \emph{leftmost} element \lstinline!x!, rather than starting from the right. So, instead -of splitting the sequence \lstinline!s! into \lstinline!s.take(s.length - 1) :+ s.last! +of splitting the sequence \lstinline!s! into \lstinline!s.init :+ s.last! as we did in the code of \lstinline!f!, we need to split \lstinline!s! into \lstinline!s.head +: s.tail!. Let us also exchange the order of the arguments of \lstinline!g!, in order to be more consistent @@ -2339,9 +2338,9 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin function as a mathematical formula. To compute the digits of, say, $n=2405$, we need to divide $n$ repeatedly by $10$, getting a sequence $n_{k}$ of intermediate numbers ($n_{0}=2405$, $n_{1}=240$, ...) -and the corresponding sequence of last digits, $n_{k}\text{ mod }10$ -(in this example: $5$, $0$, ...). The sequence $n_{k}$ is defined -using mathematical induction: +and the corresponding sequence of last digits, $n_{k}\,\%\,10$ (in +this example: $5$, $0$, ...). The sequence $n_{k}$ is defined using +mathematical induction: \begin{itemize} \item Base case: $n_{0}=n$, where $n$ is a given initial integer. \item Inductive step: $n_{k+1}=\left\lfloor \frac{n_{k}}{10}\right\rfloor \ \text{for}\ k=1,2,...$ @@ -2356,7 +2355,7 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin \hline {\small{}$n_{k}=$} & {\small{}$2405$} & {\small{}$240$} & {\small{}$24$} & {\small{}$2$} & {\small{}$0$} & {\small{}$0$} & {\small{}$0$}\tabularnewline \hline -{\small{}$n_{k}\text{ mod }10=$} & {\small{}$5$} & {\small{}$0$} & {\small{}$4$} & {\small{}$2$} & {\small{}$0$} & {\small{}$0$} & {\small{}$0$}\tabularnewline +{\small{}$n_{k}\,\%\,10=$} & {\small{}$5$} & {\small{}$0$} & {\small{}$4$} & {\small{}$2$} & {\small{}$0$} & {\small{}$0$} & {\small{}$0$}\tabularnewline \hline \end{tabular} \par\end{center} @@ -2388,6 +2387,7 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin .toList.reverse } \end{lstlisting} +$\square$ The type signature of the method \lstinline!Stream.iterate! can be written as: @@ -2395,8 +2395,8 @@ \section{Converting a single value into a sequence\label{sec:ch2Converting-a-sin def iterate[A](init: A)(next: A => A): Stream[A] \end{lstlisting} This shows a close correspondence to a definition by mathematical -induction. The base case is the first value, \lstinline!init!, and -the inductive step is a function, \lstinline!next!, that computes +induction. The base case is the first value (\lstinline!init!) and +the inductive step is a function (\lstinline!next!) that computes the next element from the previous one. It is a general way of creating sequences whose length is not determined in advance. @@ -2468,9 +2468,7 @@ \section{Transforming a sequence into another sequence\label{sec:Transforming-a- \section{Summary} We have seen a number of ways for translating mathematical induction -into Scala code. - -What problems can we solve now? +into Scala code. What problems can we solve now? \begin{itemize} \item Compute mathematical expressions involving arbitrary recursion. \item Use the accumulator trick to enforce tail recursion. @@ -2652,7 +2650,7 @@ \subsubsection{Example \label{subsec:ch2Example-seq-9}\ref{subsec:ch2Example-seq \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 +of the aggregation will be a dictionary of word counts for all the words seen so far: \begin{lstlisting} def countWords(s: String): Map[String, Int] = { @@ -2732,7 +2730,7 @@ \subsubsection{Example \label{subsec:ch2Example-binary-search-seq-4}\ref{subsec: } } \end{lstlisting} -We will first decide the type and the initial value of the accumulator, +We will first figure out the type and the initial value of the accumulator, then implement the updater. The information required for the recursive call must show the segment @@ -2778,7 +2776,7 @@ \subsubsection{Example \label{subsec:ch2Example-binary-search-seq-4}\ref{subsec: \textbf{(b)} We can visualize the binary search as a procedure that generates a stream of progressively tighter bounds for the location of \lstinline!goal!. The initial bounds are \lstinline!(0, xs.length)!, -and the final bounds are \lstinline!(k, k+1)! for some \lstinline!k!. +and the final bounds are \lstinline!(k, k + 1)! for some \lstinline!k!. We can generate the sequence of bounds using \lstinline!Stream.iterate! and stop the sequence when the bounds become sufficiently tight. To detect that, we use the \lstinline!find! method: @@ -2803,12 +2801,13 @@ \subsubsection{Example \label{subsec:ch2Example-binary-search-seq-4}\ref{subsec: } \end{lstlisting} In this code, recursion is delegated to \lstinline!Stream.iterate! -and is cleanly separated from the \textsf{``}business logic\textsf{''} (i.e., implementing -the base case, the inductive step, and the post-processing). +and is cleanly separated from the \textsf{``}business logic\textsf{''} (i.e., from +specific computations needed in the base case, the inductive step, +and the post-processing). \subsubsection{Example \label{subsec:ch2sumdigitsExample-seq-5}\ref{subsec:ch2sumdigitsExample-seq-5}} -For a given positive \lstinline!n:Int!, compute the sequence $\left[s_{0},s_{1},s_{2},...\right]$ +For a given positive \lstinline!n: Int!, compute the sequence $\left[s_{0},s_{1},s_{2},...\right]$ defined by $s_{0}=SD(n)$ and $s_{k}=SD(s_{k-1})$ for $k>0$, where $SD(x)$ is the sum of the decimal digits of the integer $x$, e.g., $SD(123)=6$. Stop the sequence $s_{i}$ when the numbers begin repeating. @@ -2845,16 +2844,16 @@ \subsubsection{Example \label{subsec:ch2sumdigitsExample-seq-5}\ref{subsec:ch2su scala> Stream.iterate(99)(SD).scanLeft((0,0)) { case ((prev, x), next) => (x, next) }.take(8).toList res2: List[(Int, Int)] = List((0,0), (0,99), (99,18), (18,9), (9,9), (9,9), (9,9), (9,9)) -scala> res2.drop(1).takeWhile { case (x, y) => x != y } +scala> res2.drop(1).takeWhile { case (x, y) => x != y } res3: List[(Int, Int)] = List((0,99), (99,18), (18,9)) \end{lstlisting} This looks right; it remains to remove the first parts of the tuples: \begin{lstlisting} -def sdSeq(n: Int): Seq[Int] = Stream.iterate(n)(SD) // Stream[Int] +def sdSeq(n: Int): Seq[Int] = Stream.iterate(n)(SD) // Stream[Int] .scanLeft((0,0)) { case ((prev, x), next) => (x, next) } // Stream[(Int, Int)] - .drop(1).takeWhile { case (x, y) => x != y } // Stream[(Int, Int)] - .map(_._2) // Stream[Int] - .toList // List[Int] + .drop(1).takeWhile { case (x, y) => x != y } // Stream[(Int, Int)] + .map(_._2) // Stream[Int] + .toList // List[Int] scala> sdSeq(99) res3: Seq[Int] = List(99, 18, 9) @@ -3074,11 +3073,11 @@ \subsubsection{Example \label{subsec:ch2Example-seq-10-1}\ref{subsec:ch2Example- 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 -duplicates. So, the accumulator should represent the longest subsequence -found so far, as well as any required extra information about other -subsequences that might grow as we iterate over the elements of \lstinline!xs!. +We first need to determine the type of the accumulator value. The +task is to find the longest subsequence without adjacent duplicates. +So, the accumulator should represent the longest subsequence found +so far, as well as any required extra information about other subsequences +that might grow as we iterate over the elements of \lstinline!xs!. What is that extra information in our case? Imagine creating the set of \emph{all} subsequences that have no adjacent @@ -3131,7 +3130,7 @@ \subsection{Exercises\index{exercises}} \subsubsection{Exercise \label{subsec:ch2Exercise-seq-1}\ref{subsec:ch2Exercise-seq-1}} Define a function \lstinline!dsq! that computes the sum of squared -digits of a given integer; for example, \lstinline!dsq(123) = 14! +digits of a given integer; for instance, \lstinline!dsq(123) = 14! (see Example~\ref{subsec:ch2sumdigitsExample-seq-5}). Generalize \lstinline!dsq! to take as an argument a function \lstinline!f: Int => Int! replacing the squaring operation. The required type signature and @@ -3139,10 +3138,10 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-1}\ref{subsec:ch2Exercise- \begin{lstlisting} def digitsFSum(x: Int)(f: Int => Int): Int = ??? -scala> digitsFSum(123){ x => x * x } +scala> digitsFSum(123) { x => x * x } res0: Int = 14 -scala> digitsFSum(123){ x => x * x * x } +scala> digitsFSum(123) { x => x * x * x } res1: Int = 36 \end{lstlisting} @@ -3206,10 +3205,10 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-4}\ref{subsec:ch2Exercise- \subsubsection{Exercise \label{subsec:ch2Exercise-seq-5}\ref{subsec:ch2Exercise-seq-5}} -Same task as in Exercise~\ref{subsec:ch2Exercise-seq-4} for a set -of sets: instead of just three sets \lstinline!a!, \lstinline!b!, -\lstinline!c!, a \lstinline!Set[Set[Int]]! is given. The required -type signature and a sample test: +Same task as in Exercise~\ref{subsec:ch2Exercise-seq-4} but using +a set of sets. Instead of just three sets \lstinline!a!, \lstinline!b!, +\lstinline!c!, we are given a value of type \lstinline!Set[Set[Int]]!. +The required type signature and a sample test: \begin{lstlisting} def prodSet(si: Set[Set[Int]]): Set[Set[Int]] = ??? @@ -3221,14 +3220,14 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-5}\ref{subsec:ch2Exercise- \subsubsection{Exercise \label{subsec:ch2Exercise-seq-4-1}\ref{subsec:ch2Exercise-seq-4-1}} -In a sorted array \lstinline!xs:Array[Int]! where no values are repeated, -find all pairs of values whose sum equals a given number $n$. Use -tail recursion. A type signature and a sample test: +In a sorted integer array where no values are repeated, find all pairs +of values whose sum equals a given number $n$. Use tail recursion. +A type signature and a sample test: \begin{lstlisting} def pairs(goal: Int, xs: Array[Int]): Set[(Int, Int)] = ??? -scala> pairs(10, Array(1, 2, 3, 4, 5, 6, 7, 8))() -res0: Set[(Int, Int)] = Set((2,8), (3,7), (4,6), (5,5)) +scala> pairs(10, Array(1, 2, 4, 5, 6, 8)) +res0: Set[(Int, Int)] = Set((2,8), (4,6), (5,5)) \end{lstlisting} @@ -3238,7 +3237,7 @@ \subsubsection{Exercise \label{subsec:ch2Exercise-seq-6}\ref{subsec:ch2Exercise- \begin{lstlisting} def revSentence(s: String): String = ??? -scala> revSentence("A quick brown fox") // Words are separated by a single space. +scala> revSentence("A quick brown fox") // Words are separated by one space. res0: String = "fox brown quick A" \end{lstlisting} @@ -3399,7 +3398,7 @@ \section{Discussion and further developments} \subsection{Total and partial functions} -In Scala, functions can be total or partial. A \textbf{\index{total function}total} +Functions can be total or partial. A \textbf{\index{total function}total} function will always compute a result value, while a \textbf{\index{partial function}partial} function may fail to compute its result for certain values of its arguments. @@ -3416,29 +3415,29 @@ \subsection{Total and partial functions} at scala.collection.AbstractTraversable.max(Traversable.scala:104) ... 32 elided \end{lstlisting} -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 +This kind of error may crash a 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 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. +the program started running, which may crash the 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 -a sequence if we know that it is non-empty. +So, it seems clear that we should avoid writing code that generates +such errors. For instance, we will prefer to apply \lstinline!max! +only to sequences that are known to be non-empty. Sometimes, a function that uses pattern matching turns out to be a partial function because its pattern matching code fails on certain input data. -If a pattern matching expression fails, the code will throw an exception -and stop running. In functional programming, we usually want to avoid -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: +If none of the cases matches in a pattern matching expression, the +code will throw an exception (a \lstinline!MatchError!). In functional +programming, we usually want to avoid that situation because reasoning +about program correctness becomes hard. In most cases, programs can +be rewritten to avoid the possibility of match errors. An example +of an unsafe pattern matching expression is: \begin{lstlisting}[mathescape=false] def h(p: (Int, Int)): Int = p match { case (x, 0) => x } @@ -3456,7 +3455,7 @@ \subsection{Total and partial functions} 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 +Pattern matching errors never happen if we match a tuple of correct 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} @@ -3486,11 +3485,11 @@ \subsection{Scope and shadowing of pattern matching variables\label{subsec:Scope \begin{lstlisting} def f(x: (Int, Int)): Int = x match { case (x, y) => x + y } -scala> f( (2,4) ) +scala> f( (2, 4) ) res0: Int = 6 \end{lstlisting} The argument of \lstinline!f! is the variable \lstinline!x! of a -tuple type \lstinline!(Int,Int)!, but there is also a pattern variable +tuple type \lstinline!(Int, Int)!, but there is also a pattern variable \lstinline!x! in the case expression. The pattern variable \lstinline!x! matches the first part of the tuple and has type \lstinline!Int!. Because variables are locally scoped, the pattern variable \lstinline!x! @@ -3508,7 +3507,7 @@ \subsection{Scope and shadowing of pattern matching variables\label{subsec:Scope \lstinline!x! (which is a \textsf{``}\index{bound variable}bound variable\textsf{''} inside the case expression). -The problem is easy to avoid: we can give the pattern variable another +This problem is easy to avoid: we can give the pattern variable another name. Since the pattern variable is locally scoped, it can be renamed within its scope without affecting any other code: \begin{lstlisting} @@ -3530,7 +3529,7 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v \end{lstlisting} At this point, we have not defined a stopping condition for this stream. In some sense, streams may be seen as \textsf{``}infinite\textsf{''} sequences, although -in practice a stream is always finite because computers cannot run +in practice a stream is always finite because programs cannot run infinitely long. Also, computers cannot store infinitely many values in memory. @@ -3684,8 +3683,8 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v same. This behavior is what we expect values to have. So, we say that integers \textsf{``}are values\textsf{''} in the mathematical sense. Alternatively, one says that numbers are \textbf{immutable\index{immutable value},} -i.e., cannot be changed. (What would it mean to \textsf{``}modify\textsf{''} the number -$10$?) +i.e., cannot be modified. (What would it mean to \textsf{``}modify\textsf{''} the +number $10$?) In programming, a type \textbf{has value-like behavior} \index{value-like behavior}if a computation applied to it always gives the same result. Usually, @@ -3750,13 +3749,12 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v way: the sequence \emph{was} stopped at a repetition, as we wanted, but some of the elements of the given sequence are missing (while other elements are present). It is difficult to debug a program that -produces \emph{partially} correct numbers. +produces \emph{partially} \emph{correct} numbers. The error in this code occurs in the expression \lstinline!halfSpeed.zip(iter)! due to the fact that \lstinline!halfSpeed! was itself defined via \lstinline!iter!. The result is that \lstinline!iter! is used twice -in this code, which leads to errors. Apparently, \lstinline!iter! -\emph{does not behave as a value}! Creating an \lstinline!Iterator! +in this code, which leads to errors. Creating an \lstinline!Iterator! and using it twice in the same expression can give wrong results or even fail with an exception: \begin{lstlisting} @@ -3807,14 +3805,14 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v a value stored in memory; starting and stopping processes or threads; reading or writing files; printing; sending or receiving data over a network; showing images on a display; playing or recording sounds; -getting photo or video from a digital camera. +getting photos or videos from a digital camera. Code that performs side effects does not behave as a value. Evaluating such code twice will perform the side effect twice, which is not the same as just re-using the result value twice. A function with a side effect may return different values each time it is called, even when the same arguments are given to the function. (For example, a digital -camera will typically give a different image each time.) \index{pure function}\textbf{Pure +camera will typically return a different image each time.) \index{pure function}\textbf{Pure functions} are those that contain no code with side effects. A pure function will always return the same result value when applied to the same arguments. So, pure functions behave similarly to functions @@ -3828,7 +3826,7 @@ \subsection{Lazy values and sequences. Iterators and streams\label{subsec:Lazy-v Otherwise we would write code like this: \begin{lstlisting} def sum(xs: Seq[Int]): Int = { - var result: Int = 0 // A mutable variable! + var result: Int = 0 // A mutable variable. sum.map { x => result += x } // Side effect: mutation. result } diff --git a/sofp-src/tex/sofp-monads.tex b/sofp-src/tex/sofp-monads.tex index d71c31c53..e964e9e57 100644 --- a/sofp-src/tex/sofp-monads.tex +++ b/sofp-src/tex/sofp-monads.tex @@ -4398,7 +4398,8 @@ \subsubsection{Statement \label{subsec:Statement-flatten-equivalent-to-flatMap}\ \subsubsection{Statement \label{subsec:Statement-flatten-has-2-laws}\ref{subsec:Statement-flatten-has-2-laws}} If a \lstinline!flatMap! function satisfies the three laws~(\ref{eq:left-naturality-law-flatMap})\textendash (\ref{eq:associativity-law-flatMap}), -the corresponding \lstinline!flatten! function defined as $\text{ftn}\triangleq\text{flm}\left(\text{id}\right)$ +the corresponding \lstinline!flatten! function\index{naturality law!of flatten@of \lstinline!flatten!} +defined as $\text{ftn}\triangleq\text{flm}\left(\text{id}\right)$ satisfies its \emph{two} laws, with an arbitrary $f^{:A\rightarrow B}$: \begin{align} {\color{greenunder}\text{naturality law of }\text{ftn}:}\quad & f^{\uparrow S\uparrow S}\bef\text{ftn}=\text{ftn}\bef f^{\uparrow S}\quad,\label{eq:naturality-law-of-flatten}\\ @@ -6616,11 +6617,23 @@ \subsubsection{Exercise \label{subsec:Exercise-1-monads-2}\ref{subsec:Exercise-1 \] -\subsubsection{Exercise \label{subsec:Exercise-1-monads-3}\ref{subsec:Exercise-1-monads-3}} +\subsubsection{Exercise \label{subsec:Exercise-1-monads-3-2}\ref{subsec:Exercise-1-monads-3-2}} Verify the associativity law for the \lstinline!Reader! monad by an explicit derivation. +\subsubsection{Exercise \label{subsec:Exercise-1-monads-3}\ref{subsec:Exercise-1-monads-3}} + +The naturality law~(\ref{eq:naturality-law-of-flatten}) of \lstinline!flatten! +is written in the code notation as:\index{naturality law!of flatten@of \lstinline!flatten!} +\[ +f^{\uparrow S\uparrow S}\bef\text{ftn}_{S}=\text{ftn}_{S}\bef f^{\uparrow S}\quad. +\] +Show that one \emph{cannot} replace $f^{\uparrow S}$ in that law +by an arbitrary function $g:S^{A}\rightarrow S^{B}$. Find a counterexample +with a specific $S$, $A$, $B$, and $g:S^{A}\rightarrow S^{B}$ +for which $g^{\uparrow S}\bef\text{ftn}_{S}\neq\text{ftn}_{S}\bef g$. + \subsubsection{Exercise \label{subsec:Exercise-1-monads-3-1}\ref{subsec:Exercise-1-monads-3-1}} Show that the laws hold for a non-standard \lstinline!List! monad diff --git a/sofp-src/tex/sofp-nameless-functions.tex b/sofp-src/tex/sofp-nameless-functions.tex index d883fe3b6..c1894c1dd 100644 --- a/sofp-src/tex/sofp-nameless-functions.tex +++ b/sofp-src/tex/sofp-nameless-functions.tex @@ -105,7 +105,7 @@ \subsection{Nameless functions\label{subsec:Nameless-functions}} but this book uses a simpler arrow symbol ($\rightarrow$) that is visually similar.} \[ -x\rightarrow\left(\text{some formula}\right)\quad. +x\rightarrow\left(\text{some formula that may use }x\right)\quad. \] So, a mathematical notation for the nameless factorial function is: \[ @@ -297,7 +297,7 @@ \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 accessible \emph{only inside} the expression \textsf{``}$\forall k.\,...$\textsf{''} +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. @@ -502,8 +502,8 @@ \section{Aggregating data from sequences} .sum \end{lstlisting} -In Scala, methods are often used one after another, as if in a chain. -For instance, \lstinline!s.map(...).sum! means: first apply \lstinline!s.map(...)!, +In Scala, methods are often used one after another in a chain. For +instance, \lstinline!s.map(...).sum! means: first apply \lstinline!s.map(...)!, which returns a \emph{new} list; then apply \texttt{}\lstinline!sum! to that new list. To make the code more readable, we may put each of the chained methods on a new line. @@ -566,7 +566,7 @@ \section{Filtering and truncating a sequence } 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. +scala> List(1, 2, 3, 4, 5).filter(k => k != 3) // Exclude the value 3. res5: List[Int] = List(1, 2, 4, 5) \end{lstlisting} @@ -575,7 +575,7 @@ \section{Filtering and truncating a sequence } the initial portion of values from the original list for which predicate remains \lstinline!true!: \begin{lstlisting} -scala> List(1, 2, 3, 4, 5).takeWhile(k => k != 3) // Truncate at the value 3. +scala> List(1, 2, 3, 4, 5).takeWhile(k => k != 3) // Truncate at the value 3. res6: List[Int] = List(1, 2) \end{lstlisting} @@ -1019,7 +1019,7 @@ \subsection{Functional programming as a paradigm} of human history. It took centuries to invent flexible and powerful notation, such as $\sum_{k\in S}p(k)$, and to develop the corresponding rules of calculation. Converting formulas into code, FP capitalizes -on the power of these reasoning tools. +on the power of those reasoning tools. As we have seen, the Scala code for certain computational tasks corresponds quite closely to mathematical formulas (although programmers do have @@ -1056,24 +1056,23 @@ \subsection{Iteration without loops} \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 this equation ten times\textsf{''}. Indeed, it -is unnecessary to evaluate a formula such as $x_{i}^{2}$ ten times, -as the value of $x_{i}^{2}$ remains the same every time. It is just -as unnecessary to \textsf{``}repeat\textsf{''} a mathematical equation. +No mathematics textbook would define the standard deviation $\sigma$ +via loops or by saying \textsf{``}now repeat this equation $n$ times\textsf{''}. +Indeed, it is unnecessary to evaluate a formula such as $x_{i}^{2}$ +many times, as 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 -certain iterative computations. Such computations are can be defined -rigorously 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!, +certain iterative computations. Such computations are defined rigorously +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 +more general methods for implementing inductive computations. Those 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: +defined by the formula shown above is computed by this code: \begin{lstlisting} def sigma(xs: Seq[Double]): Double = { val n = xs.length.toDouble @@ -1097,8 +1096,7 @@ \subsection{The mathematical meaning of \textquotedblleft variables\textquotedbl The usage of variables in functional programming is similar to how mathematical literature uses variables. In mathematics, \textbf{variables}\index{variable} -are used first of all as \emph{arguments} of functions; e.g., the -formula: +are used first of all as arguments of functions; e.g., the formula: \[ f(x)=x^{2}+x \] @@ -1288,7 +1286,7 @@ \subsection{Nameless functions in mathematical notation\label{subsec:Nameless-fu in the FP paradigm. Similar code can be written in any programming language that supports nameless functions as arguments of other functions. -\subsection{Named and nameless expressions and their uses} +\subsection{Named and nameless expressions} It is a significant advantage if a programming language supports unnamed (or \textsf{``}nameless\textsf{''}) expressions. To see this, consider a familiar diff --git a/sofp-src/tex/sofp-preface.tex b/sofp-src/tex/sofp-preface.tex index 611a8d659..69cdbb36e 100644 --- a/sofp-src/tex/sofp-preface.tex +++ b/sofp-src/tex/sofp-preface.tex @@ -43,8 +43,8 @@ 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. +from the practice of reasoning about code and are first explained +without reference to category theory. This book is \emph{not} an introduction to current theoretical research in functional programming. Instead, the focus is on material known diff --git a/sofp-src/tex/sofp-reasoning.tex b/sofp-src/tex/sofp-reasoning.tex index dc482b82d..48eb763f2 100644 --- a/sofp-src/tex/sofp-reasoning.tex +++ b/sofp-src/tex/sofp-reasoning.tex @@ -15,12 +15,12 @@ \section{This book\textsf{'}s notation for code} \subsection{The nine constructions of fully parametric code} The eight basic constructions\index{eight code constructions} introduced -in Section~\ref{subsec:The-rules-of-proof}, together with recursion, -serve as a foundation for \textbf{fully parametric} coding style. -All major techniques and design patterns of functional programming -can be implemented using only these constructions, i.e., by fully -parametric\index{fully parametric!code} code. We will now define -the code notation\index{code notation} (summarized in Table~\ref{tab:Mathematical-notation-for-basic-code-constructions}) +in Section~\ref{subsec:Short-notation-for-eight-code-constructions}, +together with recursion, serve as a foundation for \textbf{fully parametric} +coding style. All major techniques and design patterns of functional +programming can be implemented using only these constructions, i.e., +by fully parametric\index{fully parametric!code} code. We will now +define the code notation\index{code notation} (summarized in Table~\ref{tab:Mathematical-notation-for-basic-code-constructions}) for each of the nine constructions.\index{nine code constructions} \begin{table} @@ -244,7 +244,7 @@ \subsection{The nine constructions of fully parametric code} \] We will use this example to explain how disjunctive functions are -written in the matrix notation\index{matrix notation}\index{disjunctive type!in matrix notation}. +written in the matrix notation\index{matrix notation}\index{disjunctive type!matrix notation}. Each row of a matrix corresponds to a part of the disjunctive type matched by one of the \lstinline!case! expressions. In this example, @@ -382,7 +382,7 @@ \subsection{The nine constructions of fully parametric code} \paragraph{9) Use a recursive call} The last construction is to call a function recursively within its -own definition. This construction was not shown in Section~\ref{subsec:The-rules-of-proof} +own definition. This construction was not shown in Section~\ref{subsec:Short-notation-for-eight-code-constructions} because the constructive propositional logic (which was the main focus in that chapter) cannot represent a recursively defined value. However, this limitation of propositional logic means only that we do not have diff --git a/sofp-src/tex/sofp-traversable.tex b/sofp-src/tex/sofp-traversable.tex index 337653e6f..2aa1d30e4 100644 --- a/sofp-src/tex/sofp-traversable.tex +++ b/sofp-src/tex/sofp-traversable.tex @@ -1333,10 +1333,10 @@ \subsection{Recursion schemes. I. Folding operations\label{subsec:Recursion-sche lazy val x: Looping[Int] = Looping(Right(_ => x)) scala> x.run.right.get(()) // No stack overflows. -val res0: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) +res0: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) scala> x.run.right.get(()).run.right.get(()) // This is again the same value: -val res1: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) +res1: Looping[Int] = Looping(Right($Lambda$1123/1058984040@753aca85)) \end{lstlisting} Trying to compute \lstinline!fold(f)(x)! with any \lstinline!f! will result in an infinite loop. diff --git a/sofp-src/tex/sofp.tex b/sofp-src/tex/sofp.tex index dd1130d11..0aa67999b 100644 --- a/sofp-src/tex/sofp.tex +++ b/sofp-src/tex/sofp.tex @@ -320,9 +320,9 @@ {\footnotesize{}ISBN (e-book): 978-0-359-76877-6}\\ {\footnotesize{}ISBN: 978-0-359-76877-6}\\ \\ -{\scriptsize{}Source hash (sha256): 17b4bb8829374494ae3690700a5f0ae917dc56639902d1fd2d1025db57d05672}\\ -{\scriptsize{}Git commit: e12f0f1f35f5df815368c198faec75a2ec5a74a9}\\ -{\scriptsize{}PDF file built on Tue, 09 Apr 2024 20:36:21 +0200 by pdfTeX 3.141592653-2.6-1.40.25 (TeX Live 2023) on Darwin}\\ +{\scriptsize{}Source hash (sha256): cbd327cf5baeac2e9d58471a6d010dc2c542ea70d4d5c5a4c4c8ce793c5a5b43}\\ +{\scriptsize{}Git commit: 195c1f1251605e0eba92ac033f93ee2d0acaf5ef}\\ +{\scriptsize{}PDF file built on Sat, 04 May 2024 21:11:14 +0200 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, @@ -357,10 +357,10 @@ parametricity theorems.}\\ {\scriptsize{}}\\ {\scriptsize{}Long and difficult, yet boring explanations are logically -developed in excruciating detail through 1884 Scala +developed in excruciating detail through 1893 Scala code snippets, 191 statements with step-by-step derivations, -103 diagrams, 221 examples with tested Scala -code, and 297 exercises. Discussions build upon each +103 diagrams, 223 examples with tested Scala +code, and 300 exercises. Discussions build upon each chapter's material further.}\\ {\scriptsize{}}\\ {\scriptsize{}Beginners in FP will find tutorials about the map/reduce