Browse Source

hw2 init

master
L.E.R 9 months ago
parent
commit
40fc578df3
10 changed files with 876 additions and 1 deletions
  1. 1
    0
      .gitignore
  2. 0
    0
      common/defs.tex
  3. BIN
      hw1/wr1.pdf
  4. 1
    1
      hw1/wr1.tex
  5. 129
    0
      hw2/hw2-1-problems.hs
  6. 137
    0
      hw2/hw2-2-problems.hs
  7. 183
    0
      hw2/hw2-3-problems.hs
  8. BIN
      hw2/wr2-problems.pdf
  9. BIN
      hw2/wr2.pdf
  10. 425
    0
      hw2/wr2.tex

+ 1
- 0
.gitignore View File

@@ -22,6 +22,7 @@ cabal.project.local~
.ghc.environment.*
*.exe
*.zip
## Core latex/pdflatex auxiliary files:

hw1/defs.tex → common/defs.tex View File


BIN
hw1/wr1.pdf View File


+ 1
- 1
hw1/wr1.tex View File

@@ -112,7 +112,7 @@
%% DEFINITION HELPERS
%%------------------------------------------------------------------------
\input{defs.tex}
\input{../common/defs.tex}
\pagestyle{fancyplain}

+ 129
- 0
hw2/hw2-1-problems.hs View File

@@ -0,0 +1,129 @@
-- CS 839, Spring 2019: Homework 2
-- Part 1: Append lists (30)

-- Do not change the following line!
{-# OPTIONS -fwarn-incomplete-patterns -fwarn-tabs -fno-warn-type-defaults #-}

-- **Your code should compile without warnings.**
-- The following line makes the compiler treat all warnings as hard errors.
-- When you are done, uncomment it and fix until there are no more errors.
-- (You may ignore unused function warnings.)
{-# OPTIONS -Wall -Werror #-}

-- You might want some functions from these libraries:
-- Data.List
--
-- In the functional programming style, we usually avoid mutating or updating
-- memory cells, preferring instead pure operations. Accordingly, data
-- structures in functional languages look rather different from the data
-- structures you might be used to. In this assignment, you will write a few
-- purely functional data structures.

-- Concatenating lists with `(++)` is an expensive operation. It is linear in
-- the length of the first argument, which must be "unravelled" and then added
-- back on one at a time.
-- To improve this, let's consider AppendLists. These use higher-order functions
-- so that appending becomes a constant-time operation. The price is that the
-- other list operations are much less efficient.
--
-- Note that for some of these functions, the best solution is just to convert
-- the append list to a regular list, perform the list operation there, and then
-- convert back to an append list. This is unavoidable for some operations, but
-- try to see if you can perform the operation more efficiently before reaching
-- for regular lists (e.g., for append).

-- The elements of the list will be of type `a`.
newtype AppendList a = AList ([a] -> [a])

-- The empty list is represented using the identity function, by
-- AList (\x -> x)
empty :: AppendList a
empty = AList (\x -> x)

-- The list [3] is represented as AList (\x -> 3:x)
-- The list [1, 9, 4] will be represented as the function (\x -> 1 : 9: 4 : x).

-- Based on these examples, write a function that takes on argument and returns
-- the AList that corresponds to the list with just that argument as element
singleton :: a -> AppendList a
singleton = undefined

-- Write a function that prepends an element to any appendlist, just like cons
-- (written : ) does for lists
alistCons :: a -> AppendList a -> AppendList a
alistCons = undefined

-- Write foldr and map functions for AppendLists, just like for Lists
alistFoldr :: (a -> b -> b) -> b -> AppendList a -> b
alistFoldr = undefined

-- Try to write this without using fromList
alistMap :: (a -> b) -> AppendList a -> AppendList b
alistMap = undefined

-- Finally, write the function that motivated all of this: append two AppendLists
-- together.
alistAppend :: AppendList a -> AppendList a -> AppendList a
alistAppend = undefined

-- Write a concatenation function which takes a list of AppendLists and turns
-- them into a single AppendList, preserving the order.
alistConcat :: [AppendList a] -> AppendList a
alistConcat = undefined

-- Write a replication function which makes an AppendList by repeating the given
-- element for a given number of times (possibly zero times).
alistReplicate :: Int -> a -> AppendList a
alistReplicate = undefined

-- Write a function that converts an append list to the regular list that it
-- represents
toList :: AppendList a -> [a]
toList = undefined

-- Write a function that does the opposite, converting a normal list into an
-- AppendList
fromList :: [a] -> AppendList a
fromList = undefined

-- Write a function that computes the head of an AppendList (your function may
-- fail when the AppendList is empty).
alistHead :: AppendList a -> a
alistHead = undefined

-- Write a function that computes the tail of an AppendList.
alistTail :: AppendList a -> AppendList a
alistTail = undefined

-- Basic tests: you should do more testing!
checkEq :: (Eq a, Show a) => a -> a -> String
checkEq expected got
| expected == got = "PASS"
| otherwise = "FAIL Expected: " ++ (show expected) ++ " Got: " ++ (show got)

main :: IO ()
main = let myList = [1, 3, 5, 7, 9] :: [Int]
myList' = [8, 6, 4, 2, 0] :: [Int] in
do putStr "toList/fromList: "
putStrLn $ checkEq myList (toList . fromList $ myList)

putStr "alistHead: "
putStrLn $ checkEq (head myList') (alistHead . fromList $ myList')

putStr "alistTail: "
putStrLn $ checkEq (tail myList) (toList . alistTail . fromList $ myList)

putStr "alistFoldr: "
putStrLn $ checkEq (foldr (+) 0 myList) (alistFoldr (+) 0 $ fromList myList)

putStr "alistMap: "
putStrLn $ checkEq (map (+ 1) myList') (toList (alistMap (+ 1) $ fromList myList'))

putStr "alistAppend: "
putStrLn $ checkEq (myList ++ myList') (toList $ alistAppend (fromList myList) (fromList myList'))

putStr "alistConcat: "
putStrLn $ checkEq (concat [myList', myList]) (toList $ alistConcat [(fromList myList'), (fromList myList)])

putStr "alistReplicate: "
putStrLn $ checkEq ([42, 42, 42, 42, 42] :: [Int]) $ toList (alistReplicate 5 42)

+ 137
- 0
hw2/hw2-2-problems.hs View File

@@ -0,0 +1,137 @@
-- CS 839, Spring 2019: Homework 2
-- Part 2: List zippers (30)

-- Do not change the following line!
{-# OPTIONS -fwarn-incomplete-patterns -fwarn-tabs -fno-warn-type-defaults #-}

-- **Your code should compile without warnings.**
-- The following line makes the compiler treat all warnings as hard errors.
-- When you are done, uncomment it and fix until there are no more errors.
-- (You may ignore unused function warnings.)
-- {-# OPTIONS -Wall -Werror #-}

-- You might want some functions from these libraries:
-- Data.List

-- A zipper takes a plain datastructure---a list, a tree, etc.---and adds an
-- extra bit of information describing a position within the datastructure. This
-- position behaves much like a cursor: we can move the cursor, lookup the value
-- at the cursor, or update/delete the value at the cursor.

-- We can represent a position in a non-empty plain list with three parts: the
-- list of elements before the position, the element at the position, and the
-- list of elements after the position. Otherwise, the zipper may be over an
-- empty list. The elements of the list will be of type `a`.

data ListZipper a =
LZEmpty
| LZItems [a] -- list of items before
a -- current item
[a] -- list of items after

-- One detail about Haskell lists is that they support efficient operations at
-- only one end, the start (head) of the list. Working at the tail end
-- requires traversing the whole list, an expensive operation.
--
-- To make the zipper operations easier to write and more efficient, we
-- store the list of items before in *reversed* order. For instance, if the
-- underlying list is [1, 2, 3, 4, 5] and the current position is 3, then the
-- zipper should look like
--
-- LzItems [2, 1] 3 [4, 5]
--
-- Keep this invariant in mind, and make sure it is maintained through all of
-- the operations.
--
-- Write a function to convert a regular list into a zipper, with the initial
-- position set to the first element (if the list is non-empty).

zipOfList :: [a] -> ListZipper a
zipOfList = undefined

-- Write a function to convert a zipper back into a regular list.

zipToList :: ListZipper a -> [a]
zipToList = undefined

-- Write a function to get the current item. Note that the function returns
-- `Maybe a`. Your function should return `Nothing` if the zipper is empty.

getCurItem :: ListZipper a -> Maybe a
getCurItem = undefined

-- Write functions to move the position left or right in the zipper. Since we
-- cannot actually change the input zipper in a pure functional language, your
-- function will return a zipper with the updated position. Remember to keep
-- track of the elements in the zipper: moving left or right should not change
-- the elements in the underlying list.
--
-- If the input zipper is empty, or the move is not valid (trying to move left
-- in the first position, or trying to move right in the last position), return
-- the original zipper with no change. Your function should be total---it should
-- never raise an error!

goLeftL :: ListZipper a -> ListZipper a
goLeftL = undefined

goRightL :: ListZipper a -> ListZipper a
goRightL = undefined

-- Write a function to replace the item at the current position in the zipper
-- with a new element. If the input zipper is empty, return the input zipper
-- unchanged. Again, your function should never raise an error!

updateItem :: a -> ListZipper a -> ListZipper a
updateItem = undefined

-- Write a function to insert a new element into the zipper *after* the current
-- position. The cursor should move to the new item after the insertion. Your
-- function should behave correctly for all zippers, including the empty zipper.

insertItem :: a -> ListZipper a -> ListZipper a
insertItem = undefined

-- Write a function to delete the current element from the zipper. The cursor
-- should move to the item before the deleted position, or after the first
-- position when deleting the first item. Again, your function should behave
-- correctly for all zippers, including the empty zipper. (Deleting from the
-- empty zipper should just return the empty zipper.)

deleteItem :: ListZipper a -> ListZipper a
deleteItem = undefined

-- This main function forms lists of strings. You enter commands to move around
-- the zipper and modify the list using it. If you want to start from a
-- different zipper, change the definition below.

initZip :: ListZipper String
initZip = LZEmpty

main :: IO ()
main =
aux initZip
where headMay xs = case xs of
(x:_) -> Just x
[] -> Nothing
isSpace c = c `elem` "\t \n\r\v\f"
aux zipp = do
putStr "-- Current list: "
putStr $ show (zipToList zipp)
case getCurItem zipp of
Just el -> do putStr " at element: "
print el
Nothing -> putStrLn ""
putStrLn ("-- Enter an operation on the list: " ++
"(l)eft, (r)ight, (e)dit, (i)nsert, or (d)elete:")
input <- getLine
case headMay input of
Just 'l' -> aux (goLeftL zipp)
Just 'r' -> aux (goRightL zipp)
Just 'e' -> let w2 = dropWhile isSpace (tail input)
in aux (updateItem w2 zipp)
Just 'i' -> let w2 = dropWhile isSpace (tail input)
in aux (insertItem w2 zipp)
Just 'd' -> aux (deleteItem zipp)
_ -> do putStrLn "!! Error: unrecognized command"
aux zipp


+ 183
- 0
hw2/hw2-3-problems.hs View File

@@ -0,0 +1,183 @@
-- CS 839, Spring 2019: Homework 2
-- Part 3: Tree zippers (40)

-- Do not change the following line!
{-# OPTIONS -fwarn-incomplete-patterns -fwarn-tabs -fno-warn-type-defaults #-}

-- **Your code should compile without warnings.**
-- The following line makes the compiler treat all warnings as hard errors.
-- When you are done, uncomment it and fix until there are no more errors.
-- (You may ignore unused function warnings.)
{-# OPTIONS -Wall -Werror #-}

-- You might want some functions from these libraries:
-- Data.List

-- We'll now extend zippers to work for trees. First, we'll set up a datatype
-- for plain trees. Trees will either consist of a leaf with a piece of data of
-- type `a`, or a list of trees. Complete the following datatype declaration,
-- replacing () with the correct types.

data Tree a =
Leaf ()
| Node ()

-- Just like before, we want to represent a (1) position and an (2) item with
-- our zipper. Both of these pieces are more complicated for trees. Let's start
-- with representing positions in a tree. Positions may be either leaf nodes or
-- internal nodes. We will represent positions recursively: a position of a node
-- is either the root of a tree, or it is the position of its parent node along
-- with two lists describing the node's siblings (child nodes of the same
-- parent): the sibling trees before the current node, and sibling trees after
-- the current node.
--
-- Fill out the following datatype declaration for the type of paths, replacing
-- (or removing) ().

data Path a =
Top
| Loc () () ()

-- Just like we did for list zippers, we will store the list of siblings before
-- the current position in *reverse* order, and the list of siblings after the
-- current position in *normal* order. Keep this invariant in mind and make sure
-- that it is preserved in all the operations.

-- Since the position may be an internal node, the item at a position may be a
-- tree. By combining these two pieces of data, we are ready to define the type
-- of tree zippers.

data TreeZipper a = TZ { getPath :: Path a, getItem :: Tree a }

-- Write a function to convert a regular tree into a zipper, with the initial
-- position set to the root.

zipOfTree :: Tree a -> TreeZipper a
zipOfTree = undefined

-- Write a function to convert a zipper back into a regular tree.
-- (Hint: you'll want to recurse, calling zipToTree on a smaller path.)

zipToTree :: TreeZipper a -> Tree a
zipToTree = undefined

-- Write a function to get the subtree at the current position.

getCurTree :: TreeZipper a -> Tree a
getCurTree = undefined

-- For trees, we can move the position in more directions. A left/right move
-- corresponds to switching to one of the siblings of the current position,
-- while an up/down move corresponds to moving to the parent or moving to the
-- first child of the current position.
--
-- If the move is not valid (trying to move left at the first sibling, or trying
-- to move right in the last sibling, etc.), return the original zipper with no
-- change. Your function should be total---it should never raise an error!

goLeftT :: TreeZipper a -> TreeZipper a
goLeftT = undefined

goRightT :: TreeZipper a -> TreeZipper a
goRightT = undefined

goUpT :: TreeZipper a -> TreeZipper a
goUpT = undefined

goDownT :: TreeZipper a -> TreeZipper a
goDownT = undefined

-- Write a function to replace the tree at the current position in the zipper
-- with a new subtree. Again, your function should never raise an error!

updateTree :: Tree a -> TreeZipper a -> TreeZipper a
updateTree = undefined

-- Write a function to insert a new subtree into the zipper. There are three
-- possible places to insert: left (as a new sibling before the current
-- position), right (as a new sibling after the current position), and down (as
-- a new first/left-most child of the current position). The cursor should end
-- up on the newly inserted item. If the insertion is invalid (inserting
-- left/right at the root), return the original zipper. Again, your function
-- should never raise an error!

insertLeftT :: Tree a -> TreeZipper a -> TreeZipper a
insertLeftT = undefined

insertRightT :: Tree a -> TreeZipper a -> TreeZipper a
insertRightT = undefined

insertDownT :: Tree a -> TreeZipper a -> TreeZipper a
insertDownT = undefined

-- Write a function to delete the whole subtree at the current position from the
-- zipper. The final position of the zipper should be (in decreasing priority)
-- the next sibling on the right, or the previous sibling on the left, or the
-- parent node if there are no other siblings.
--
-- Again, your function should behave correctly for all zippers; deleting the
-- root node should return the original zipper.

deleteT :: TreeZipper a -> TreeZipper a
deleteT = undefined

-- This main function forms lists of strings. You enter commands to move around
-- the zipper and modify the list using it. If you want to start from a
-- different zipper, change the definition below.
-- (Note: the following will not compile until you define the TreeZipper type.)

initZip :: TreeZipper Integer
initZip = undefined

main :: IO ()
main =
aux initZip
where headMay xs = case xs of
(x:_) -> Just x
[] -> Nothing
isDigit c = c `elem` "0123456789"
showTree t = case t of
Leaf a -> show a
Node children -> "(" ++ unwords ch_strs ++ ")"
where ch_strs = map showTree children
readTree word = case word of
"()" -> Right (Node [])
_ -> if all isDigit word
then Right (Leaf (read word))
else Left ("!! Error: Second argument must "
++ "be a number or ()")
onSnd wrds = case tail wrds of
[] -> Left "!! Error: need second argument"
(sec:_) -> readTree sec
aux :: TreeZipper Integer -> IO ()
aux zipp = do
putStr "-- Current Tree: "
putStr $ showTree (zipToTree zipp)
putStr " at subtree: "
print (showTree (getCurTree zipp))
putStrLn ("-- Enter an operation on the list:\n" ++
"-- (l)eft, (r)ight, (u)p, (d)own,\n-- (e)dit, " ++
"(il) insert left, (ir) insert right, " ++
"(id) insert down,\n-- or (del)ete:")
input <- getLine
let wrds = words input
case headMay wrds of
Just "l" -> aux (goLeftT zipp)
Just "r" -> aux (goRightT zipp)
Just "u" -> aux (goUpT zipp)
Just "d" -> aux (goDownT zipp)
Just "e" -> case onSnd wrds of
Left msg -> putStrLn msg >> aux zipp
Right tr -> aux (updateTree tr zipp)
Just "il" -> case onSnd wrds of
Left msg -> putStrLn msg >> aux zipp
Right tr -> aux (insertLeftT tr zipp)
Just "ir" -> case onSnd wrds of
Right tr -> aux (insertRightT tr zipp)
Left str -> putStrLn str >> aux zipp
Just "id" -> case onSnd wrds of
Right tr -> aux (insertDownT tr zipp)
Left str -> putStrLn str >> aux zipp
Just "del" -> aux (deleteT zipp)
_ -> putStrLn "!! Error: unrecognized command"
>> aux zipp

BIN
hw2/wr2-problems.pdf View File


BIN
hw2/wr2.pdf View File


+ 425
- 0
hw2/wr2.tex View File

@@ -0,0 +1,425 @@
\documentclass[a4paper]{article}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{natbib}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{paralist}
\usepackage{epstopdf}
\usepackage{tabularx}
\usepackage{longtable}
\usepackage{multirow}
\usepackage{multicol}
\usepackage[hidelinks]{hyperref}
\usepackage{fancyvrb}
\usepackage{algorithm}
\usepackage{algorithmic}
\usepackage{float}
\usepackage{listings}
\usepackage[svgname]{xcolor}
\usepackage{enumerate}
\usepackage{array}
\usepackage{times}
\usepackage{url}
\usepackage{fancyhdr}
\usepackage{comment}
\usepackage{environ}
\usepackage{times}
\usepackage{textcomp}
\usepackage{caption}
\urlstyle{rm}
\setlength\parindent{0pt} % Removes all indentation from paragraphs
\theoremstyle{definition}
\newtheorem{definition}{Definition}[]
\newtheorem{conjecture}{Conjecture}[]
\newtheorem{example}{Example}[]
\newtheorem{theorem}{Theorem}[]
\newtheorem{lemma}{Lemma}
\newtheorem{proposition}{Proposition}
\newtheorem{corollary}{Corollary}
\floatname{algorithm}{Procedure}
\renewcommand{\algorithmicrequire}{\textbf{Input:}}
\renewcommand{\algorithmicensure}{\textbf{Output:}}
\newcommand{\abs}[1]{\lvert#1\rvert}
\newcommand{\norm}[1]{\lVert#1\rVert}
\newcommand{\RR}{\mathbb{R}}
\newcommand{\CC}{\mathbb{C}}
\newcommand{\Nat}{\mathbb{N}}
\newcommand{\br}[1]{\{#1\}}
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}
\renewcommand{\qedsymbol}{$\blacksquare$}
\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\newcommand{\Var}{\mathrm{Var}}
\newcommand{\Cov}{\mathrm{Cov}}
\newcommand{\vc}[1]{\boldsymbol{#1}}
\newcommand{\xv}{\vc{x}}
\newcommand{\Sigmav}{\vc{\Sigma}}
\newcommand{\alphav}{\vc{\alpha}}
\newcommand{\muv}{\vc{\mu}}
\newcommand{\red}[1]{\textcolor{red}{#1}}
\def\x{\mathbf x}
\def\y{\mathbf y}
\def\w{\mathbf w}
\def\v{\mathbf v}
\def\E{\mathbb E}
\def\V{\mathbb V}
% TO SHOW SOLUTIONS, include following (else comment out):
\newenvironment{soln}{
\leavevmode\color{blue}\ignorespaces
}{}
\hypersetup{
% colorlinks,
linkcolor={red!50!black},
citecolor={blue!50!black},
urlcolor={blue!80!black}
}
\geometry{
top=1in, % <-- you want to adjust this
inner=1in,
outer=1in,
bottom=1in,
headheight=3em, % <-- and this
headsep=2em, % <-- and this
footskip=3em,
}
\lstset{
basicstyle=\ttfamily,
columns=fullflexible,
breaklines=true,
keepspaces=true,
postbreak=\raisebox{0ex}[0ex][0ex]{\color{red}$\hookrightarrow$\space}
}
%%------------------------------------------------------------------------
%% DEFINITION HELPERS
%%------------------------------------------------------------------------
\input{../common/defs.tex}
\pagestyle{fancyplain}
\lhead{\fancyplain{}{Homework 1: Written Assignment}}
\rhead{\fancyplain{}{CS 538 Theory and Design of Programming Languages}}
\cfoot{\thepage}
\title{\textsc{CS 538, Spring 2019}} % Title
%%% NOTE: Replace 'NAME HERE' etc., and delete any "\red{}" wrappers (so it won't show up as red)
\author{
Everette Rong \\
yrong9@wisc.edu \\
rong@cs.wisc.edu \\
% \red{$>>$ID HERE$<<$}\\
}
\date{}
\begin{document}
\maketitle
\begin{center}
\Huge
HW1: Written Assignment 1
\end{center}
\section{Calculator language: Syntax (10)}
Translate this English description of the language into a grammar.
\begin{soln}
\begin{lstlisting}
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
num = digit { digit }
bool = "tt" | "ff" (* boolean constants *)
int = [ "-" ] num (* positive/negative int *)
ae = int (* integer constants *)
| ae "+" ae (* addition *)
| ae "*" ae (* multiplication *)
| "if" be "then" ae "else" ae (* if-then-else *)
be = bool (* boolean constants *)
| be "&&" be (* logical and *)
| be "||" be (* logical or *)
| ae "==" ae (* equals *)
| ae "<" ae (* less than *)
\end{lstlisting}
\end{soln}
\section{Calculator language: Operational semantics (10)}
\begin{enumerate}
\item Give a small-step operational semantics for our calculator language.
\begin{soln}
Preliminaries:
\begin{itemize}
\item Both addition and multiplication will be calculated from left to right.
\item $add$ and $times$ mean the actual mathematical calculation of $+$ and $*$.
\item $\land$ and $\lor$ mean the actual logical operation of $and$ and $or$.
\item $-$ on the top means there is no step.
\item $e_i$ means the corresponding expression (int ($ae$) or bool ($be$)) in those steps.
\item $n_i$ represents an int constant, and $b_i$ represents a bool constant.
\end{itemize}
If-then-else (\textit{lazy-if}):
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{be_1}{be_1'}}
{\rstep{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2)}{(\text{if } be_1' \text{ then } ae_1 \text{ else } ae_2)}}
\\
\\
\infr[(2)]
{b_1 == tt}
{\rstep{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2)}{ae_1}}
\\
\\
\infr[(3)]
{b_1 == ff}
{\rstep{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2)}{ae_2}}
\end{array}
\]
Integer Addition:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1 + e_2}{e_1' + e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{n_1 + e_2}{n_1 + e_2'}}
\\
\\
\infr[$n_3 = add(n_1, n_2)$ (3)]
{-}
{\rstep{n_1 + n_2}{n_3}}
\end{array}
\]
Similarly, Integer Multiplication:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1 * e_2}{e_1' * e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{n_1 * e_2}{n_1 * e_2'}}
\\
\\
\infr[$n_3 = times(n_1, n_2)$ (3)]
{-}
{\rstep{n_1 * n_2}{n_3}}
\end{array}
\]
Boolean Logical And:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1 \ \&\&\ e_2}{e_1'\ \&\&\ e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{e_1\ \&\&\ e_2}{e_1\ \&\&\ e_2'}}
\\
\\
\infr[$b_3 = (b_1 \land b_2)$ (3)]
{-}
{\rstep{b_1\ \&\&\ b_2}{b_3}}
\end{array}
\]
Boolean Logical Or:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1\ ||\ e_2}{e_1'\ ||\ e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{e_1\ ||\ e_2}{e_1\ ||\ e_2'}}
\\
\\
\infr[$b_3 = (b_1 \lor b_2)$ (3)]
{-}
{\rstep{b_1\ ||\ b_2}{b_3}}
\end{array}
\]
Integer Equal:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1 == e_2}{e_1' == e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{e_1 == e_2}{e_1 == e_2'}}
\\
\\
\infr[$b_3 = (b_1 == b_2)$ (3)]
{-}
{\rstep{b_1 == b_2}{b_3}}
\end{array}
\]
Integer Less than:
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{e_1}{e_1'}}
{\rstep{e_1 < e_2}{e_1' < e_2}}
\\
\\
\infr[(2)]
{\rstep{e_2}{e_2'}}
{\rstep{e_1 < e_2}{e_1 < e_2'}}
\\
\\
\infr[$b_3 = (b_1 < b_2)$ (3)]
{-}
{\rstep{b_1 < b_2}{b_3}}
\end{array}
\]
\end{soln}
\item
\begin{itemize}
\item Give an alternative operational semantics for if-then-else that evaluates both bodies before evaluating
the guard
\begin{soln}
If-then-else (\textit{eager-if}):
\[
\begin{array}{rcll}
\infr[(1)]
{\rstep{ae_1}{ae_1'}}
{\rstep{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2)}{(\text{if } be_1 \text{ then } ae_1' \text{ else } ae_2)}}
\\
\\
\infr[(2)]
{\rstep{ae_2}{ae_2'}}
{\rstep{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2)}{(\text{if } be_1 \text{ then } ae_1 \text{ else } ae_2')}}
\\
\\
\infr[(3)]
{b_1 == tt}
{\rstep{(\text{if } be_1 \text{ then } n_1 \text{ else } n_2)}{n_1}}
\\
\\
\infr[(4)]
{b_1 == ff}
{\rstep{(\text{if } be_1 \text{ then } n_1 \text{ else } n_2)}{n_2}}
\end{array}
\]
\end{soln}
\item What are some reasons to prefer \textit{lazy-if} over \textit{eager-if} ?
\begin{soln}
In \textit{lazy-if}, we don't need to calculate both expression before we can get the final result. We always evaluate one bool condition, and one arithmatic expression.
\textit{Eager-if} on the other hand, requires us to always evaluate one bool condition and two arithmatic expressions. \\
Also, \textit{lazy-if} won't stuck in an expression that will never be reached, while \textit{eager-if} would always stuck if any expression is problematic.
\end{soln}
\end{itemize}
\end{enumerate}
\section{Lambda calculus (5)}
Evaluate each of the following programs until it reaches a value, or returns to the original program. Show
each step in the evaluation.
\begin{enumerate}
\item $(\lambda f \cdot \lambda x \cdot f x) (\lambda x \cdot x + 1) 5$\\
\begin{soln}
$= (\lambda x \cdot (\lambda a \cdot a+1)\ x)\ 5$ \\
$= (\lambda x \cdot x + 1)\ 5 $ \\
$= 5+1$ \\
$= 6$
\end{soln}
\item $(\lambda f \cdot \lambda x \cdot \lambda y \cdot f\ y\ x)\ (\lambda x \cdot \lambda y \cdot x-y)\ 5\ 3$ \\
\begin{soln}
$=(\lambda x \cdot \lambda y \cdot (\lambda a \cdot \lambda b \cdot a-b)\ y\ x)\ 5\ 3$ \\
$=(\lambda y \cdot (\lambda x \cdot \lambda a \cdot x - a)\ y\ 5)\ 3$ \\
$=(\lambda x \cdot \lambda y \cdot x - y)\ 3\ 5$ \\
$=3 - 5$ \\
$=-2$
\end{soln}
\item $(\lambda x \cdot x\ x)\ (\lambda x \cdot x\ x)$ \\
\begin{soln}
$=(\lambda x \cdot x\ x)\ (\lambda x \cdot x\ x)$ \\
$=(\lambda x \cdot x\ x)\ (\lambda x \cdot x\ x)$ \\
$=...$
\end{soln}
\end{enumerate}
\section{Recursion (5)}
Use the program construct $fix f. e$ we introduced to write a lambda calculus function that takes in a natural
number $n$ and returns the $n-th$ Fibonacci number $fib(n)$.
\begin{soln}
$$
fib = fix\ f.\ \lambda n.\ \text{ if } n = 1 \text{ then } 1 \text{ else } (\text{ if } n = 2 \text{ then } 1 \text{ else } f(n-1)+f(n-2))
$$
\centering \textbf{evaluating fib(3)}
$\rightarrow fix\ f.\ \lambda n.\ \text{ if } n = 1 \text{ then } 1 \text{ else } (\text{ if } n = 2 \text{ then } 1 \text{ else } f(n-1)+f(n-2))\ 3$ \\
$\rightarrow \text{ if } 3 = 1 \text{ then } 1 \text{ else } (\text{ if } 3 = 2 \text{ then } 1 \text{ else } f(3-1)+f(3-2))$ \\
$f(2) \rightarrow \text{ if } 2 = 1 \text{ then } 1 \text{ else } (\text{ if } 2 = 2 \text{ then } 1 \text{ else } f(2-1)+f(2-2)) \rightarrow 1$ \\
$f(1) \rightarrow \text{ if } 1 = 1 \text{ then } 1 \text{ else } (\text{ if } 1 = 2 \text{ then } 1 \text{ else } f(1-1)+f(1-2)) \rightarrow 1$ \\
$f(3) = f(2) + f(1) = 1+1 = 2$
\end{soln}
\clearpage % do not erase this!
\bibliographystyle{apalike}
%----------------------------------------------------------------------------------------
\end{document}

Loading…
Cancel
Save