1
0
mirror of https://github.com/ikoHSE/sc-task-3.git synced 2024-10-05 20:47:58 +03:00

Initial commit

This commit is contained in:
iko 2020-05-03 19:04:47 +03:00
parent f15e203db2
commit 728d38cb11
3 changed files with 310 additions and 3 deletions

3
.gitignore vendored
View File

@ -21,7 +21,8 @@ cabal.project.local
cabal.project.local~
.HTF/
.ghc.environment.*
*.cabal
.DS_Store
.idea/
*.dump-hi
*.lock
*.iml

View File

@ -1,3 +1,270 @@
module Task
(
) where
( ErrorState (..),
get,
put,
throwError,
modify,
BFState (..),
BFError (..),
BFMonad,
readInput,
writeOutput,
CommandResult (..),
shiftCommandR,
shiftCommandL,
shiftDataR,
shiftDataL,
readData,
writeData,
executeCommand,
evaluateProgram,
executeProgram,
)
where
-- ____ _____ _ _ _
-- | __ )| ___| (_)_ __ | |_ ___ _ __ _ __ _ __ ___| |_ ___ _ __
-- | _ \| |_ | | '_ \| __/ _ \ '__| '_ \| '__/ _ \ __/ _ \ '__|
-- | |_) | _| | | | | | || __/ | | |_) | | | __/ || __/ |
-- |____/|_| |_|_| |_|\__\___|_| | .__/|_| \___|\__\___|_|
-- |_|
-- In this section you will implements an interpreter for the BF language.
-- If you are not familiar with it, please familiarize yourself:
-- https://en.wikipedia.org/wiki/Brainfuck
-- _____
-- |_ _|_ _ _ __ ___
-- | |/ _` | '_ \/ -_)
-- |_|\__,_| .__/\___|
-- |_|
-- | Represents a possibly infinite tape with a tape head pointing to one of the
-- tape value.
--
-- So, this object:
--
-- Tape
-- { leftTape :: [2, 6, ...],
-- tapeValue :: 1,
-- rightTape :: [5, 8, ...]
-- }
--
-- Would represent this tape:
--
-- ◀──┬─────┬─────┬─────┬─────┬─────┬──▶
-- ... │ 6 │ 2 │ 1 │ 5 │ 8 │ ...
-- ◀──┴─────┴─────┴─────┴─────┴─────┴──▶
-- ▲
-- │
data Tape a
= Tape
{ leftTape :: [a],
tapeValue :: a,
rightTape :: [a]
}
deriving (Eq, Ord, Show)
-- | This is represents the operation of moving the tape pointer to the left.
shiftTapeL :: Tape a -> Maybe (Tape a)
shiftTapeL (Tape (l : ll) c rr) = Just (Tape ll l (c : rr))
shiftTapeL _ = Nothing
-- | This is represents the operation of moving the tape pointer to the right.
shiftTapeR :: Tape a -> Maybe (Tape a)
shiftTapeR (Tape ll c (r : rr)) = Just (Tape (c : ll) r rr)
shiftTapeR _ = Nothing
-- | This operation allows you to modify the cell at the tape pointer.
touchTape :: (a -> a) -> Tape a -> Tape a
touchTape f (Tape l c r) = Tape l (f c) r
-- ___ _ _ _
-- / __| |_ __ _| |_ ___ _ __ ___ _ _ __ _ __| |
-- \__ \ _/ _` | _/ -_) | ' \/ _ \ ' \/ _` / _` |
-- |___/\__\__,_|\__\___| |_|_|_\___/_||_\__,_\__,_|
-- In this section we will implement the state monad with some basic operations
-- it supports.
-- | Since the standard `State` monad doesn't have error handling capabilities.
-- we will implement a version of `State`, which can also handle errors.
--
-- `e` is the type of the possible error
-- `s` is the type of the state that is carried through the monad
-- `a` is the value that is returned.
data ErrorState e s a
= ErrorState
{runErrorState :: s -> Either e (a, s)}
instance Functor (ErrorState e s) where
fmap = error "TODO: Functor (ErrorState e s) - fmap"
instance Applicative (ErrorState e s) where
pure = error "TODO: Applicative (ErrorState e s) - pure"
(<*>) = error "TODO: Applicative (ErrorState e s) - (<*>)"
instance Monad (ErrorState e s) where
(>>=) = error "TODO: Monad (ErrorState e s) - >>="
-- | This operation returns the state that the monad currently contains.
get :: ErrorState e s s
get = error "TODO: get"
-- | This operation sets the state in the monad to a new value.
put :: s -> ErrorState e s ()
put = error "TODO: put"
-- | This operation throws an error in the monad.
throwError :: e -> ErrorState e s a
throwError = error "TODO: throwError"
-- | This operations allows you to encapsulate the process of reading the state,
-- modifying it and writing it into the monad into a single operation.
--
-- It should modify the current state with the given function.
modify :: (s -> s) -> ErrorState e s ()
modify = error "TODO: modify"
-- ___ ___ _
-- | _ ) __| _ __ ___ _ _ __ _ __| |
-- | _ \ _| | ' \/ _ \ ' \/ _` / _` |
-- |___/_| |_|_|_\___/_||_\__,_\__,_|
-- In this section we will implement the specific state we will be using and
-- some operations that operate on it within the state monad.
type BFCommand = Char
-- | This represents the state of our BF interpreter.
data BFState
= BFState
{ -- | The command tape. It contains the a
-- pointer to the command being executed.
bfCommandTape :: Tape BFCommand,
-- | The data tape.
bfDataTape :: Tape Char,
-- | The input stream of the BF interpreter.
bfInput :: [Char],
-- | The output stream of the BF interpreter.
bfOutput :: [Char]
}
deriving (Eq, Show)
data BFError
= NotEnoughInput
| DataTapeExhausted
deriving (Show, Eq)
type BFMonad a = ErrorState BFError BFState a
-- | This operation should consume one 'Char' from the input stream
-- and return it.
readInput :: BFMonad Char
readInput = error "TODO: readInput"
-- | This operation should write one 'Char' to the output stream.
-- This should just prepend the character to the start of the string using the
-- `:` (cons) operator.
writeOutput :: Char -> BFMonad ()
writeOutput = error "TODO: writeOutput"
data CommandResult
= ExecutionTerminated
| ExecutionNotTerminated
deriving (Eq, Show)
-- | This operations shifts the command pointer to the right.
--
-- NOTE: The execution of the program ends successfully if the command pointer
-- moves past the end of the command tape.
--
-- For this reason you should not throw an error, and instead return whether the
-- execution of the program should be terminated.
shiftCommandR :: BFMonad CommandResult
shiftCommandR = error "TODO: shiftCommandR"
-- | This operations shifts the command pointer to the left.
--
-- NOTE: The execution of the program ends successfully if the command pointer
-- moves past the end of the command tape.
--
-- For this reason you should not throw an error, and instead return whether the
-- execution of the program should be terminated.
shiftCommandL :: BFMonad CommandResult
shiftCommandL = error "TODO: shiftCommandL"
-- | This operations shifts the data pointer to the right.
--
-- NOTE: if the tape has ended, you should throw the 'DataTapeExhausted' error.
shiftDataR :: BFMonad ()
shiftDataR = error "TODO: shiftDataR"
-- | This operations shifts the data pointer to the left.
--
-- NOTE: if the tape has ended, you should throw the 'DataTapeExhausted' error.
shiftDataL :: BFMonad ()
shiftDataL = error "TODO: shiftDataL"
-- | This operation reads the 'Char' at the data pointer.
--
-- NOTE: if the input has been exhausted, you should throw the 'NotEnoughInput'
-- error.
readData :: BFMonad Char
readData = error "TODO: readData"
-- | This operation writes the 'Char' to the current data pointer.
writeData :: Char -> BFMonad ()
writeData = error "TODO: writeData"
-- _____ _ _ _ _
-- |_ _| |_ ___ (_)_ _| |_ ___ _ _ _ __ _ _ ___| |_ ___ _ _
-- | | | ' \/ -_) | | ' \ _/ -_) '_| '_ \ '_/ -_) _/ -_) '_|
-- |_| |_||_\___| |_|_||_\__\___|_| | .__/_| \___|\__\___|_|
-- |_|
-- | Executes one BF command.
--
-- The command should be read from the function argument, not the monad state.
--
-- Please have a look at this commands table:
-- https://en.wikipedia.org/wiki/Brainfuck#Commands
--
-- To increment and decrement a `Char` you can use `succ` and `pred`.
--
-- Note: non-command characters are ignored.
executeCommand :: BFCommand -> BFMonad CommandResult
executeCommand = error "TODO: executeCommand"
-- | This function should evaluate the whole program starting from the current
-- command pointer.
--
-- This will probably be recursive.
evaluateProgram :: BFMonad ()
evaluateProgram = error "TODO: evaluateProgram"
-- | This constant just contains the "zero" 'Char' value for your convenience.
zeroChar :: Char
zeroChar = toEnum 0
-- | This constant just contains an infinite empty tape. You can use this as
-- the initial data tape.
emptyTape :: Tape Char
emptyTape = Tape (repeat zeroChar) zeroChar (repeat zeroChar)
-- | In this function you should bring everything together and execute the given
-- list of commands.
--
-- The input stream is the second argument to the function.
--
-- The returned string should contain the output stream that the evaluation
-- produces.
--
-- NOTE: since the output stream of the program is written backwards, you
-- will need to reverse the output stream. (You can use the `reverse` function.)
--
-- You will need to construct the initial state for the monad, evaluate the
-- program from the initial state, and convert the resulting value to the
-- appropriate type.
executeProgram :: [BFCommand] -> String -> Maybe String
executeProgram = error "TODO: executeProgram"

39
task.cabal Normal file
View File

@ -0,0 +1,39 @@
cabal-version: 2.2
-- This file has been generated from package.yaml by hpack version 0.33.0.
--
-- see: https://github.com/sol/hpack
--
-- hash: c454617de75af64ca6c743a3a745918472bb438f8df9c2019b67700d4caaf63c
name: task
version: 0.1.0.0
license: Unlicense
license-file: LICENSE
build-type: Simple
library
exposed-modules:
Task
other-modules:
Paths_task
hs-source-dirs:
src
build-depends:
base >=4.7 && <5
default-language: Haskell2010
test-suite task-tests
type: exitcode-stdio-1.0
main-is: Main.hs
other-modules:
Tests
Paths_task
hs-source-dirs:
test
build-depends:
base >=4.7 && <5
, task
, tasty
, tasty-hspec
default-language: Haskell2010