AmidamaruZXC

Untitled

May 17th, 2020
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haskell 11.31 KB | None | 0 0
  1. module Task
  2.   ( -- * List Monoids
  3.     constructFirstMonoid,
  4.     destructFirstMonoid,
  5.     FirstMonoid,
  6.     constructLastMonoid,
  7.     destructLastMonoid,
  8.     LastMonoid,
  9.  
  10.     -- * Todo List
  11.     Priority (..),
  12.     Completion (..),
  13.     TaskManager (..),
  14.     MyTaskManager,
  15.  
  16.     -- * Coffee
  17.     DebitCard (..),
  18.     Coffee (..),
  19.     CoffeeExtra (..),
  20.     HasPrice (..),
  21.     chargeCoffee,
  22.     PaymentMethod (..),
  23.     Customer (..),
  24.     payForCoffee,
  25.     applyPayment,
  26.     buyCoffee,
  27.     saveTheDiabetic,
  28.     calculateSugarDanger,
  29.   )
  30. where
  31.  
  32. --   _     _     _     __  __                   _     _
  33. --  | |   (_)___| |_  |  \/  | ___  _ __   ___ (_) __| |___
  34. --  | |   | / __| __| | |\/| |/ _ \| '_ \ / _ \| |/ _` / __|
  35. --  | |___| \__ \ |_  | |  | | (_) | | | | (_) | | (_| \__ \
  36. --  |_____|_|___/\__| |_|  |_|\___/|_| |_|\___/|_|\__,_|___/
  37.  
  38. -- Write a datatype and a Monoid instance for it such that:
  39. --
  40. --   (destructFirstMonoid . fold . fmap constructFirstMonoid) == safeHead
  41. --
  42. -- (constructFirstMonoid and destructFirstMonoid would wrap and
  43. -- unwrap the `FirstMonoid`)
  44. --
  45. -- In other words, it needs to have a monoid instance such that `fold`ing
  46. -- a list of `FirstMonoid`s should return the first element
  47. --
  48. -- >>> (destructFirstMonoid . fold . fmap constructFirstMonoid) [1, 2, 3]
  49. -- Just 1
  50. --
  51. -- >>> (destructFirstMonoid . fold . fmap constructFirstMonoid) []
  52. -- Nothing
  53. data FirstMonoid a
  54.  
  55. instance Semigroup (FirstMonoid a)
  56.  
  57. instance Monoid (FirstMonoid a)
  58.  
  59. -- Warps an `a` in a `FirstMonoid`.
  60. constructFirstMonoid :: a -> FirstMonoid a
  61. constructFirstMonoid = error "TODO: constructFirstMonoid"
  62.  
  63. -- Unwraps the `a` from a `FirstMonoid`, if there is one.
  64. destructFirstMonoid :: FirstMonoid a -> Maybe a
  65. destructFirstMonoid = error "TODO: destructFirstMonoid"
  66.  
  67. -- Write a datatype and a Monoid instance for it such that:
  68. --
  69. --   (destructLastMonoid . fold . fmap constructLastMonoid) == safeLast
  70. --
  71. -- (constructLastMonoid and destructLastMonoid would wrap and
  72. -- unwrap the `LastMonoid`)
  73. --
  74. -- In other words, it needs to have a monoid instance such that `fold`ing
  75. -- a list of `LastMonoid`s should return the last element
  76. --
  77. -- >>> (destructLastMonoid . fold . fmap constructLastMonoid) [1, 2, 3]
  78. -- Just 3
  79. --
  80. -- >>> (destructLastMonoid . fold . fmap constructLastMonoid) []
  81. -- Nothing
  82. data LastMonoid a
  83.  
  84. instance Semigroup (LastMonoid a)
  85.  
  86. instance Monoid (LastMonoid a)
  87.  
  88. -- Warps an `a` in a `LastMonoid`.
  89. constructLastMonoid :: a -> LastMonoid a
  90. constructLastMonoid = error "TODO: constructLastMonoid"
  91.  
  92. -- Unwraps the `a` from a `LastMonoid`, if there is one.
  93. destructLastMonoid :: LastMonoid a -> Maybe a
  94. destructLastMonoid = error "TODO: destructLastMonoid"
  95.  
  96. --   _____         _         _     _     _
  97. --  |_   _|__   __| | ___   | |   (_)___| |_
  98. --    | |/ _ \ / _` |/ _ \  | |   | / __| __|
  99. --    | | (_) | (_| | (_) | | |___| \__ \ |_
  100. --    |_|\___/ \__,_|\___/  |_____|_|___/\__|
  101.  
  102. -- Your task is to create a todo list backend, which supports adding tasks,
  103. -- changing the priority of tasks, completing tasks, renaming tasks, and
  104. -- displaying tasks as a list in order of descending priority.
  105.  
  106. -- | The priority of a task.
  107. data Priority = Low | Medium | High
  108.   deriving (Show, Eq)
  109.  
  110. -- | The completion status of a task.
  111. data Completion = Completed | NotCompleted
  112.   deriving (Show, Eq, Ord)
  113.  
  114. class TaskManager t where
  115.   -- | Returns an empty task manager backend (it should have no tasks).
  116.   emptyTaskManager :: t
  117.  
  118.   -- | Gets the list of all tasks, sorted by priority in the order:
  119.   -- High, Medium, Low
  120.   --
  121.   -- Ordering of tasks with the same priority is not defined
  122.   -- (You can do whatever you want)
  123.   getPriorityList :: t -> [(Completion, Priority, String)]
  124.  
  125.   -- | Creates a new task with the given name and priority.
  126.   -- Tasks are uniquely identified by their name.
  127.   -- When a task is newly created its status should be 'NotCompleted'.
  128.   --
  129.   -- If there is already a task with the given name, then the
  130.   -- behavior is undefined. (You can do whatever you want)
  131.   createTask :: String -> Priority -> t -> t
  132.  
  133.   -- | Toggles a task with the given name.
  134.   -- If the task has the status 'Completed', then it would become 'NotCompleted'.
  135.   -- If the task has the status 'NotCompleted', then it would become 'Completed'.
  136.   --
  137.   -- Needless to say, toggling the same task twice should be
  138.   -- equivalent to not doing anything.
  139.   --
  140.   -- If there is no tasks with the given name, then it does nothing.
  141.   toggleTaskCompletion :: String -> t -> t
  142.  
  143.   -- | Removes the task with the given name.
  144.   -- If there isn't a task with the given name, then it does nothing.
  145.   removeTask :: String -> t -> t
  146.  
  147.   -- | Sets the priority of the task with the given name.
  148.   -- If there isn't a task with the given name, then it does nothing.
  149.   modifyPriority :: String -> Priority -> t -> t
  150.  
  151.   -- | Renames the task with the given name to have a new name.
  152.   -- The first argument is the old name, the second argument is the new name.
  153.   -- If there isn't a task with the given name, then it does nothing.
  154.   -- If the new name clashes with an existing task, then the
  155.   -- behavior is undefined. (You can do whatever you want)
  156.   renameTask :: String -> String -> t -> t
  157.  
  158. -- The task manager you are creating.
  159. data MyTaskManager
  160.  
  161. -- TODO: You have to make your 'MyTaskManager' an instance of
  162. -- the 'TaskManager' typeclass.
  163. instance TaskManager MyTaskManager
  164.  
  165. --    ____       __  __
  166. --   / ___|___  / _|/ _| ___  ___
  167. --  | |   / _ \| |_| |_ / _ \/ _ \
  168. --  | |__| (_) |  _|  _|  __/  __/
  169. --   \____\___/|_| |_|  \___|\___|
  170. --
  171. --      /~~~~~~~~~~~~~~~~~~~/|
  172. --     /              /######/ / |
  173. --    /              /______/ /  |
  174. --   ========================= /||
  175. --   |_______________________|/ ||
  176. --    |  \****/     \__,,__/    ||
  177. --    |===\**/       __,,__     ||
  178. --    |______________\====/%____||
  179. --    |   ___        /~~~~\ %  / |
  180. --   _|  |===|===   /      \%_/  |
  181. --  | |  |###|     |########| | /
  182. --  |____\###/______\######/__|/
  183. --  ~~~~~~~~~~~~~~~~~~~~~~~~~~
  184.  
  185. -- | Just a typealias to make types more readable.
  186. type RUBAmount = Integer
  187.  
  188. -- | Represents a cup of coffee with extra ingredients added.
  189. data Coffee
  190.   = Coffee
  191.       { -- | The price of the coffee itself
  192.         -- (without the cost of the extra ingredients.)
  193.         cost :: RUBAmount,
  194.         -- | The extra ingredients added to the coffee.
  195.         extras :: [CoffeeExtra]
  196.       }
  197.   deriving (Eq, Show)
  198.  
  199. -- Extra ingredients added to the coffee.
  200. data CoffeeExtra
  201.   = Cream
  202.   | AlmondMilk
  203.   | SoyMilk
  204.   | OatMilk
  205.   | Cinnamon
  206.   | WhiteSugar
  207.   | BrownSugar
  208.   deriving (Eq, Show)
  209.  
  210. -- | A typeclass representing objects, for which the price can be calculated.
  211. class HasPrice x where
  212.   -- | Calculated the price of the item.
  213.   price :: x -> RUBAmount
  214.  
  215. -- I have already made a 'CoffeeExtra' an instance of 'HasPrice' for you.
  216. -- You should use this in price calculations.
  217. instance HasPrice CoffeeExtra where
  218.   price Cream = 50
  219.   price AlmondMilk = 70
  220.   price SoyMilk = 80
  221.   price OatMilk = 65
  222.   price Cinnamon = 20
  223.   price WhiteSugar = 15
  224.   price BrownSugar = 35
  225.  
  226. -- TODO: You want to make 'Coffee' an instance of 'HasPrice'.
  227. instance HasPrice Coffee
  228.  
  229. -- | A debit card.
  230. -- Note: the balance can be negative.
  231. data DebitCard
  232.   = DebitCard
  233.       { balance :: RUBAmount,
  234.         cardId :: Int
  235.       }
  236.   deriving (Eq, Show)
  237.  
  238. -- | Given a coffee and a debit card, deduce the total price of the coffee from
  239. -- the debit card. Return the given debit card with the reduced balance.
  240. --
  241. -- If the balance of the debit card after deducing the price of the coffee
  242. -- would become negative, return 'Nothing' from the function.
  243. chargeCoffee :: Coffee -> DebitCard -> Maybe DebitCard
  244. chargeCoffee = error "TODO: chargeCoffee"
  245.  
  246. -- | How was the coffee charged.
  247. data PaymentMethod
  248.   = -- | The coffee was charged using a debit card.
  249.     Card
  250.       { -- | The debit card with the balance deduced.
  251.         chargedCard :: DebitCard
  252.       }
  253.   | -- | The coffee was charged with cash.
  254.     Cash
  255.       { -- | The leftover money from the payment.
  256.         -- (We assume that the person pays with all of the cash he has.)
  257.         change :: RUBAmount
  258.       }
  259.   deriving (Eq, Show)
  260.  
  261. -- | Represents a coffee shop customer with all of the money he has on him.
  262. data Customer
  263.   = Customer
  264.       { -- | All of the debit hards the person has on him.
  265.         -- Sorted in order of descending preference.
  266.         -- (He would prefer to use the first card in the list.)
  267.         cards :: [DebitCard],
  268.         -- | The amount of cash the customer has on him.
  269.         cash :: RUBAmount
  270.       }
  271.   deriving (Eq, Show)
  272.  
  273. -- You have some new privacy-invading piece of ... technology, which
  274. -- automatically scans the customer, determines how he would prefer to pay and
  275. -- charges him automatically.
  276.  
  277. -- | This function determines how the given customer would prefer to pay for the
  278. -- coffee he wants.
  279. --
  280. -- The customer would always prefer to pay with a debit card if it is possible.
  281. -- The customer has a strict preference in the cards he carries with him:
  282. -- he would always like to pay with the first card in his wallet (the list). If
  283. -- the first card doesn't have enough money on it, then he would prefer to use
  284. -- the second card, and so on.
  285. --
  286. -- If non of the cards have enough balance to cover the coffee, then the
  287. -- customer will have to pay in cash.
  288. --
  289. -- NOTE: The customer can only buy a coffee with strictly one payment method.
  290. --   (Only one card or cash)
  291. payForCoffee :: Customer -> Coffee -> Maybe PaymentMethod
  292. payForCoffee = error "TODO: payForCoffee"
  293.  
  294. -- | This function should apply the chosen payment method to the customer.
  295. -- In other words, it needs to apply the charge to the customer himself
  296. -- (update the debit card or update the amount of cash he currently has)
  297. --
  298. -- If the specified card is not present in the 'Customer' structure, then
  299. -- do nothing.
  300. --
  301. -- NOTE: You can not change the order of the cards.
  302. applyPayment :: Customer -> PaymentMethod -> Customer
  303. applyPayment = error "TODO: applyPayment"
  304.  
  305. -- | Performs the full payment (as in 'payForCoffee') and
  306. -- returns the modified customer (as in 'applyPayment').
  307. buyCoffee :: Customer -> Coffee -> Maybe Customer
  308. buyCoffee = error "TODO: buyCoffee"
  309.  
  310. -- | You know that due to a medical condition the customer needs to watch his
  311. -- sugar intake. The new privacy-invading piece of ... technology can now
  312. -- automatically apply filters to coffee orders.
  313. --
  314. -- You have to make a filter, which removes any occurrences of sugar
  315. -- (either WhiteSugar or BrownSugar) from the ordered cups of coffee and
  316. -- return the filtered orders and the amount of money the customer saves by
  317. -- being healthy (sugar costs money after all). So, you also have to count how
  318. -- much the total sugar would have cost.
  319. --
  320. -- NOTE: You can not change the order of the coffee.
  321. saveTheDiabetic :: [Coffee] -> (RUBAmount, [Coffee])
  322. saveTheDiabetic = error "TODO: saveTheDiabetic"
  323.  
  324. -- | And just to torment those who love sugar lets make a function which
  325. -- calculates health hazard (sugar content) of the given orders.
  326. --
  327. -- The only ingredient that elevates the danger level is, of course, sugar:
  328. --
  329. --   WhiteSugar: 2 extra danger points
  330. --   BrownSugar: 1 extra danger point
  331. calculateSugarDanger :: [Coffee] -> Int
  332. calculateSugarDanger = error "TODO: calculateSugarDanger"
Add Comment
Please, Sign In to add comment