Files
Computeability/3/3.org
2025-11-20 15:39:01 +01:00

136 lines
9.9 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+title: Assignment 3
#+options: toc:nil
#+latex_header: \usepackage{parskip}
* Supporting files
This time you can make use of a [[http://bnfc.digitalgrammars.com/][BNFC]] specification ([[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.cf][~Chi.cf~]]) of a variant of the concrete syntax of $\chi$. This grammar gives specific rules for variable and constructor names, and differs from the concrete syntax presented in the lectures in some ways:
- Variables and constructors are sequences of letters (~a~ to ~z~ and ~A~ to ~Z~), digits (~0~ to ~9~), underscores (~_~), dashes (~-~) and primes (='=), and variables have to start with lower-case letters or underscores, whereas constructors have to start with upper-case letters.
- Lambdas are written using backslash characters (~\~) and arrows are written using the string ~->~.
- End-of-line comments of the form ~-- ...~ are allowed, as are (non-nested) comments of the form ~{- ... -}~.
- There can be a final comma after a non-empty list of constructor arguments, and there can be a final semicolon after a non-empty list of branches.
- Parentheses are treated differently. Superfluous parentheses are allowed around expressions. Some parentheses can be omitted; application is treated as a left-associative operation. Note that some grammatically correct expressions actually parse differently with this variant of the grammar, for instance ~(rec x = x y)~ which is interpreted as ~rec x = (x y)~ rather than ~(rec x = x) y~ (which was previously grammatically incorrect). See the [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.cf][grammar]] for details.
If you want to use Haskell then there is also a wrapper module ([[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.cf][~Chi.cf~]]) that exports the generated abstract syntax and some definitions that may be useful for testing your code ([[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.html][documentation]]). The wrapper module comes with a Cabal file ([[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/chi.cabal][~chi.cabal~]]) and a [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/cabal.project][~cabal.project~]] file that might make installation a little easier. Here is one way to (hopefully) get started:
+ Install all dependencies properly, including suitable versions of GHC and cabal-install ([[https://www.haskell.org/downloads/][installation instructions]]), as well as [[http://bnfc.digitalgrammars.com/][BNFC]].
+ Put [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.cf][~Chi.cf~]], [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.hs][~Chi.hs~]], [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/chi.cabal][~chi.cabal~]] and [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/cabal.project][~cabal.project~]] in an otherwise empty directory.
+ Run ~bnfc --haskell Chi.cf~ in that directory.
+ Now it is hopefully possible to use standard ~cabal~ commands. You could for instance try the following (still in the same directory):
+ First use cabal repl to start GHCi.
+ Then issue the following commands at the GHCi command prompt:
#+begin_src haskell
import Chi
import Prelude
pretty <$>
(runDecode (decode =<< asDecoder
(code =<< code (parse "\\x. x"))))
#+end_src
\newpage
* Exercises
In order to pass this assignment you have to get at least four points.
Please provide your source code in a form which is easy to test, not, say, a PDF file. Do not submit the files provided on this page or the generated code, only the code that you write.
(Exercises marked with [BN] are based on exercises from a previous version of this course, given by Bengt Nordström.)
** (1p)
Consider the following $\chi$ program:
#+begin_src chi
rec foo = \m. \n. case m of
{ Zero() → case n of
{ Zero() → True()
; Suc(n) → False()
}
; Suc(m) → case n of
{ Zero() → False()
; Suc(n) → foo m n
}
}
#+end_src
Give a high-level explanation of the mathematical function in $\mathbb{N} \rightarrow \mathbb{N} \rightarrow \text{Bool}$ that is implemented by this code.
*** Answer
The function will check for equality of the two natural numbers. If they are both $\text{Zero}()$, then it returns true, and if both are the successor of a some values, it checks if they are equal. In the other cases, it returns false.
** (2p)
Consider the $\chi$ term /t/ with concrete syntax $C (\lambda z.z)$:
- Give the abstract syntax corresponding to /t/. Use the abstract syntax presented in the lectures. The answer should be a value in the set /Exp/.
- Give the concrete syntax of the (standard) $\chi$ representation of /t/.
- Give the abstract syntax of the (standard) $\chi$ representation of /t/.
In the abstract syntax the constructor ~C~ should be represented by $\underline{C} \in \text{Const}$, and the variable ~z~ by $\underline{z} \in \text{Var}$. When giving the $\chi$ representation of the term you should use (the representation of) the number 0 to represent $\underline{C}$, and 1 to represent $\underline{z}$.
*** Answer
The abstract syntax is the following:
\[ \text{const}\ \underline{C}\ (\text{cons}\ (\text{lambda}\ \underline{z}\ (\text{var}\ \underline{z}))\ \text{nil}) \]
The concrete syntax of the standard representation is the following:
\[ \text{Const}(\ulcorner \underline{C} \urcorner, \text{Cons}(\text{Lambda}(\ulcorner \underline{z} \urcorner, \text{Cons} (\text{Var}(\ulcorner \underline{z} \urcorner), \text{Nil}())), \text{Nil}())) \]
The abstract syntax of the standard representation, given that $\underline{z}$ and $\underline{C}$ corresponds to zero:
\[ \text{Const}(\text{Zero}(), \text{Cons}(\text{Lambda}(\text{Zero}(), \text{Cons} (\text{Var}(\text{Zero}()), \text{Nil}())), \text{Nil}())) \]
** (2p) [BN]
Implement substitution for $\chi$. The function should take three arguments, a variable, a closed term, and another term, and substitute the first term for every free occurrence of the variable in the second term.
If you use the BNFC specification above and Haskell, then the substitution function should have the following type:
#+begin_src haskell
Variable -> Exp -> Exp -> Exp
#+end_src
Test your implementation. Here are some test cases that must work:
| Variable | Substituted term | Term | Result |
|----------+------------------+---------------------------------------------+------------------------------------------------------|
| ~x~ | $Z()$ | $\text{rec}\ x = x$ | $\text{rec}\ x = x$ |
| ~y~ | $\lambda x.x$ | $\lambda x. (x y)$ | $\lambda x . (x (\lambda x . x))$ |
| ~z~ | $C(\lambda z . z)$ | $\text{case}\ z\ \text{of}\ \{ C(z) \rightarrow z \}$ | $\text{case}\ C(\lambda z. z) \ \text{of}\ \{ C(z) \rightarrow z \}$ |
*** Answer
See =Main.hs=.
** (1p)
Implement multiplication of natural numbers in $\chi$, using the representation of natural numbers given in the $\chi$ specification.
Hint: If you want to make use of addition in the implementation of multiplication, then you can define multiplication using a free variable ~add~, and use the substitution operation from the previous exercise to substitute a complete (closed) implementation of addition for this variable.
*** Answer
#+begin_src chi
\m. rec mult = \n. case n of
{ Zero() -> Zero()
; Succ(n) -> add m (mult n)
}
[ add <- \m. rec add = \n. case n of
{ Zero() -> m
; Succ(n) -> Suc(add n)
}]
#+end_src
** (2p) [BN]
Implement an interpreter for $\chi$. The interpreter should be a partial function from closed terms to values, and should implement the operational semantics of $\chi$.
If you use the BNFC specification above and Haskell, then the interpreter should have the following type:
#+begin_src haskell
Exp -> Exp
#+end_src
Test your implementation, for instance by testing that addition (defined in the [[https://chalmers.instructure.com/courses/36941/file_contents/course%20files/chi/Chi.hs][wrapper module]]) works for some inputs. If addition doesnt work when your code is tested, then your solution will not be accepted. Also make sure that the following examples are implemented correctly:
- The following programs should fail to terminate:
+ $\text{C}()\ \text{C}()$
+ $\text{case}\ \lambda x.x\ \text{of}\ {}$
+ $\text{case}\ \text{C}()\ \text{of}\ { \text{C}(x) \rightarrow \text{C}() }$
+ $\text{case}\ \text{C}(\text{C}())\ \text{of}\ { \text{C}() \rightarrow \text{C}() }$
+ $\text{case}\ \text{C}(\text{C}())\ \text{of}\ { \text{C}() \rightarrow \text{C}(); \text{C}(x) \rightarrow x }$
+ $\text{case} \text{C}()\ \text{of}\ { \text{D}() \rightarrow \text{D}() }$
+ $(\lambda x.\lambda y.x) (\text{rec}\ x = x)$
- The following programs should terminate with specific results:
+ The program $case C(D(),E()) of { C(x, x) \rightarrow x }$ should terminate with the value $E()$.
+ The program $case C(\lambda x.x, Zero()) of { C(f, x) \rightarrow f x }$ should terminate with the value $Zero()$.
+ The program $case (\lambda x.x) C() of { C() \rightarrow C() }$ should terminate with the value $C()$.
+ The program $((\lambda x.x)(\lambda x.x))(\lambda x.x)$ should terminate with the value $\lambda x.x$.
Note that implementing a call-by-value semantics properly in a language like Haskell, which is by default non-strict, can be tricky. However, you will not fail if the only problem with your implementation is that some programs that should fail to terminate instead terminate with a “reasonable” result.
*** Answer
See =Main.hs=.