Compare commits

..

5 Commits

Author SHA1 Message Date
153c179388 Mjahaja 2025-11-20 15:39:01 +01:00
5b3392dab2 Myes 2 2025-11-19 18:19:50 +01:00
773fe1a9c3 Myes 2025-11-19 11:15:50 +01:00
d91a947186 Tehee 2025-11-17 19:58:03 +01:00
e219436446 Yippie 2025-11-17 19:36:26 +01:00
5 changed files with 85 additions and 61 deletions

View File

@ -12,19 +12,21 @@ This time you can make use of a [[http://bnfc.digitalgrammars.com/][BNFC]] speci
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: 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]]. + 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. + 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. + 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): + 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. + First use cabal repl to start GHCi.
- Then issue the following commands at the GHCi command prompt: + Then issue the following commands at the GHCi command prompt:
#+begin_src haskell #+begin_src haskell
import Chi import Chi
import Prelude import Prelude
pretty <$> (runDecode (decode =<< pretty <$>
asDecoder (code =<< code (parse "\\x. x")))) (runDecode (decode =<< asDecoder
(code =<< code (parse "\\x. x"))))
#+end_src #+end_src
\newpage
* Exercises * Exercises
In order to pass this assignment you have to get at least four points. In order to pass this assignment you have to get at least four points.
@ -49,7 +51,7 @@ rec foo = \m. \n. case m of
Give a high-level explanation of the mathematical function in $\mathbb{N} \rightarrow \mathbb{N} \rightarrow \text{Bool}$ that is implemented by this code. 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 *** Answer
The function will check for equality of the two natural numbers. If they are both $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. 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) ** (2p)
Consider the $\chi$ term /t/ with concrete syntax $C (\lambda z.z)$: Consider the $\chi$ term /t/ with concrete syntax $C (\lambda z.z)$:
@ -77,14 +79,14 @@ If you use the BNFC specification above and Haskell, then the substitution funct
Variable -> Exp -> Exp -> Exp Variable -> Exp -> Exp -> Exp
#+end_src #+end_src
Test your implementation. Here are some test cases that must work: Test your implementation. Here are some test cases that must work:
| Variable | Substituted term | Term | Result | | Variable | Substituted term | Term | Result |
|----------+------------------+---------------------------------------------+---------------------------------------------| |----------+------------------+---------------------------------------------+------------------------------------------------------|
| ~x~ | ~Z()~ | ~rec x = x~ | ~rec x = x~ | | ~x~ | $Z()$ | $\text{rec}\ x = x$ | $\text{rec}\ x = x$ |
| ~y~ | $\lambda x.x$ | $\lambda x. (x y)$ | $\lambda x . (x (\lambda 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 \}$ | | ~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 *** Answer
See Assignment.hs See =Main.hs=.
** (1p) ** (1p)
Implement multiplication of natural numbers in $\chi$, using the representation of natural numbers given in the $\chi$ specification. Implement multiplication of natural numbers in $\chi$, using the representation of natural numbers given in the $\chi$ specification.
@ -97,13 +99,10 @@ Hint: If you want to make use of addition in the implementation of multiplicatio
{ Zero() -> Zero() { Zero() -> Zero()
; Succ(n) -> add m (mult n) ; Succ(n) -> add m (mult n)
} }
#+end_src [ add <- \m. rec add = \n. case n of
where we substitute ~add~ for the following: { Zero() -> m
#+begin_src chi ; Succ(n) -> Suc(add n)
\m. rec add = \n. case n of }]
{ Zero() -> m
; Succ(n) -> Suc(add n)
}
#+end_src #+end_src
** (2p) [BN] ** (2p) [BN]
@ -117,13 +116,13 @@ If you use the BNFC specification above and Haskell, then the interpreter should
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: 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: - The following programs should fail to terminate:
+ $C() C()$ + $\text{C}()\ \text{C}()$
+ $case \lambda x.x of {}$ + $\text{case}\ \lambda x.x\ \text{of}\ {}$
+ $case C() of { C(x) \rightarrow C() }$ + $\text{case}\ \text{C}()\ \text{of}\ { \text{C}(x) \rightarrow \text{C}() }$
+ $case C(C()) of { C() \rightarrow C() }$ + $\text{case}\ \text{C}(\text{C}())\ \text{of}\ { \text{C}() \rightarrow \text{C}() }$
+ $case C(C()) of { C() \rightarrow C(); C(x) \rightarrow x }$ + $\text{case}\ \text{C}(\text{C}())\ \text{of}\ { \text{C}() \rightarrow \text{C}(); \text{C}(x) \rightarrow x }$
+ $case C() of { D() \rightarrow D() }$ + $\text{case} \text{C}()\ \text{of}\ { \text{D}() \rightarrow \text{D}() }$
+ $(\lambda x.\lambda y.x) (rec x = x)$ + $(\lambda x.\lambda y.x) (\text{rec}\ x = x)$
- The following programs should terminate with specific results: - 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(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 C(\lambda x.x, Zero()) of { C(f, x) \rightarrow f x }$ should terminate with the value $Zero()$.
@ -133,3 +132,4 @@ Test your implementation, for instance by testing that addition (defined in the
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. 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 *** Answer
See =Main.hs=.

View File

@ -1,25 +0,0 @@
{-# Language LambdaCase #-}
module Assignment where
import Chi
subst :: Variable -> Exp -> Exp -> Exp
subst var e = \case
Apply e1 e2 -> Apply (subst var e e1) (subst var e e2)
Lambda x e' -> Lambda x $ if var /= x then (subst var e e') else e'
Var x -> if var == x then e else Var x
Const c es -> Const c $ map (subst var e) es
Rec x e' -> Rec x $ if var /= x then (subst var e e') else e'
Case e' branches -> Case (subst var e e') $ map substBr branches
where
substBr :: Br -> Br
substBr (Branch c vs e') = Branch c vs $ if var `notElem` vs then (subst var e e') else e'
eval' :: Exp -> Reader (Map Variable Exp) Exp
eval' = undefined
eval :: Exp -> Exp
eval = undefined
main :: IO ()
main = getLine >>= print . eval . parse

View File

@ -12,12 +12,12 @@ library
hashable >= 1.4.7.0 && < 1.6, hashable >= 1.4.7.0 && < 1.6,
mtl >= 2.2.2 && < 2.4, mtl >= 2.2.2 && < 2.4,
pretty ^>= 1.1.3.6, pretty ^>= 1.1.3.6,
QuickCheck ^>= 2.15.0.0, QuickCheck >= 2.16.0.0,
transformers >= 0.5.6.2 && < 0.7, transformers >= 0.5.6.2 && < 0.7,
unordered-containers ^>= 0.2.20 unordered-containers ^>= 0.2.20
build-tool-depends: build-tool-depends:
alex:alex ^>= 3.5.2.0, alex:alex ^>= 3.5.4.0,
happy:happy ^>= 2.1.5 happy:happy ^>= 2.1.7
exposed-modules: exposed-modules:
AbsChi AbsChi
Chi Chi
@ -28,6 +28,9 @@ library
. .
executable interpreter executable interpreter
main-is: Assignment.hs main-is: Main.hs
hs-source-dirs:
interpreter
build-depends: base build-depends: base
, chi , chi
, mtl

View File

@ -10,7 +10,7 @@
outputs = { self, nixpkgs, flake-utils }: outputs = { self, nixpkgs, flake-utils }:
let let
ghcVer = "ghc910"; ghcVer = "ghc912";
makeHaskellOverlay = overlay: final: prev: { makeHaskellOverlay = overlay: final: prev: {
haskell = prev.haskell // { haskell = prev.haskell // {
packages = prev.haskell.packages // { packages = prev.haskell.packages // {
@ -53,9 +53,6 @@
withHoogle = true; withHoogle = true;
buildInputs = buildInputs =
(with pkgs; [ (with pkgs; [
gnumake
jasmin
jre_minimal
]) ++ ]) ++
(with haskellPackages; [ (with haskellPackages; [
haskell-language-server haskell-language-server

49
3/interpreter/Main.hs Normal file
View File

@ -0,0 +1,49 @@
{-# Language LambdaCase, Strict #-}
module Main where
import Chi
import Data.Functor ( (<&>) )
import Control.Monad.Identity ( Identity( runIdentity ) )
-- Task 3
subst :: Variable -> Exp -> Exp -> Exp
subst var e = \case
Apply e1 e2 -> Apply (subst var e e1) (subst var e e2)
Lambda x e' -> Lambda x $ if var /= x then subst var e e' else e'
Var x -> if var == x then e else Var x
Const c es -> Const c $ map (subst var e) es
Rec x e' -> Rec x $ if var /= x then subst var e e' else e'
Case e' bs -> Case (subst var e e') $ map substBr bs
where
substBr :: Br -> Br
substBr (Branch c vs e') = Branch c vs $ if var `notElem` vs then subst var e e' else e'
-- Task 5
eval :: Exp -> Exp
eval = runIdentity . eval'
where
eval' :: Exp -> Identity Exp
eval' = \case
e@(Apply e1 e2) -> eval' e1 >>= \case
Lambda x e' -> eval' e2 >>= eval' . flip (subst x) e'
_ -> error $ "Function was not function in evaluation: " <> show e
Const c es -> mapM eval' es <&> Const c
Rec x e -> eval' $ subst x (Rec x e) e
Case e bs -> eval' e >>= \case
Const c vs -> lookupBranch c bs >>= \case
(xs,e') ->
if length vs /= length xs then error "Not the same amount of arguments in case" else
eval' $ foldr (uncurry subst) e' (zip xs vs)
e -> error $ "Non const in case: " <> show e
x -> pure x
lookupBranch :: Constructor -> [Br] -> Identity ([Variable], Exp)
lookupBranch c [] = error "No matching branch"
lookupBranch c ((Branch c' bs e):brs) =
if c == c'
then pure (bs,e)
else lookupBranch c brs
main :: IO ()
main = getLine >>= print . eval . parse