mirror of
https://github.com/janishutz/eth-summaries.git
synced 2026-04-28 16:19:23 +02:00
[FMFP] Interpreters
This commit is contained in:
@@ -1,11 +1,17 @@
|
|||||||
-- Declaring a function. Naming using lowerCamelCase
|
-- Declaring a function. Naming using lowerCamelCase. Arguments separated by whitespace
|
||||||
-- Arguments separated by whitespace
|
-- We can omit the parenthesis in the type (they show what compiler does)
|
||||||
myFunc :: Int -> Int -> Int
|
-- The below function uses guards (boolean checks)
|
||||||
|
myFunc :: Int -> (Int -> Int)
|
||||||
myFunc x y
|
myFunc x y
|
||||||
| x > 0 = x + y
|
| x > 0 = x + y
|
||||||
| x < 0 = -x + y
|
| x < 0 = -x + y
|
||||||
|
| otherwise = 0
|
||||||
|
|
||||||
-- On compile the above function is transformed like this:
|
-- If the checks are pattern-based, use pattern matching. _ is wildcard (any value)
|
||||||
-- TODO: Transform the template into correct version
|
-- It is used when we don't need the variable. You can combine pattern-matching and guards
|
||||||
myFuncXCompiled :: Int -> Int
|
myOtherFunc :: Int -> Int -> Int
|
||||||
myFuncXCompiled x = x
|
myOtherFunc 0 _ = 0
|
||||||
|
myOtherFunc x 0 = x
|
||||||
|
myOtherFunc x y
|
||||||
|
| x > 0 = x + y
|
||||||
|
| x < 0 = -x + y
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
||||||
|
|
||||||
|
{-# HLINT ignore "Use lambda-case" #-}
|
||||||
|
{-# HLINT ignore "Use newtype instead of data" #-}
|
||||||
|
|
||||||
|
import Prelude hiding (return, (>>), (>>=))
|
||||||
|
|
||||||
|
data Parser a = Prs (String -> [(a, String)])
|
||||||
|
|
||||||
|
-- Main parser function
|
||||||
|
parse :: Parser a -> String -> [(a, String)]
|
||||||
|
parse (Prs p) = p
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- Basic parsers --
|
||||||
|
-------------------
|
||||||
|
-- Trivial failure ([] signifies parse failed)
|
||||||
|
failure :: Parser a
|
||||||
|
failure = Prs (const [])
|
||||||
|
|
||||||
|
-- Trivial success without progress
|
||||||
|
return :: a -> Parser a
|
||||||
|
return x = Prs (\inp -> [(x, inp)])
|
||||||
|
|
||||||
|
-- Trivial success with progress
|
||||||
|
item :: Parser Char
|
||||||
|
item =
|
||||||
|
Prs
|
||||||
|
( \inp -> case inp of
|
||||||
|
"" -> []
|
||||||
|
(x : xs) -> [(x, xs)]
|
||||||
|
)
|
||||||
|
|
||||||
|
----------
|
||||||
|
-- Glue --
|
||||||
|
----------
|
||||||
|
-- Apply both parsers
|
||||||
|
(|||) :: Parser a -> Parser a -> Parser a
|
||||||
|
p ||| q = Prs (\s -> parse p s ++ parse q s)
|
||||||
|
|
||||||
|
-- If first parser fails, apply second parser
|
||||||
|
(+++) :: Parser a -> Parser a -> Parser a
|
||||||
|
p +++ q =
|
||||||
|
Prs
|
||||||
|
( \s -> case parse p s of
|
||||||
|
[] -> parse q s
|
||||||
|
res -> res
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Sequencing (first parser p, then parser q)
|
||||||
|
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
|
||||||
|
p >>= g = Prs (\s -> [(u, s'') | (t, s') <- parse p s, (u, s'') <- parse (g t) s'])
|
||||||
|
|
||||||
|
-- Simple version of the above
|
||||||
|
(>>) :: Parser a -> Parser b -> Parser b
|
||||||
|
p >> q = p >>= const q
|
||||||
|
|
||||||
|
-- Parse single character with property p
|
||||||
|
sat :: (Char -> Bool) -> Parser Char
|
||||||
|
sat p = item >>= \x -> if p x then return x else failure
|
||||||
|
|
||||||
|
char :: Char -> Parser Char
|
||||||
|
char x = sat (== x)
|
||||||
|
|
||||||
|
string :: String -> Parser String
|
||||||
|
string "" = return ""
|
||||||
|
string (x : xs) = char x >> string xs >> return (x : xs)
|
||||||
|
|
||||||
|
-- 0 or more repetitions of p
|
||||||
|
many :: Parser a -> Parser [a]
|
||||||
|
many p = many1 p ||| return []
|
||||||
|
|
||||||
|
-- 1 or more repetitions of p
|
||||||
|
many1 :: Parser a -> Parser [a]
|
||||||
|
many1 p = p >>= \t -> many p >>= \ts -> return (t : ts)
|
||||||
Binary file not shown.
@@ -77,7 +77,15 @@
|
|||||||
\input{parts/02_typing/01_mini-haskell/02_further-rules.tex}
|
\input{parts/02_typing/01_mini-haskell/02_further-rules.tex}
|
||||||
\input{parts/02_typing/01_mini-haskell/03_type-inference.tex}
|
\input{parts/02_typing/01_mini-haskell/03_type-inference.tex}
|
||||||
\input{parts/02_typing/02_algebraic-data-types/00_correctness.tex}
|
\input{parts/02_typing/02_algebraic-data-types/00_correctness.tex}
|
||||||
% \input{parts/02_typing/01_mini-haskell/}
|
\input{parts/02_typing/02_algebraic-data-types/01_induction-nat-num.tex}
|
||||||
|
\input{parts/02_typing/02_algebraic-data-types/02_lists.tex}
|
||||||
|
\input{parts/02_typing/02_algebraic-data-types/03_trees.tex}
|
||||||
|
\input{parts/02_typing/02_algebraic-data-types/04_structural-induction.tex}
|
||||||
|
\input{parts/02_typing/03_interpreter/00_intro.tex}
|
||||||
|
\input{parts/02_typing/03_interpreter/01_read.tex}
|
||||||
|
\input{parts/02_typing/03_interpreter/02_eval.tex}
|
||||||
|
% \input{parts/02_typing/03_interpreter/}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,76 +13,3 @@ Or the same as a natural deduction rule:
|
|||||||
\infer2[$m$ not free in $\Gamma, P$]{\Gamma \vdash \forall n \in \N. P}
|
\infer2[$m$ not free in $\Gamma, P$]{\Gamma \vdash \forall n \in \N. P}
|
||||||
\end{prooftree}
|
\end{prooftree}
|
||||||
\]
|
\]
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{Induction over the natural numbers}
|
|
||||||
In Haskell, we can also define all the natural numbers using
|
|
||||||
\mint{haskell}+data Nat = Zero | Succ Nat deriving (Eq, Ord, Show)+
|
|
||||||
|
|
||||||
Thus the natural numbers are (isomorphic to) the set
|
|
||||||
\[
|
|
||||||
\texttt{Nat} = \{ \texttt{Zero}, \texttt{Succ Zero}, \texttt{Succ (Succ Zero)}, \ldots \}
|
|
||||||
\]
|
|
||||||
|
|
||||||
The data type provides two crucial rules for constructing members of \texttt{Nat}:
|
|
||||||
\begin{itemize}
|
|
||||||
\item $\texttt{Zero} \in \texttt{Nat}$
|
|
||||||
\item If $x \in \texttt{Nat}$, then $\texttt{Succ} x \in \texttt{Nat}$
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
The induction stated as a natural deduction rule:
|
|
||||||
\[
|
|
||||||
\begin{prooftree}
|
|
||||||
\hypo{\Gamma \vdash P[n \mapsto \texttt{Zero}]}
|
|
||||||
\hypo{\Gamma, P[n \mapsto m] \vdash P[n \mapsto \texttt{Succ}\ m]}
|
|
||||||
\infer2[$m$ not free in $\Gamma, P$]{\Gamma \vdash \forall n \in \texttt{Nat}. P}
|
|
||||||
\end{prooftree}
|
|
||||||
\]
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{Lists}
|
|
||||||
A possible data type for lists in Haskell is:
|
|
||||||
\mint{haskell}+data L t = Nil | Cons t (L t)+
|
|
||||||
|
|
||||||
A natural deduction rule for induction over lists is:
|
|
||||||
\[
|
|
||||||
\begin{prooftree}
|
|
||||||
\hypo{\Gamma \vdash P[xs \mapsto \texttt{Nil}]}
|
|
||||||
\hypo{\Gamma, P[xs \mapsto ys] \vdash P[xs \mapsto \texttt{Cons}\ y\ ys]}
|
|
||||||
\infer2[$y$, $ys$ not free in $\Gamma, P$]{\Gamma \vdash \forall xs \in \texttt{L}\ t. P}
|
|
||||||
\end{prooftree}
|
|
||||||
\]
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{Trees}
|
|
||||||
A possible data type for trees in Haskell is:
|
|
||||||
\mint{haskell}+data Tree t = Leaf | Node t (Tree t) (Tree t)+
|
|
||||||
|
|
||||||
A natural deduction rule for induction over trees is:
|
|
||||||
\[
|
|
||||||
\begin{prooftree}
|
|
||||||
\hypo{\Gamma \vdash P[x \mapsto \texttt{Leaf}]}
|
|
||||||
\hypo{\Gamma, P[x \mapsto l] \vdash P[xs \mapsto \texttt{Node}\ a\ l\ r]}
|
|
||||||
\infer2[$a$, $l$, $r$ not free in $\Gamma, P$]{\Gamma \vdash \forall x \in \texttt{Tree}\ t. P}
|
|
||||||
\end{prooftree}
|
|
||||||
\]
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{Structural Induction}
|
|
||||||
Induction is based on the structure of terms
|
|
||||||
\mint{haskell}+data T t = Leaf t | Node1 (T t) | Node2 t (T t) (T t)+
|
|
||||||
|
|
||||||
\shade{blue}{Base Case} $T_0 = \{ \texttt{Leaf}\ a \divider a \in t \}$
|
|
||||||
|
|
||||||
\shade{green}{Step Case} $T_i = T_{i - 1} \cup \{ \texttt{Node1}\ s \divider s \in T_{i - 1} \} \cup \{ \texttt{Node2}\ a\ l\ r \divider a \in t \text{ and } l, r \in T_{i - 1} \}$
|
|
||||||
|
|
||||||
A natural deduction rule structural induction is:
|
|
||||||
\[
|
|
||||||
\begin{prooftree}
|
|
||||||
\hypo{\Gamma \vdash P[x \mapsto \texttt{Leaf}\ a]}
|
|
||||||
\hypo{\Gamma, P[x \mapsto s] \vdash P[xs \mapsto \texttt{Node1}\ s]}
|
|
||||||
\hypo{\Gamma, P[x \mapsto l], P[x \mapsto r] \vdash P[ \mapsto \texttt{Node2}\ a\ l\ r]}
|
|
||||||
\infer3[$(*)$]{\Gamma \vdash \forall x \in \texttt{T}\ t. P}
|
|
||||||
\end{prooftree}
|
|
||||||
\]
|
|
||||||
(*) $a$, $l$, $r$, $s$ not free in $\Gamma, P$
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
\subsubsection{Induction over the natural numbers}
|
||||||
|
In Haskell, we can also define all the natural numbers using
|
||||||
|
\mint{haskell}+data Nat = Zero | Succ Nat deriving (Eq, Ord, Show)+
|
||||||
|
|
||||||
|
Thus the natural numbers are (isomorphic to) the set
|
||||||
|
\[
|
||||||
|
\texttt{Nat} = \{ \texttt{Zero}, \texttt{Succ Zero}, \texttt{Succ (Succ Zero)}, \ldots \}
|
||||||
|
\]
|
||||||
|
|
||||||
|
The data type provides two crucial rules for constructing members of \texttt{Nat}:
|
||||||
|
\begin{itemize}
|
||||||
|
\item $\texttt{Zero} \in \texttt{Nat}$
|
||||||
|
\item If $x \in \texttt{Nat}$, then $\texttt{Succ} x \in \texttt{Nat}$
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
The induction stated as a natural deduction rule:
|
||||||
|
\[
|
||||||
|
\begin{prooftree}
|
||||||
|
\hypo{\Gamma \vdash P[n \mapsto \texttt{Zero}]}
|
||||||
|
\hypo{\Gamma, P[n \mapsto m] \vdash P[n \mapsto \texttt{Succ}\ m]}
|
||||||
|
\infer2[$m$ not free in $\Gamma, P$]{\Gamma \vdash \forall n \in \texttt{Nat}. P}
|
||||||
|
\end{prooftree}
|
||||||
|
\]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
\subsubsection{Lists}
|
||||||
|
A possible data type for lists in Haskell is:
|
||||||
|
\mint{haskell}+data L t = Nil | Cons t (L t)+
|
||||||
|
|
||||||
|
A natural deduction rule for induction over lists is:
|
||||||
|
\[
|
||||||
|
\begin{prooftree}
|
||||||
|
\hypo{\Gamma \vdash P[xs \mapsto \texttt{Nil}]}
|
||||||
|
\hypo{\Gamma, P[xs \mapsto ys] \vdash P[xs \mapsto \texttt{Cons}\ y\ ys]}
|
||||||
|
\infer2[$y$, $ys$ not free in $\Gamma, P$]{\Gamma \vdash \forall xs \in \texttt{L}\ t. P}
|
||||||
|
\end{prooftree}
|
||||||
|
\]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
\subsubsection{Trees}
|
||||||
|
A possible data type for trees in Haskell is:
|
||||||
|
\mint{haskell}+data Tree t = Leaf | Node t (Tree t) (Tree t)+
|
||||||
|
|
||||||
|
A natural deduction rule for induction over trees is:
|
||||||
|
\[
|
||||||
|
\begin{prooftree}
|
||||||
|
\hypo{\Gamma \vdash P[x \mapsto \texttt{Leaf}]}
|
||||||
|
\hypo{\Gamma, P[x \mapsto l] \vdash P[xs \mapsto \texttt{Node}\ a\ l\ r]}
|
||||||
|
\infer2[$a$, $l$, $r$ not free in $\Gamma, P$]{\Gamma \vdash \forall x \in \texttt{Tree}\ t. P}
|
||||||
|
\end{prooftree}
|
||||||
|
\]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
\subsubsection{Structural Induction}
|
||||||
|
Induction is based on the structure of terms
|
||||||
|
\mint{haskell}+data T t = Leaf t | Node1 (T t) | Node2 t (T t) (T t)+
|
||||||
|
|
||||||
|
\shade{blue}{Base Case} $T_0 = \{ \texttt{Leaf}\ a \divider a \in t \}$
|
||||||
|
|
||||||
|
\shade{green}{Step Case} $T_i = T_{i - 1} \cup \{ \texttt{Node1}\ s \divider s \in T_{i - 1} \} \cup \{ \texttt{Node2}\ a\ l\ r \divider a \in t \text{ and } l, r \in T_{i - 1} \}$
|
||||||
|
|
||||||
|
A natural deduction rule structural induction is:
|
||||||
|
\[
|
||||||
|
\begin{prooftree}
|
||||||
|
\hypo{\Gamma \vdash P[x \mapsto \texttt{Leaf}\ a]}
|
||||||
|
\hypo{\Gamma, P[x \mapsto s] \vdash P[xs \mapsto \texttt{Node1}\ s]}
|
||||||
|
\hypo{\Gamma, P[x \mapsto l], P[x \mapsto r] \vdash P[ \mapsto \texttt{Node2}\ a\ l\ r]}
|
||||||
|
\infer3[$(*)$]{\Gamma \vdash \forall x \in \texttt{T}\ t. P}
|
||||||
|
\end{prooftree}
|
||||||
|
\]
|
||||||
|
(*) $a$, $l$, $r$, $s$ not free in $\Gamma, P$
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
\newpage
|
||||||
|
\subsection{Interpreters}
|
||||||
|
Interpreters are prevalent in programming languages, database systems, text processors, HDLs, search engines, etc.
|
||||||
|
|
||||||
|
They are in concept very simple, as they perform three steps read, evaluate, print.
|
||||||
|
|
||||||
|
The implementation of one however is not trivial by any stretch of the imagination.
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
\subsubsection{Read step}
|
||||||
|
During this step, text is turned from text into a more easily handlable format
|
||||||
|
|
||||||
|
|
||||||
|
\paragraph{Lexical Analysis}
|
||||||
|
During lexical analysis, the input is turned into tokens.
|
||||||
|
For example: The source code is \texttt{position := initial + rate + 60}
|
||||||
|
|
||||||
|
The translation is:
|
||||||
|
\begin{multicols}{2}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Identifier \texttt{position}
|
||||||
|
\item Assignment symbol \texttt{:=}
|
||||||
|
\item Identifier \texttt{initial}
|
||||||
|
\item Addition symbol \texttt{+}
|
||||||
|
\item Identifier \texttt{rate}
|
||||||
|
\item Addition symbol \texttt{+}
|
||||||
|
\item Number \texttt{60}
|
||||||
|
\end{enumerate}
|
||||||
|
\end{multicols}
|
||||||
|
|
||||||
|
It also removes whitespaces and comments
|
||||||
|
|
||||||
|
|
||||||
|
\paragraph{Parsing}
|
||||||
|
The tokens are then turned into an abstract syntax tree.
|
||||||
|
|
||||||
|
The syntax is specified by a grammar such as:
|
||||||
|
\begin{align*}
|
||||||
|
Expr & ::= Identifier \divider Number \divider Expr\; \texttt{`+`}\; Expr \\
|
||||||
|
Assign & ::= Identifier\; \texttt{`:=`}\; Expr
|
||||||
|
\end{align*}
|
||||||
|
|
||||||
|
This can also be represented as a haskell type:
|
||||||
|
\begin{code}{haskell}
|
||||||
|
data Expr = Identifier Ident | Number Num | Plus Expr Expr
|
||||||
|
data Assign = Assignment Ident Expr
|
||||||
|
type Ident = String
|
||||||
|
type Num = Int
|
||||||
|
\end{code}
|
||||||
|
|
||||||
|
Since some to be parsed statements are more complex to parse, we may do combinatory parsing.
|
||||||
|
|
||||||
|
This is much more powerful as it can handle ambiguous grammars typically found in real programming languages.
|
||||||
|
|
||||||
|
We can use for example these parser combinators:
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\inputcode{haskell}{code/10_parser.hs}
|
||||||
|
|
||||||
|
These are just some of the functions defined.
|
||||||
|
You can find a full mini-haskell and lambda-calculus parser on CodeExpert (at the time of writing this that was the case at least)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
\newpage
|
||||||
|
\subsection{Evaluation}
|
||||||
|
Evaluation is then done using tree traversal as we have already seen in the haskell section.
|
||||||
Reference in New Issue
Block a user