Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Your use of an accumulator is making the output unnecessarily strict. Accumulators are good in strict languages because they allow tail recursion; in lazy languages, they are unnecessary (and often bad). I've rewritten your code below to not use one.</p> <pre><code>module Interpreter where -------------------------------------------------------------------- type Id = [Char] type Output = [Char] type Value = Int type Table = [(Id, Value)] data Stm = CompoundStm Stm Stm | AssignStm Id Exp | PrintStm ExpList deriving Show data Exp = IdExp Id | NumExp Value | OpExp Exp Op Exp | EseqExp Stm Exp deriving Show data ExpList = PairExpList Exp ExpList | LastExpList Exp deriving Show data Op = Plus | Minus | Times | Div deriving Show example :: Stm example = CompoundStm (AssignStm "a" (OpExp (NumExp 5) Plus (NumExp 3))) (CompoundStm (AssignStm "b" (EseqExp (PrintStm (PairExpList (IdExp "a") (LastExpList (OpExp (IdExp "a") Minus (NumExp 1))))) (OpExp (NumExp 10) Times (IdExp "a")))) (PrintStm (LastExpList (IdExp "b")))) -------------------------------------------------------------------- tableUpdate :: Table -&gt; Id -&gt; Value -&gt; Table tableUpdate t i v = (i,v):t tableLookup :: Table -&gt; Id -&gt; Value tableLookup ((x,v):t) i | x == i = v tableLookup ((x,v):t) i | x /= i = tableLookup t i -------------------------------------------------------------------- execute :: Stm -&gt; IO() execute s = putStr ((\(o,_)-&gt;o) (interpStm s [])) interpStm :: Stm -&gt; Table -&gt; (Output, Table) interpStm (CompoundStm l r) t = let (o, t') = interpStm l t in let (o', t'') = interpStm r t' in (o ++ o', t'') interpStm (PrintStm el) t = interpExpList el t interpStm (AssignStm i e) t = let (v, o, t') = interpExp e t in (o, tableUpdate t' i v) interpExp :: Exp -&gt; Table -&gt; (Value, Output, Table) interpExp (IdExp i) t = (tableLookup t i, "", t) interpExp (NumExp v) t = (v, "", t) interpExp (EseqExp s e) t = let (o, t') = interpStm s t in let (v, o', t'') = interpExp e t' in (v, o ++ o', t'') interpExp (OpExp l op r) t = let (v, o, t') = interpExp l t in let (v', o', t'') = interpExp r t' in (g v op v', o++o', t'') where g v1 Plus v2 = v1 + v2 g v1 Minus v2 = v1 - v2 g v1 Times v2 = v1 * v2 g v1 Div v2 = v1 `div` v2 interpExpList :: ExpList -&gt; Table -&gt; (Output, Table) interpExpList (LastExpList e) t = let (v, o, t') = interpExp e t in (o ++ show v ++ "\n", t') interpExpList (PairExpList e el) t = let (v, o, t') = interpExp e t in let (o', t'') = interpExpList el t' in (o ++ show v ++ " " ++ o', t') </code></pre> <p>With this change, the output comes properly lazily.</p> <p>You'll notice that there's a <em>lot</em> of repeated code of the form <code>let (value, newTable) = f oldTable in ...</code>, and a <em>lot</em> of repeated code of the form <code>let (output, value) = exp; (moreOutput, value) = exp2 in (output ++ moreOutput, exp3)</code>. There are a couple of monads that write this code for you! Here's an example using StateT Table (Writer Output):</p> <pre><code>module Interpreter where import Control.Monad.Writer import Control.Monad.State import Data.Maybe -------------------------------------------------------------------- type Id = [Char] type Output = [Char] type Value = Int type Table = [(Id, Value)] data Stm = CompoundStm Stm Stm | AssignStm Id Exp | PrintStm ExpList deriving Show data Exp = IdExp Id | NumExp Value | OpExp Exp Op Exp | EseqExp Stm Exp deriving Show data ExpList = PairExpList Exp ExpList | LastExpList Exp deriving Show data Op = Plus | Minus | Times | Div deriving Show type InterpreterM = StateT Table (Writer Output) example :: Stm example = CompoundStm (AssignStm "a" (OpExp (NumExp 5) Plus (NumExp 3))) (CompoundStm (AssignStm "b" (EseqExp (PrintStm (PairExpList (IdExp "a") (LastExpList (OpExp (IdExp "a") Minus (NumExp 1))))) (OpExp (NumExp 10) Times (IdExp "a")))) (PrintStm (LastExpList (IdExp "b")))) -------------------------------------------------------------------- tableUpdate :: Id -&gt; Value -&gt; InterpreterM () tableUpdate i v = modify ((i,v):) tableLookup :: Id -&gt; InterpreterM Value tableLookup i = gets (fromJust . lookup i) -------------------------------------------------------------------- execute :: Stm -&gt; IO () execute s = putStr . execWriter $ evalStateT (interpStm s) [] interpStm :: Stm -&gt; InterpreterM () interpStm (CompoundStm l r) = interpStm l &gt;&gt; interpStm r interpStm (PrintStm el) = interpExpList el interpStm (AssignStm i e) = interpExp e &gt;&gt;= tableUpdate i interpExp :: Exp -&gt; InterpreterM Value interpExp (IdExp i) = tableLookup i interpExp (NumExp v) = return v interpExp (EseqExp s e) = interpStm s &gt;&gt; interpExp e interpExp (OpExp l op r) = liftM2 (g op) (interpExp l) (interpExp r) where g Plus v1 v2 = v1 + v2 g Minus v1 v2 = v1 - v2 g Times v1 v2 = v1 * v2 g Div v1 v2 = v1 `div` v2 interpExpList :: ExpList -&gt; InterpreterM () interpExpList (LastExpList e) = interpExp e &gt;&gt;= \v -&gt; tell (show v ++ "\n") interpExpList (PairExpList e el) = interpExp e &gt;&gt;= \v -&gt; tell (show v ++ " ") &gt;&gt; interpExpList el </code></pre> <p>There are plenty of other changes that could be suggested from here, but hopefully you agree that this final form is much, much nicer to read than the previous one.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload