AmidamaruZXC

Untitled

May 23rd, 2020
348
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haskell 10.42 KB | None | 0 0
  1. module Task
  2.   ( Tape (..),
  3.     touchTape,
  4.     initializeTape,
  5.     shiftTapeL,
  6.     shiftTapeR,
  7.     ErrorState (..),
  8.     executeErrorState,
  9.     get,
  10.     put,
  11.     throwError,
  12.     modify,
  13.     BFState (..),
  14.     BFError (..),
  15.     BFMonad,
  16.     readInput,
  17.     writeOutput,
  18.     shiftDataR,
  19.     shiftDataL,
  20.     readData,
  21.     writeData,
  22.     BFCommand (..),
  23.     executeCommand,
  24.     evaluateProgram,
  25.     executeProgram,
  26.   )
  27. where
  28.  
  29. import Data.Char
  30. import Data.List
  31.  
  32. --   ____  _____   _       _                           _
  33. --  | __ )|  ___| (_)_ __ | |_ ___ _ __ _ __  _ __ ___| |_ ___ _ __
  34. --  |  _ \| |_    | | '_ \| __/ _ \ '__| '_ \| '__/ _ \ __/ _ \ '__|
  35. --  | |_) |  _|   | | | | | ||  __/ |  | |_) | | |  __/ ||  __/ |
  36. --  |____/|_|     |_|_| |_|\__\___|_|  | .__/|_|  \___|\__\___|_|
  37. --                                     |_|
  38.  
  39. -- In this section you will implements an interpreter for the BF language.
  40. -- If you are not familiar with it, please familiarize yourself:
  41. --   https://en.wikipedia.org/wiki/Brainfuck
  42.  
  43. --   _____
  44. --  |_   _|_ _ _ __  ___
  45. --    | |/ _` | '_ \/ -_)
  46. --    |_|\__,_| .__/\___|
  47. --            |_|
  48.  
  49. -- | Represents a possibly infinite tape with a tape head pointing to one of the
  50. -- tape value.
  51. --
  52. -- So, this object:
  53. --
  54. -- Tape
  55. --  { leftTape :: [2, 6, ...],
  56. --    tapeValue :: 1,
  57. --    rightTape :: [5, 8, ...]
  58. --  }
  59. --
  60. --  Would represent this tape:
  61. --
  62. --   ◀──┬─────┬─────┬─────┬─────┬─────┬──▶
  63. --  ... │  6  │  2  │  1  │  5  │  8  │ ...
  64. --   ◀──┴─────┴─────┴─────┴─────┴─────┴──▶
  65. --                     ▲
  66. --                     │
  67. data Tape a
  68.   = Tape
  69.       { leftTape :: [a],
  70.         tapeValue :: a,
  71.         rightTape :: [a]
  72.       }
  73.   deriving (Eq, Ord)
  74.  
  75. -- We need a special instance to handle infinite tapes. The derived
  76. -- implementation would go into an infinite loop.
  77. instance Show a => Show (Tape a) where
  78.   show (Tape l c right) =
  79.     "["
  80.       <> tapeify (reverse (take 5 l))
  81.       <> " { "
  82.       <> show c
  83.       <> " } "
  84.       <> tapeify (take 5 right)
  85.       <> "]"
  86.     where
  87.       tapeify = mconcat . intersperse " " . fmap show
  88.  
  89. -- | Creates a tape from a list.
  90. --
  91. -- Note that the tape will be empty to the left.
  92. --
  93. -- >>> initializeTape [1, 5, 8, ...]
  94. --
  95. --  ┌─────┬─────┬─────┬──▶
  96. --  │  1  │  5  │  8  │ ...
  97. --  └─────┴─────┴─────┴──▶
  98. --     ▲
  99. --     │
  100. initializeTape :: [a] -> Maybe (Tape a)
  101. initializeTape [] = Nothing
  102. initializeTape (a : aa) = Just (Tape [] a aa)
  103.  
  104. -- | This is represents the operation of moving the tape pointer to the left.
  105. shiftTapeL :: Tape a -> Maybe (Tape a)
  106. shiftTapeL (Tape (l : ll) c rr) = Just (Tape ll l (c : rr))
  107. shiftTapeL _ = Nothing
  108.  
  109. -- | This is represents the operation of moving the tape pointer to the right.
  110. shiftTapeR :: Tape a -> Maybe (Tape a)
  111. shiftTapeR (Tape ll c (r : rr)) = Just (Tape (c : ll) r rr)
  112. shiftTapeR _ = Nothing
  113.  
  114. -- | This operation allows you to modify the cell at the tape pointer.
  115. touchTape :: (a -> a) -> Tape a -> Tape a
  116. touchTape f (Tape l c r) = Tape l (f c) r
  117.  
  118. --   ___ _        _                                _
  119. --  / __| |_ __ _| |_ ___   _ __  ___ _ _  __ _ __| |
  120. --  \__ \  _/ _` |  _/ -_) | '  \/ _ \ ' \/ _` / _` |
  121. --  |___/\__\__,_|\__\___| |_|_|_\___/_||_\__,_\__,_|
  122.  
  123. -- In this section we will implement the state monad with some basic operations
  124. -- it supports.
  125.  
  126. -- | Since the standard `State` monad doesn't have error handling capabilities.
  127. -- we will implement a version of `State`, which can also handle errors.
  128. --
  129. -- `e` is the type of the possible error
  130. -- `s` is the type of the state that is carried through the monad
  131. -- `a` is the value that is returned.
  132. data ErrorState e s a
  133.   = ErrorState
  134.       {runErrorState :: s -> Either e (a, s)}
  135.  
  136. -- | Executes the state monad and returns the result without returning the
  137. -- final state.
  138. executeErrorState :: s -> ErrorState e s a -> Either e a
  139. executeErrorState = error "TODO: executeErrorState"
  140.  
  141. instance Functor (ErrorState e s) where
  142.   fmap = error "TODO: fmap"
  143.  
  144. instance Applicative (ErrorState e s) where
  145.   pure = error "TODO: pure"
  146.   (<*>) = error "TODO: <*>"
  147.  
  148. instance Monad (ErrorState e s) where
  149.   (>>=) = error "TODO: >>="
  150.   return = error "TODO: return"
  151.  
  152. -- | This operation returns the state that the monad currently contains.
  153. get :: ErrorState e s s
  154. get = error "TODO: get"
  155.  
  156. -- | This operation sets the state in the monad to a new value.
  157. put :: s -> ErrorState e s ()
  158. put = error "TODO: put"
  159.  
  160. -- | This operation throws an error in the monad.
  161. throwError :: e -> ErrorState e s a
  162. throwError = error "TODO: throwError"
  163.  
  164. -- | This operations allows you to encapsulate the process of reading the state,
  165. -- modifying it and writing it into the monad in a single operation.
  166. --
  167. -- It should modify the current state with the given function.
  168. modify :: (s -> s) -> ErrorState e s ()
  169. modify = error "TODO: modify"
  170.  
  171. --   ___ ___                          _
  172. --  | _ ) __|  _ __  ___ _ _  __ _ __| |
  173. --  | _ \ _|  | '  \/ _ \ ' \/ _` / _` |
  174. --  |___/_|   |_|_|_\___/_||_\__,_\__,_|
  175.  
  176. -- In this section we will implement the specific state we will be using and
  177. -- some operations that work within it.
  178.  
  179. -- | This represents the state of our BF interpreter.
  180. data BFState
  181.   = BFState
  182.       { -- | The data tape.
  183.         bfDataTape :: Tape Int,
  184.         -- | The input stream of the BF interpreter.
  185.         bfInput :: [Int],
  186.         -- | The output stream of the BF interpreter.
  187.         bfOutput :: [Int]
  188.       }
  189.   deriving (Eq, Show)
  190.  
  191. -- | This represents the errors that can occur while executing a BF program.
  192. data BFError
  193.   = -- | Tried reading input, but the input stream was empty.
  194.     NotEnoughInput
  195.   | -- | Tried going past the end of the data tape (if it was finite).
  196.     DataTapeExhausted
  197.   deriving (Show, Eq)
  198.  
  199. -- | The monad in which we will interpreting the BF commands.
  200. type BFMonad a = ErrorState BFError BFState a
  201.  
  202. -- | This operation should consume one element from the input stream
  203. -- and return it.
  204. --
  205. -- If there is not enough input, it should throw 'NotEnoughInput' error.
  206. readInput :: BFMonad Int
  207. readInput = error "TODO: readInput"
  208.  
  209. -- | This operation should write the element at the data tape head to the
  210. -- output stream.
  211. --
  212. -- It should just prepend the character to the start of the string using the
  213. -- `:` (cons) operator.
  214. --
  215. -- This will make writing O(1).
  216. writeOutput :: Int -> BFMonad ()
  217. writeOutput = error "TODO: writeOutput"
  218.  
  219. -- | This operation shifts the data pointer to the right.
  220. --
  221. -- NOTE: if the tape has ended, you should throw the 'DataTapeExhausted' error.
  222. shiftDataR :: BFMonad ()
  223. shiftDataR = error "TODO: shiftDataR"
  224.  
  225. -- | This operation shifts the data pointer to the left.
  226. --
  227. -- NOTE: if the tape has ended, you should throw the 'DataTapeExhausted' error.
  228. shiftDataL :: BFMonad ()
  229. shiftDataL = error "TODO: shiftDataL"
  230.  
  231. -- | This operation reads the element at the data pointer.
  232. readData :: BFMonad Int
  233. readData = error "TODO: readData"
  234.  
  235. -- | This operation writes the element to the current data pointer.
  236. writeData :: Int -> BFMonad ()
  237. writeData = error "TODO: writeData"
  238.  
  239. --   _____ _          _     _                        _
  240. --  |_   _| |_  ___  (_)_ _| |_ ___ _ _ _ __ _ _ ___| |_ ___ _ _
  241. --    | | | ' \/ -_) | | ' \  _/ -_) '_| '_ \ '_/ -_)  _/ -_) '_|
  242. --    |_| |_||_\___| |_|_||_\__\___|_| | .__/_| \___|\__\___|_|
  243. --                                     |_|
  244.  
  245. -- | The parsed commands from the BF language.
  246. --
  247. -- Please have a look at this commands table:
  248. --   https://en.wikipedia.org/wiki/Brainfuck#Commands
  249. data BFCommand
  250.   = -- | 'Loop x' is equivalent to `[x]` in BF. It is essentially a while loop.
  251.     Loop [BFCommand]
  252.   | -- | The `>` command.
  253.     ShiftRight
  254.   | -- | The `<` command.
  255.     ShiftLeft
  256.   | -- | The `+` command.
  257.     Increment
  258.   | -- | The `-` command.
  259.     Decrement
  260.   | -- | The `,` command.
  261.     ReadInput
  262.   | -- | The `.` command.
  263.     WriteOutput
  264.   deriving (Eq, Show)
  265.  
  266. type BFProgram = [BFCommand]
  267.  
  268. prependMaybe :: Maybe a -> [a] -> [a]
  269. prependMaybe Nothing aa = aa
  270. prependMaybe (Just x) xx = x : xx
  271.  
  272. -- | This is just a helper function.
  273. parseProgram' :: String -> (BFProgram, String)
  274. parseProgram' "" = ([], "")
  275. parseProgram' ('[' : rest) = (Loop innerProgram : outerProgram, s')
  276.   where
  277.     (innerProgram, s) = parseProgram' rest
  278.    (outerProgram, s') = parseProgram' s
  279. parseProgram' (']' : rest) = ([], rest)
  280. parseProgram' (x : rest) = (command `prependMaybe` restProgram, s)
  281.  where
  282.    (restProgram, s) = parseProgram' rest
  283.     command = case x of
  284.       '>' -> pure ShiftRight
  285.       '<' -> pure ShiftLeft
  286.       '+' -> pure Increment
  287.       '-' -> pure Decrement
  288.       '.' -> pure WriteOutput
  289.       ',' -> pure ReadInput
  290.       _ -> Nothing
  291.  
  292. -- | This function parses the given string and returns a sequence of BF
  293. -- commands.
  294. parseProgram :: String -> BFProgram
  295. parseProgram = fst . parseProgram'
  296.  
  297. -- | Executes one BF command.
  298. --
  299. -- NOTE: You will probably need to call 'evaluateProgram' somewhere in
  300. -- this function.
  301. executeCommand :: BFCommand -> BFMonad ()
  302. executeCommand = error "TODO: executeCommand"
  303.  
  304. -- | This function should evaluate the whole program.
  305. evaluateProgram :: BFProgram -> BFMonad ()
  306. evaluateProgram = error "TODO: evaluateProgram"
  307.  
  308. -- | This constant just contains an infinite empty tape. You can use this as
  309. -- the initial data tape.
  310. --
  311. -- NOTE: It is infinite.
  312. emptyTape :: Tape Int
  313. emptyTape = Tape (repeat 0) 0 (repeat 0)
  314.  
  315. -- | In this function you should bring everything together and execute the given
  316. -- list of commands.
  317. --
  318. -- The input stream is the second argument to the function.
  319. --
  320. -- The returned string should contain the output stream that the evaluation
  321. -- produces.
  322. --
  323. -- NOTE: since the output stream of the program is written backwards, you
  324. -- will need to reverse the output stream. (You can use the 'reverse' function.)
  325. --
  326. -- You will need to construct the initial state for the monad, evaluate the
  327. -- program from the initial state, and convert the resulting value to the
  328. -- appropriate type.
  329. executeProgram ::
  330.  -- | The text of the BF program.
  331.  String ->
  332.  -- | The input to pass into the program.
  333.  String ->
  334.  Maybe String
  335. executeProgram = error "TODO: evaluateProgram"
Add Comment
Please, Sign In to add comment