Skip to content

Commit

Permalink
Week5 Ex 1, 2, 3 ,4
Browse files Browse the repository at this point in the history
  • Loading branch information
Tien committed Sep 7, 2019
1 parent e0f6aff commit 9a6ab5a
Show file tree
Hide file tree
Showing 14 changed files with 432 additions and 0 deletions.
3 changes: 3 additions & 0 deletions cis194/week5/tien/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.stack-work/
tien.cabal
*~
3 changes: 3 additions & 0 deletions cis194/week5/tien/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Changelog for tien

## Unreleased changes
30 changes: 30 additions & 0 deletions cis194/week5/tien/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright Tien (c) 2019

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of Tien nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 change: 1 addition & 0 deletions cis194/week5/tien/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# tien
2 changes: 2 additions & 0 deletions cis194/week5/tien/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
5 changes: 5 additions & 0 deletions cis194/week5/tien/app/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Main where


main :: IO ()
main = putStr "main hs"
49 changes: 49 additions & 0 deletions cis194/week5/tien/package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: tien
version: 0.1.0.0
github: "tienwei/tien"
license: BSD3
author: "Tien"
maintainer: "tienlindev@gmail.com"
copyright: "2019 Tien"

extra-source-files:
- README.md
- ChangeLog.md

# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web

# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/tienwei/tien#readme>

dependencies:
- base >= 4.7 && < 5
- hspec

library:
source-dirs: src

executables:
tien-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- tien

tests:
tien-test:
main: CalcSpec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- tien
68 changes: 68 additions & 0 deletions cis194/week5/tien/src/Calc.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE ViewPatterns #-}

module Calc where

import ExprT
import Parser

-- Exercise 1 --
eval :: ExprT -> Integer
eval (Lit a) = a
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b

-- Exercise 2 --
evalStr :: String -> Maybe Integer
evalStr (parseExp Lit Add Mul -> justExpr) = eval <$> justExpr

-- Exercise 3 --
class Expr a where
lit :: Integer -> a
add :: a -> a -> a
mul :: a -> a -> a

instance Expr ExprT where
lit a = Lit a
add a b = Add a b
mul a b = Mul a b

-- Exercise 4 --
newtype MinMax =
MinMax Integer
deriving (Eq, Show)

newtype Mod7 =
Mod7 Integer
deriving (Eq, Show)

instance Expr Integer where
lit a = a
add a b = a + b
mul a b = a * b

instance Expr Bool where
lit a = a > 0
add a b = a || b
mul a b = a && b

instance Expr MinMax where
lit a = MinMax a
add (MinMax a) (MinMax b) = MinMax $ max a b
mul (MinMax a) (MinMax b) = MinMax $ min a b

instance Expr Mod7 where
lit a = Mod7 $ mod 7 a
add (Mod7 a) (Mod7 b) = Mod7 $ lit a + lit b
mul (Mod7 a) (Mod7 b) = Mod7 $ lit a * lit b

testExp :: Expr a => Maybe a
testExp = parseExp lit add mul "(3 * -4) + 5"

testInteger = testExp :: Maybe Integer

testBool = testExp :: Maybe Bool

testMM = testExp :: Maybe MinMax

testSat = testExp :: Maybe Mod7
6 changes: 6 additions & 0 deletions cis194/week5/tien/src/ExprT.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module ExprT where

data ExprT = Lit Integer
| Add ExprT ExprT
| Mul ExprT ExprT
deriving (Show, Eq)
105 changes: 105 additions & 0 deletions cis194/week5/tien/src/Parser.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
-- Applicative parser for infix arithmetic expressions without any
-- dependency on hackage. Builds an explicit representation of the
-- syntax tree to fold over using client-supplied semantics.
module Parser (parseExp) where
import Control.Applicative hiding (Const)
import Control.Arrow
import Data.Char
import Data.Monoid
import Data.List (foldl')

-- Building block of a computation with some state of type @s@
-- threaded through it, possibly resulting in a value of type @r@
-- along with some updated state.
newtype State s r = State (s -> Maybe (r, s))

-- Expressions
data Expr = Const Integer
| Add Expr Expr
| Mul Expr Expr
deriving Show

instance Functor (State s) where
fmap f (State g) = State $ fmap (first f) . g

instance Applicative (State s) where
pure x = State $ \s -> Just (x, s)
State f <*> State g = State $ \s ->
case f s of
Nothing -> Nothing
Just (r, s') -> fmap (first r) . g $ s'

instance Alternative (State s) where
empty = State $ const Nothing
State f <|> State g = State $ \s -> maybe (g s) Just (f s)

-- A parser threads some 'String' state through a computation that
-- produces some value of type @a@.
type Parser a = State String a

-- Parse one numerical digit.
digit :: Parser Integer
digit = State $ parseDigit
where parseDigit [] = Nothing
parseDigit s@(c:cs)
| isDigit c = Just (fromIntegral $ digitToInt c, cs)
| otherwise = Nothing

-- Parse an integer. The integer may be prefixed with a negative sign.
num :: Parser Integer
num = maybe id (const negate) <$> optional (char '-') <*> (toInteger <$> some digit)
where toInteger = foldl' ((+) . (* 10)) 0

-- Parse a single white space character.
space :: Parser ()
space = State $ parseSpace
where parseSpace [] = Nothing
parseSpace s@(c:cs)
| isSpace c = Just ((), cs)
| otherwise = Nothing

-- Consume zero or more white space characters.
eatSpace :: Parser ()
eatSpace = const () <$> many space

-- Parse a specific character.
char :: Char -> Parser Char
char c = State parseChar
where parseChar [] = Nothing
parseChar (x:xs) | x == c = Just (c, xs)
| otherwise = Nothing

-- Parse one of our two supported operator symbols.
op :: Parser (Expr -> Expr -> Expr)
op = const Add <$> (char '+') <|> const Mul <$> (char '*')

-- Succeed only if the end of the input has been reached.
eof :: Parser ()
eof = State parseEof
where parseEof [] = Just ((),[])
parseEof _ = Nothing

-- Parse an infix arithmetic expression consisting of integers, plus
-- signs, multiplication signs, and parentheses.
parseExpr :: Parser Expr
parseExpr = eatSpace *>
((buildOp <$> nonOp <*> (eatSpace *> op) <*> parseExpr) <|> nonOp)
where buildOp x op y = x `op` y
nonOp = char '(' *> parseExpr <* char ')' <|> Const <$> num

-- Run a parser over a 'String' returning the parsed value and the
-- remaining 'String' data.
execParser :: Parser a -> String -> Maybe (a, String)
execParser (State f) = f

-- Run a parser over a 'String' returning the parsed value.
evalParser :: Parser a -> String -> Maybe a
evalParser = (fmap fst .) . execParser

-- Parse an arithmetic expression using the supplied semantics for
-- integral constants, addition, and multiplication.
parseExp :: (Integer -> a) -> (a -> a -> a) -> (a -> a -> a) -> String -> Maybe a
parseExp con add mul = (convert <$>) . evalParser (parseExpr <* eof)
where convert (Const x) = con x
convert (Add x y) = add (convert x) (convert y)
convert (Mul x y) = mul (convert x) (convert y)
58 changes: 58 additions & 0 deletions cis194/week5/tien/src/StackVM.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module StackVM (StackVal(..), StackExp(..), Stack, Program, stackVM) where

-- Values that may appear in the stack. Such a value will also be
-- returned by the stackVM program execution function.
data StackVal = IVal Integer | BVal Bool | Void deriving Show

-- The various expressions our VM understands.
data StackExp = PushI Integer
| PushB Bool
| Add
| Mul
| And
| Or
deriving Show

type Stack = [StackVal]
type Program = [StackExp]

-- Execute the given program. Returns either an error message or the
-- value on top of the stack after execution.
stackVM :: Program -> Either String StackVal
stackVM = execute []

errType :: String -> Either String a
errType op = Left $ "Encountered '" ++ op ++ "' opcode with ill-typed stack."

errUnderflow :: String -> Either String a
errUnderflow op = Left $ "Stack underflow with '" ++ op ++ "' opcode."

-- Execute a program against a given stack.
execute :: Stack -> Program -> Either String StackVal
execute [] [] = Right Void
execute (s:_) [] = Right s

execute s (PushI x : xs) = execute (IVal x : s) xs
execute s (PushB x : xs) = execute (BVal x : s) xs

execute (IVal s1 : IVal s2 : ss) (Add : xs) = execute (s':ss) xs
where s' = IVal (s1 + s2)
execute (_:_:_) (Add:_) = errType "Add"
execute _ (Add:_) = errUnderflow "Add"

execute (IVal s1:IVal s2:ss) (Mul : xs) = execute (s':ss) xs
where s' = IVal (s1 * s2)
execute (_:_:_) (Mul:_) = errType "Mul"
execute _ (Mul:_) = errUnderflow "Mul"

execute (BVal s1:BVal s2:ss) (And : xs) = execute (s':ss) xs
where s' = BVal (s1 && s2)
execute (_:_:_) (And:_) = errType "And"
execute _ (And:_) = errUnderflow "And"

execute (BVal s1 : BVal s2 : ss) (Or : xs) = execute (s':ss) xs
where s' = BVal (s1 || s2)
execute (_:_:_) (Or:_) = errType "Or"
execute _ (Or:_) = errUnderflow "Or"

test = stackVM [PushI 3, PushI 5, Add]
Loading

0 comments on commit 9a6ab5a

Please sign in to comment.