{
    "componentChunkName": "component---src-pages-markdown-remark-frontmatter-slug-jsx",
    "path": "/haskell-interpreter-imp/",
    "result": {"data":{"markdownRemark":{"html":"<p><a href=\"https://github.com/fsankratz/haskell-interpreter-imp\">imp.hs auf GitHub</a></p>\n<p>Unser Informatik-Prof hat uns die Bonusaufgabe gegeben, einen Interpreter in Haskell für eine imperative Programmiersprache namens ”IMP“ in der funktionalen Programmiersprache Haskell zu schreiben.</p>\n<p>Um die Aufgabe anzugehen habe ich mir zunächst angeschaut, ob es dazu schon Lösungen im Netz gibt. Ich bin dann auf ein <a href=\"https://www.youtube.com/watch?v=lDWTNVfsvbk\">Video von James Hobson</a> gestoßen, in dem erklärt wird wie man einen Interpreter für eine sehr simple imperative Programmiersprache basteln kann. Eine andere tolle Erklärung wie man die Aufgabe ohne Monaden lösen kann liefert <a href=\"https://stackoverflow.com/questions/16970431/implementing-a-language-interpreter-in-haskell\">Stefan Holdermans auf StackOverflow</a>.</p>\n<p>Die in unserer Vorlesung präsentierte Sprache ”IMP“ unterscheidet sich von den hier verwendeten nur in wenigen Punkten:</p>\n<ol>\n<li>IMP soll nicht nur numerische Ausdrücke, sondern auch boole’sche evaluieren können und</li>\n<li>IMP soll relationale (<code>=</code>, <code>></code>) und boole’sche (<code>&#x26;&#x26;</code>, <code>||</code>, <code>¬</code>) Operatoren interpretieren können und</li>\n<li>IMP soll eine If-Anweisung bereitstellen.</li>\n</ol>\n<p>Doch wie sich zeigte ist die Implementierung von Punkt 1. nicht trivial. Um zu verstehen wieso, schauen wir uns die Definition eines Ausdruckes (hier <code>Exp</code>) in dem Code<sup id=\"fnref-1\"><a href=\"#fn-1\" class=\"footnote-ref\">1</a></sup> von Stafan Holdermans an:</p>\n<pre><code>infixl 6 :+:, :-:\ninfixl 7 :*:, :/:\ndata Exp\n  = C Int        -- constant                                                     \n  | V Var        -- variable                                                     \n  | Exp :+: Exp  -- addition                                                     \n  | Exp :-: Exp  -- subtraction                                                  \n  | Exp :*: Exp  -- multiplication                                               \n  | Exp :/: Exp  -- division\n</code></pre>\n<p>Hier kann ein Ausdruck entweder eine verknüpfung von mehreren Ausdrücken, eine Variable oder eine Konstante sein. Allerdings nimmt der Typ-Konstruktor <code>C</code> nur einen <code>Int</code> entgegen. Zunächst wollte ich einen neuen Datentypen erstellen, der entweder einen <code>Int</code> oder einen <code>Bool</code> annimmt. Diese Idee hat sich als schwierig herausgestellt, da bei der Auswertung der Ausdrücke dann immer geprüft werden müsste welchen Typ diese haben. Anstatt dessen habe ich mich daran erinnert, dass boole’sche Ausdrücke ja in den allermeisten Programmiersprachen sowieso als Zahlen, nämlich <code>1 -> True</code> und <code>0 -> False</code> darstellt werden. Damit hat sich Punkt 1 geklärt. Für die relationalen und boole’schen Operatoren habe ich die folgenden Zeilen hinzugefügt:</p>\n<pre><code>infixl 5 :=:, :>:, :||:, :&#x26;&#x26;:\n...\n  | Exp :=: Exp    -- equality\n  | Exp :>: Exp    -- ordering\n  | Exp :||: Exp   -- logical or\n  | Exp :&#x26;&#x26;: Exp   -- logical and\n  | Not Exp        -- negation\n</code></pre>\n<p>Um diese Ausdrücke auszuwerden, implementieren wir eine Funktion <code>eval</code> die einen Ausdruck und einen Zustand nimmt und einen Wert zurückgibt:</p>\n<pre><code>eval :: Exp -> Store -> Val\n...\neval (e1 :=: e2) r  = if eval e1 r == eval e2 r then 1 else 0 \neval (e1 :>: e2) r  = if eval e1 r > eval e2 r then 1 else 0 \neval (e1 :&#x26;&#x26;: e2) r  = if eval e1 r == 1 &#x26;&#x26; eval e2 r == 1 then 1 else 0 \neval (e1 :||: e2) r  = if eval e1 r == 1 || eval e2 r == 1 then 1 else 0 \neval (Not e) r  = if eval e r == 1 then 0 else 1\n</code></pre>\n<p>An dieser Stelle wird Pattern-Matching genutzt um die verschiedenn Operationen voneinander zu trennen und indiviuell auszuwerten. Dabei werden die neuen Operatoren unter dem Mantel einfach zu den Haskell-eignen übersetzt.</p>\n<p>Ähnlich kann man vorgehen um eine If-Anweisung in unserer fiktiven Sprache zu definieren. Wir beginnen damit den Typ-Konstruktor <code>If</code> zu unserer Liste von Anweisungen (hier <code>Stmt</code>) hinzuzufügen:</p>\n<pre><code>data Stmt \n...\n  | If Exp Stmt Stmt -- conditional\n</code></pre>\n<p>Entsprechend definieren wir eine Funktion <code>exec</code>, die eine Anweisung und einen Zustand nimmt und den darauffolgenden Zustand zurückgibt:</p>\n<pre><code>exec :: Stmt -> Store -> Store \n...\nexec (If e1 s1 s2) r = if eval e1 r == 1 then exec s1 r else exec s2 r \n</code></pre>\n<p>Da ein imperatives Programm nichts anderes ist als eine aneinanderreihung von Anweisungen hat die Funktion <code>run</code>, die unser Programm ausführt den Typ <code>Prog -> Store -> Store</code>. Dabei ist <code>Prog</code> ein Typ-Alias für <code>[Stmt]</code>. Wir führen eine Aktion in einer “Start-Welt” aus und erhalten dann eine veränderte neue Welt. Die Funktion sieht wie folgt aus:</p>\n<pre><code>run :: Prog -> Store -> Store\nrun p r = nubBy ((==) `on` fst) $ exec p r\n</code></pre>\n<p>In unserer neuen Sprache IMP können wir jetzt zum Beispiel ein Programm schreiben, dass die Fakultät einer Zahl n berechnet:</p>\n<pre><code>fac' :: Prog\nfac' = Seq\n  [ \"x\" := C 1\n  , \"i\" := C 1\n  , (While (V \"n\" :>: V \"i\") (Seq\n    [ \"x\" := V \"x\" :*: V \"i\"\n    , \"i\" := V \"i\" :+: C 1\n    ]))\n  ]\n</code></pre>\n<p>Wenn wir unseren Code in GHCi laden, liefert uns der Befehl <code>lookup \"x\" $ run fac' [(\"n\", 5)]</code> das Ergebnis <code>120</code>, genau die Fakultät von 5. Perfekt!</p>\n<div class=\"footnotes\">\n<hr>\n<ol>\n<li id=\"fn-1\">Stefan Holdermans, License <a href=\"https://creativecommons.org/licenses/by-sa/4.0/\">CC-BY-SA</a><a href=\"#fnref-1\" class=\"footnote-backref\">↩</a></li>\n</ol>\n</div>","excerpt":"imp.hs auf GitHub Unser Informatik-Prof hat uns die Bonusaufgabe gegeben, einen Interpreter in Haskell für eine imperative…","frontmatter":{"slug":"haskell-interpreter-imp","title":"Interpreter für eine einfache imperative Programmiersprache in Haskell","thumbnail":{"childImageSharp":{"gatsbyImageData":{"layout":"constrained","backgroundColor":"#b8a808","images":{"fallback":{"src":"/static/c8967d7c512a12fa52bb0a5996c9d581/3b307/imp.jpg","srcSet":"/static/c8967d7c512a12fa52bb0a5996c9d581/d9f52/imp.jpg 200w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/0132d/imp.jpg 400w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/3b307/imp.jpg 800w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/1e618/imp.jpg 1600w","sizes":"(min-width: 800px) 800px, 100vw"},"sources":[{"srcSet":"/static/c8967d7c512a12fa52bb0a5996c9d581/b9488/imp.webp 200w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/47294/imp.webp 400w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/89c0d/imp.webp 800w,\n/static/c8967d7c512a12fa52bb0a5996c9d581/94e9c/imp.webp 1600w","type":"image/webp","sizes":"(min-width: 800px) 800px, 100vw"}]},"width":800,"height":533}}}}}},"pageContext":{"id":"da105da2-a660-5df0-8f74-aac2b403b056","frontmatter__slug":"haskell-interpreter-imp","__params":{"frontmatter__slug":"haskell-interpreter-imp"}}},
    "staticQueryHashes": ["27537384"]}