Skip to content

Instantly share code, notes, and snippets.

@nelsonni
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nelsonni/361e64eca8de2578c9ce to your computer and use it in GitHub Desktop.
Save nelsonni/361e64eca8de2578c9ce to your computer and use it in GitHub Desktop.
CS381 Homework #2
-- Hugh McDonald (mcdonalh)
-- Faith Steltzer (steltzef)
-- Nick Nelson (nelsonni)
--
-- CS 381: Homework 2
-- 4.23.15
module HW2 where
import Prelude hiding (Num)
import Data.List
-- Grammar for MiniLogo:
--
-- num ::= (any natural number)
-- var ::= (any variable name)
-- macro ::= (any macro name)
-- prog ::= epsilon | cmd ; prog sequence of commands
-- mode ::= `down` | `up` pen status
-- expr ::= var variable reference
-- | num literal number
-- | expr `+` expr addition expression
-- cmd ::= `pen` mode change pen mode
-- | move `(` expr, expr `)` move pen to a new position
-- | define macro `(` var* `)` { prog } define a macro
-- | call macro `(` expr* `)` invoke a macro
-- 1. Define the abstract syntax of MiniLogo as a set of Haskell data types.
type Num = Int
type Var = String
type Macro = String
type Prog = [Cmd]
data Mode = Down
| Up
deriving (Eq,Show)
data Expr = Ref Var
| Lit Num
| Add Expr Expr
deriving (Eq,Show)
data Cmd = Pen Mode
| Move Expr Expr
| Define Macro [Var] Prog
| Call Macro [Expr]
deriving (Eq,Show)
-- 2. Define a MiniLogo macro `line (x1,y1,x2,y2)` that (starting from anywhere on the canvas)
-- draws a line segment from (x1,y1) to (x2,y2).
--
-- define line (x1,y1,x2,y2) {
-- pen up; move (x1,y1);
-- pen down; move (x2,y2);
-- }
line :: Cmd
line = Define "line"
["x1", "y1", "x2", "y2"]
[Pen Up, Move (Ref "x1") (Ref "y1"), Pen Down, Move (Ref "x2") (Ref "y2")]
-- 3. Using the `line` macro you just defined to define a new MiniLogo macro `nix (x,y,w,h)`
-- that draws a big "X" of width `w` and height `h`, starting from position `(x,y)`.
--
-- define nix (x,y,w,h) {
-- line (x,y,x+w,y+h);
-- line (x,y+h,x+w,y);
-- }
nix :: Cmd
nix = Define "nix"
["x", "y", "w", "h"]
[ Call "line" [(Ref "x"), (Ref "y"), (Add (Ref "x") (Ref "w")), (Add (Ref "y") (Ref "h"))]
, Call "line" [(Ref "x"), (Add (Ref "y") (Ref "h")), (Add (Ref "x") (Ref "w")), (Ref "y")] ]
-- 4. Define a Haskell function `steps :: Int -> Prog` that constructs a MiniLogo program that
-- draws a staircase of `n` steps starting from `(0,0)`.
steps :: Int -> Prog
steps 0 = [Pen Up, Move (Lit 0) (Lit 0), Pen Down]
steps n = steps (pred n) ++ [Move (Lit (pred n)) (Lit n)] ++ [Move (Lit n) (Lit n)]
-- 5. Define a Haskell function `macros :: Prog -> [Macro]` that returns a list of the names
-- of all of the macros that are defined anywhere in a given MiniLogo program.
macros :: Prog -> [Macro]
macros [] = []
macros (x:xs) = if (ismacros x) == True then extractmacros x : macros xs else macros xs
extractmacros :: Cmd -> Macro
extractmacros (Define m v p) = m
ismacros :: Cmd -> Bool
ismacros (Define m v p) = True
ismacros _ = False
-- 6. Define a Haskell function `pretty :: Prog -> String` that pretty-prints a MiniLogo program.
pretty :: Prog -> String
pretty [] = []
pretty (x:xs) = prettyCmd x ++ pretty xs
prettyCmd :: Cmd -> String
prettyCmd (Define x y z) = "define " ++ x ++ " (" ++ prettyVar y ++ ") {\n" ++ pretty z ++ "}\n"
prettyCmd (Call x y) = "call " ++ x ++ " (" ++ concat (intersperse "," (map prettyExpr y)) ++ ");\n"
prettyCmd (Pen Down) = "pen down;\n"
prettyCmd (Pen Up) = "pen up;\n"
prettyCmd (Move x y) = "move (" ++ prettyExpr x ++ "," ++ prettyExpr y ++ ");\n"
prettyExpr :: Expr -> String
prettyExpr (Ref x) = x
prettyExpr (Lit x) = show x
prettyExpr (Add x y) = (prettyExpr x) ++ "+" ++ (prettyExpr y)
prettyVar :: [Var] -> String
prettyVar [] = []
prettyVar [x] = x
prettyVar (x:xs) = x ++ ", " ++ prettyVar xs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment