From 292687c2bfb759725caa10edd1e50f60ac9c45a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Votroubek?= <36277753+votroto@users.noreply.github.com> Date: Fri, 3 May 2024 19:01:46 +0200 Subject: [PATCH] Port labs 11-13 (#23) --- .vitepress/config.mts | 3 + .vitepress/theme/dark.css | 3 + .vitepress/theme/index.js | 4 + img/automaton.png | Bin 0 -> 41039 bytes img/montecarlo.png | Bin 0 -> 45356 bytes labs/lab11.md | 290 ++++++++++++++++++++ labs/lab12.md | 555 ++++++++++++++++++++++++++++++++++++++ labs/lab13.md | 325 ++++++++++++++++++++++ 8 files changed, 1180 insertions(+) create mode 100644 .vitepress/theme/dark.css create mode 100644 .vitepress/theme/index.js create mode 100644 img/automaton.png create mode 100644 img/montecarlo.png create mode 100644 labs/lab11.md create mode 100644 labs/lab12.md create mode 100644 labs/lab13.md diff --git a/.vitepress/config.mts b/.vitepress/config.mts index e55d683..c7b9a1e 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -56,6 +56,9 @@ export default defineConfig({ { text: '08: Haskell Basics', link: '/labs/lab08' }, { text: '09: Haskell Types', link: '/labs/lab09' }, { text: '10: Polymorphic functions', link: '/labs/lab10' }, + { text: '11: Functors and IO', link: '/labs/lab11' }, + { text: '12: Monads in action', link: '/labs/lab12' }, + { text: '13: State Monad', link: '/labs/lab13' }, ] }, diff --git a/.vitepress/theme/dark.css b/.vitepress/theme/dark.css new file mode 100644 index 0000000..ba7f2bb --- /dev/null +++ b/.vitepress/theme/dark.css @@ -0,0 +1,3 @@ +:root.dark .inverting-image { + filter: invert(1) hue-rotate(180deg); +} \ No newline at end of file diff --git a/.vitepress/theme/index.js b/.vitepress/theme/index.js new file mode 100644 index 0000000..5a63183 --- /dev/null +++ b/.vitepress/theme/index.js @@ -0,0 +1,4 @@ +import DefaultTheme from 'vitepress/theme' +import './dark.css' + +export default DefaultTheme \ No newline at end of file diff --git a/img/automaton.png b/img/automaton.png new file mode 100644 index 0000000000000000000000000000000000000000..8292ac8a1c53b89058759eb4a6ba842f8783751b GIT binary patch literal 41039 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 literal 0 HcmV?d00001 diff --git a/img/montecarlo.png b/img/montecarlo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc3ee5178fe59474a30031ece8710e1572a9052b GIT binary patch literal 45356 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%0AfvDe_)Cxe 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 literal 0 HcmV?d00001 diff --git a/labs/lab11.md b/labs/lab11.md new file mode 100644 index 0000000..d1a5e39 --- /dev/null +++ b/labs/lab11.md @@ -0,0 +1,290 @@ +# Lab 11: Functors and IO + +## Exercise 1 + This is a warm-up exercise. Write a function converting a string into a CamelCase format. It takes a string, splits particular words separated by whitespace characters, changes the first letter of each word to uppercase, and joins all the words into a single string. E.g. `" no air"` is converted into `"NoAir"`. Moreover, make the function polymorphic so that it works over any functor instance over `String`, i.e., our function should have the following type: + +```haskell +toCamelCaseF :: Functor f => f String -> f String +``` + +### Solution + First, we need a function converting an alphabetic character into uppercase. In the library `Data.Char` there is a function `toUpper` doing that. We will implement this function ourselves. To represent the relation between lowercase and uppercase letters, we take a list of tuples `[('a','A'), ('b','B'),...]`. This can be created by zipping `['a'..'z']` and `['A'..'Z']`. For a character `c` if it is a lowercase letter, then we return the corresponding uppercase letter; otherwise we return just `c`. To do that we can use the function +```haskell +lookup :: Eq a => a -> [(a, b)] -> Maybe b +``` +that takes an element of type `a` and a list of pairs and lookups the element among first components of those pairs. If it is there, it returns `Just` the second component and otherwise `Nothing`. Using the case expression, we can distinguish both cases by pattern matching. +::: details Solution: `toUpper` +```haskell +toUpper :: Char -> Char +toUpper c = case lookup c $ zip ['a'..'z'] ['A'..'Z'] of + Nothing -> c + Just c' -> c' +``` +::: + +To split the input string into particular words, we can apply the function +```haskell +words :: String -> [String] +``` +Then we have to apply `toUpper` to the first letter of each word. Finally, concatenate the resulting words. Thus we have a function converting a string into a CamelCase string. +::: details Solution: `toCamelCase` +```haskell +toCamelCase :: String -> String +toCamelCase = concat . map toUpperHead . words where + toUpperHead "" = "" + toUpperHead (x:xs) = toUpper x:xs +``` +::: + +It remains to lift the above function by `fmap` so that we can apply `toCamelCase` over any functor instance. +::: details Solution: `toCamelCaseF` +```haskell +toCamelCaseF :: Functor f => f String -> f String +toCamelCaseF = fmap toCamelCase +``` +::: + +Examples: +```haskell +> toCamelCaseF [" no air ", " get back"] -- over the list functor +["NoAir","GetBack"] + +> toCamelCaseF (Just " no air ") -- over the Maybe functor +Just "NoAir" + +> toCamelCaseF getLine -- over IO functor + no air -- user's input +"NoAir" +``` + +## Exercise 2 + A deterministic finite automaton (DFA) is a tuple $\langle Q,\Sigma,\delta,init,F\rangle$, where $Q$ is a set of states, $\Sigma$ is a finite alphabet, $\delta\colon Q\times\Sigma\to Q$ is a transition function, $init\in Q$ is an initial state and $F\subseteq Q$ is a set of final states. DFAs play a crucial role in applications of regular expressions as each regular expression can be converted into an equivalent DFA accepting the language defined by the regular expression. For instance, the regular expression `[0-9]+\.[0-9][0-9]` defines a language of numbers having the decimal point followed by two digits, e.g. $123.00$, $0.12$, $3476.25$. The equivalent automaton is depicted below. It has states `Before, Digit, Dot, First, Second`. `Before` is the initial state and `Second` is the only final state. Automaton reads the input characters and changes its state according to $\delta$. After the whole input is read, it accepts the input string iff it is in a final state. At the beginning, it is in `Before`. Once it reads a digit, the state changes to `Digit` and remains there until `.` is read. Then the next digit changes the state to `First` and finally the second digit after the decimal point changes the state to `Second` which is final. Anything else leads to the state `Fail`. + +![](/img/automaton.png){class="inverting-image" style="width: 100%; margin: auto;" } + +Our task is to define a parametric data type `DFA a` modelling a DFA and implement the function +```haskell +evalDFA :: DFA a -> String -> Bool +``` +taking an automaton, a string `w` and returning true if `w` is accepted by the automaton and false otherwise. + +Further, define the above automaton and use it to implement a function +```haskell +parseNum :: String -> Maybe Float +``` +taking a string and returning `Just` the parsed floating number if the string is accepted by the automaton or `Nothing`. +Finally, lift `parseNum` to any functor instance +```haskell +parseNumF :: Functor f => f String -> f (Maybe Float) +``` + +### Solution + To model an automaton, we need the transition function $\delta\colon Q\times\Sigma\to Q$, the initial and final states. +We make the type `DFA a` parametric over a type `a` representing states as we wish to work with automata whose states might be integers or strings or other data types. We could also make `DFA a` parametric over a type `b` representing the alphabet $\Sigma$ but for this example we set $\Sigma=$ `Char`. Thus the transition function $\delta$ is of type `a -> Char -> a`. The initial state is of type `a` and the set of final states can be represented as a predicate of type `a -> Bool`. +```haskell +data DFA a = Automaton (a->Char->a) a (a->Bool) +``` +Now we can write the function simulating the automaton computation. It starts with the initial states and repeatedly applies the transition function to the current state and the current letter. This can be done by folding as I explained in the lecture introducing folding in Scheme. In the comment below, you can see how to implement the automaton computation directly without folding. Finally, the predicate defining the final states is applied. +::: details Solution: `evalDFA` +```haskell +evalDFA :: DFA a -> String -> Bool +evalDFA (Automaton dlt s inF) w = + inF (foldl dlt s w) +-- inF (deltaStar s w) +-- where deltaStar q [] = q +-- deltaStar q (a:ws) = deltaStar (dlt q a) ws +``` +::: + +Now we represent the above automaton as an instance of `DFA a`. We first define a type representing the states. Then we define the automaton over these states. +```haskell +data State = Before | Digit | Dot | First | Second | Fail + +isNum :: Char -> Bool +isNum c = c `elem` ['0'..'9'] + +final :: State -> Bool +final Second = True +final _ = False + +delta :: State -> Char -> State +delta Before c | isNum c = Digit + | otherwise = Fail +delta Digit c | isNum c = Digit + | c == '.' = Dot + | otherwise = Fail +delta Dot c | isNum c = First + | otherwise = Fail +delta First c | isNum c = Second + | otherwise = Fail +delta Second _ = Fail +delta Fail _ = Fail + +automaton :: DFA State +automaton = Automaton delta Before final +``` + +Next, the function `parseNum` takes a string, and uses the automaton to check if the string has the correct format. If yes, it is read by the `read` function and otherwise `Nothing` is returned. +::: details Solution: `parseNum` +```haskell +parseNum :: String -> Maybe Float +parseNum w = if evalDFA automaton w then Just (read w) + else Nothing +``` +::: + +Now, we can lift it via `fmap`. + +::: details Solution: `parseNumF` +```haskell +parseNumF :: Functor f => f String -> f (Maybe Float) +parseNumF = fmap parseNum +``` +::: + +Examples: +```haskell +> parseNumF ["234", "123.12", ".5", "0.50"] -- the list functor instance +[Nothing,Just 123.12,Nothing,Just 0.5] + +> parseNumF getLine -- IO functor instance +1234.34 -- user's input +Just 1234.34 + +> parseNumF getLine -- IO functor instance +1.234 -- user's input +Nothing +``` + +## Exercise 3 + Using the function `parseNumF` from the previous exercise, write a function `parseIO :: IO ()` that displays a string "Enter number:\n" and then reads from the keyboard a string. If the string has the correct format (i.e., number with two digits after the decimal point), then it displays "Ok"; otherwise it asks for the user's input again. + +### Solution + First, we execute the action `putStrLn` displaying the string "Enter number:". Then we execute the action `parseNumF getLine :: IO (Maybe Float)`. Depending of its result, we either display "Ok" or execute the whole action `parseIO` again. We can either use the monadic operators as follows: +::: details Solution: `using bind` +```haskell +parseIO :: IO () +parseIO = putStrLn "Enter number:" + >> parseNumF getLine + >>= \x -> case x of + Nothing -> parseIO + Just _ -> putStrLn "Ok" +``` +::: +or we can use the do-syntax as follows: + +::: details Solution: `using do` +```haskell +parseIO :: IO () +parseIO = do putStrLn "Enter number:" + x <- parseNumF getLine + case x of + Nothing -> parseIO + Just _ -> putStrLn "Ok" +``` +::: + +## Task 1 + Consider the following data type representing Boolean propositional formulas built up from atoms by negations, conjunctions, and disjunctions. + +```haskell +data Expr a = Atom a + | Neg (Expr a) + | And (Expr a) (Expr a) + | Or (Expr a) (Expr a) + deriving (Eq, Show) +``` + +The type constructor `Expr` has a single parameter `a` representing a data type for atoms. So for instance `Expr Bool` is a Boolean expression that can be directly evaluated, e.g. the expression $(True\wedge \neg False)\vee False$ is represented as +```haskell +expr :: Expr Bool +expr = Or (And (Atom True) (Neg (Atom False))) (Atom False) +``` + + On the other hand, `Expr String` might represent propositional formulas whose atoms are variables represented as strings, e.g. the formula +$(\neg x\vee x)\wedge y$ is represented as +```haskell +fle :: Expr String +fle = And (Or (Neg (Atom "x")) (Atom "x")) (Atom "y") +``` + +Write a function `eval :: Expr Bool -> Bool` evaluating a given Boolean expression. Thus it should evaluate `expr` to `True`. Further, implement a function `getAtoms :: Expr a -> [a]` returning the list of atoms for a given expression, e.g. `getAtoms fle` should return +`["x","x","y"]`. + +::: tip Hint + Logical operations negation, conjunction and disjunction can be respectively computed by `not, &&, ||`. The last two are infix operators. +::: + +::: details Solution: `eval` +```haskell +eval :: Expr Bool -> Bool +eval (Atom c) = c +eval (Neg e) = not (eval e) +eval (And e1 e2) = eval e1 && eval e2 +eval (Or e1 e2) = eval e1 || eval e2 +``` +::: + +::: details Solution: `getAtoms` +```haskell +getAtoms :: Expr a -> [a] +getAtoms (Atom c) = [c] +getAtoms (Neg e) = getAtoms e +getAtoms (And e1 e2) = getAtoms e1 ++ getAtoms e2 +getAtoms (Or e1 e2) = getAtoms e1 ++ getAtoms e2 +``` +::: + +## Task 2 + The type constructor `Expr` from the previous task can be made into an instance of `Functor` as follows: + +```haskell +instance Functor Expr where + fmap f (Atom c) = Atom (f c) + fmap f (Neg e) = Neg (fmap f e) + fmap f (And e1 e2) = And (fmap f e1) (fmap f e2) + fmap f (Or e1 e2) = Or (fmap f e1) (fmap f e2) +``` + +Thus if we have a map `f :: a -> b`, it can be lifted by `fmap` to a map of type `Expr a -> Expr b`. This might be handy if we need to rename variables or we want to assign concrete Boolean values to variables. Write a polymorphic function +```haskell +subst :: Functor f => [String] -> f String -> f Bool +``` +taking a list of strings (variables) and a data structure over strings returning the same data structure where the strings (variables) in the input list are replaced by `True` and the rest by `False`. Use the lifting by `fmap`. + +::: details Solution: `subst` +```haskell +subst :: Functor f => [String] -> f String -> f Bool +subst xs = fmap (`elem` xs) +``` +::: + +Next, apply the function `subseqs :: [a] -> [[a]]` from the previous lab returning a list of all sublists of a given list. +```haskell +subseqs :: [a] -> [[a]] +subseqs [] = [[]] +subseqs (x:xs) = subseqs xs ++ [x:ys | ys <- subseqs xs] +``` + +The above function can generate all possible evaluations of a propositional formula if we apply it to the result of `getAtoms`. Implement functions +```haskell +isTaut, isSat :: Expr String -> Bool +``` +testing whether a given formula is a tautology (resp. satisfiable). A propositional formula is satisfiable if there exists an evaluation of atoms +such that the Boolean expression resulting from the replacing atoms by the respective Boolean values is evaluated to `True`. A propositional formula is called tautology if it is satisfied by all possible evaluations of its atoms. + +::: tip Hint + To check that there exists an evaluation satisfying a formula or if all evaluations satisfy the formula, use the functions `or`, `and` respectively. These functions are applicable to any list of Boolean values. +::: + +::: details Solution: `isTaut, isSat` +```haskell +check :: ([Bool] -> Bool) -> Expr String -> Bool +check g e = g [ eval $ subst vs e | vs <- vss] + where vss = subseqs $ getAtoms e + +isTaut, isSat :: Expr String -> Bool +isTaut = check and +isSat = check or +``` +::: \ No newline at end of file diff --git a/labs/lab12.md b/labs/lab12.md new file mode 100644 index 0000000..e0b4e52 --- /dev/null +++ b/labs/lab12.md @@ -0,0 +1,555 @@ +# Lab 12: Monads in action + +This lab will illustrate a complete Haskell program searching for the shortest path in a maze. We will see `Maybe` and `IO` monads in action. +It will be split into two parts. The first part deals with the breadth-first search and the second with parsing the file containing a maze. +Short fragments of code are left for you to fill. + +Before you start, make sure that you have the following imports in your source file: +```haskell +import Data.Char +import Control.Applicative +``` +We are going to need these libraries for our parser. + +## Data structures + + +As building blocks for a maze, we introduce the following data type: +```haskell +data Block = W | F | S deriving (Eq,Show) +``` +The values `W`, `F`, `S` represent respectively a wall, a free space, and a star that we will use to depict solutions. +A data type capturing mazes can be defined as follows: +```haskell +data Maze = M [[Block]] + +maze :: Maze -- a testing maze +maze = M [[W,W,W,W,W], + [W,F,W,F,W], + [W,F,W,W,W], + [W,F,F,F,W], + [W,W,W,W,W]] +``` + +To display a maze we make `Maze` into an instance of `Show`. +```haskell +instance Show Maze where + show (M []) = "" + show (M (r:rs)) = map dispBlock r ++ "\n" ++ show (M rs) + where dispBlock W = '#' + dispBlock F = ' ' + dispBlock S = '*' +``` + +Finally, we represent a position in a maze by a tuple of integers. A path can be represented as a list of positions and a planning task +is a triple consisting of start and goal positions and a maze. +```haskell +type Pos = (Int, Int) +type Path = [Pos] +type Task = (Pos,Pos,Maze) +``` + +## Manipulations with maze + + +We will need to extract a block on a given position and conversely set a block on a given position. To see `Maybe` monad in action, +we implement these functions to be safe. E.g., if we provide a position outside the maze, it will return `Nothing`. We will start by implementing +such safe functions for lists. + +Suppose we have an index `n`, an element `x :: a` and a list `xs :: [a]`. We want to implement a function that replaces the element of index +`n` in `xs` by `x` provided that `n` is within the range of indexes of `xs`. If `n` is outside this range, it returns `Nothing`. +```haskell +safePut :: Int -> a -> [a] -> Maybe [a] +... +``` +::: details Solution: `safePut` +```haskell +safePut :: Int -> a -> [a] -> Maybe [a] +safePut n x xs | 0 <= n && n < length xs = Just $ take n xs ++ [x] ++ drop (n+1) xs + | otherwise = Nothing +``` +::: + +Similarly, try to implement the function `safeGet` that extract the element of index `n` provided it exists: +```haskell +safeGet :: Int -> [a] -> Maybe a +... +``` +::: details Solution: `safeGet` +```haskell +safeGet :: Int -> [a] -> Maybe a +safeGet n xs | n `elem` [0..length xs-1] = Just $ xs !! n + | otherwise = Nothing +``` +::: + +Now we can use the above functions to implement functions extracting and setting a block in a maze. +To extract a block, we first safely extract a row of a maze. If it is successful, we can extract the block from the row. +Using the fact that `Maybe` is a monad, we don't have to test every time if the computation was successful. +::: details Solution: `getBlock` +```haskell +getBlock :: Pos -> Maze -> Maybe Block +getBlock (x,y) (M xss) = do row <- safeGet y xss + block <- safeGet x row + return block +``` +::: +Examples: +```haskell +> getBlock (1,0) maze +Just W + +> getBlock (10,10) maze +Nothing +``` + +Using `safeGet` and `safePut`, try to implement a function that takes +a block `b`, a maze `m`, a position `(x,y)` and returns a new maze created by replacing +the block on `(x,y)` by `b`. +```haskell +setBlock :: Block -> Pos -> Maze -> Maybe Maze +... +``` + +::: details Solution: `setBlock` +```haskell +setBlock :: Block -> Pos -> Maze -> Maybe Maze +setBlock b (x,y) (M xss) = do row <- safeGet y xss + row' <- safePut x b row + xss' <- safePut y row' xss + return (M xss') +``` +::: + +Example: +```haskell +> setBlock S (1,2) maze +Just ##### +# # # +#*### +# # +##### +``` +Finally, if we have a path (i.e., a list of positions), we can set recursively all its positions in a maze. Again using the fact that `Maybe` is a monad. +::: details Solution: `setPath` +```haskell +setPath :: Maze -> Path -> Maybe Maze +setPath m [] = Just m +setPath m (p:ps) = do m' <- setBlock S p m + m'' <- setPath m' ps + return m'' +``` +::: + +You might note that this is, in fact, a kind of monadic `foldr`. There is, of course, a generic monadic `foldr` called `foldrM`. +If you import `Data.Foldable`, then you can rewrite the above function as follows: +```haskell +setPath = foldrM (setBlock S) +``` + +As `setPath` returns a value of type `Maybe Maze`, we can extract it from the `Maybe` context by pattern matching. +::: details Solution: `drawSol` +```haskell +drawSol :: Maze -> Path -> Maze +drawSol m ps = case setPath m ps of + Nothing -> m + Just m' -> m' +``` +::: + +## Breadth-first search (BFS) + +To find a path leading from a start position into the goal position, we need a function taking a position and returning all possible successive positions. +Assume that there are at most eight possible moves. All possibilities are generated by the function `neighbs`. We have to filter only those leading to a free block out of these possibilities. Moreover, it is necessary to check that the input position is permissible as well. + +```haskell +neighbs :: Pos -> [Pos] +neighbs (x,y) = [(x-1,y), (x+1,y), (x,y-1), (x,y+1), + (x-1,y-1), (x-1,y+1), (x+1,y-1), (x+1,y+1)] + +nextPos :: Pos -> Maze -> [Pos] +nextPos p m = case getBlock p m of -- is the input position admissible? + Just F -> [ p' | p' <- neighbs p, getBlock p' m == Just F] -- if yes, take all possibilities and filter admissible positions + _ -> [] + +> nextPos (1,1) maze +[(1,2)] +``` + +Using `nextPos`, implement the following function taking a path, a maze and returning all its possible extensions. For efficiency reasons +we will represent paths in BFS in the reversed order. Thus extend a given path using the operator `(:)`. +::: details Solution: `extend` +```haskell +extend :: Path -> Maze -> [Path] +extend [] _ = [] +extend path@(p:_) m = map (:path) $ nextPos p m + +> extend [(1,2),(1,1)] maze +[[(1,1),(1,2),(1,1)],[(1,3),(1,2),(1,1)],[(2,3),(1,2),(1,1)]] +``` +::: + +Now we can quickly implement BFS. Recall that in BFS, we use a queue storing partial solutions. We will implement this queue naively as a list. +In addition, we have to keep information about already visited positions. We define the function `solve` as just a wrapper for +the `bfs` function implementing BFS. The function `bfs` takes several arguments. The first is a list of already visited positions. +The second is the queue of partial solutions. The third is the goal position and the last one is the maze. +```haskell +solve :: Task -> Maybe Path +solve (p,q,m) = bfs [] [[p]] q m + +bfs :: [Pos] -> [Path] -> Pos -> Maze -> Maybe Path +bfs _ [] _ _ = Nothing +bfs visited (path@(p:_):paths) q m -- consider the first path in the queue and its head p + | p ## q + Just $ reverse path -- is path a solution? If yes, return the reversed solution + | p `elem` visited = bfs visited paths q m -- does path end in an already visited position? If yes, disregard it + | otherwise = bfs (p:visited) (paths ++ extend path m) q m -- add p to visited positions and extend path by all possible positions + +> solve ((1,2),(3,3),maze) +Just [(1,2),(2,3),(3,3)] + +> solve ((3,1),(3,3),maze) +Nothing +``` + +## Type constructor Parser + + +As a next task, we must create a user interface for the BFS solver. We have to allow the user to specify a maze together with a start and goal +positions. The user provides a string containing all the necessary data via the standard input. It might look as follows: + +``` +start = (1,1) +goal = (28,4) +######################################### +# # # # +# # # # +########### ####### ########### # +# # # # # +# ##################### # +#### # # # # +# ########## ################ # +# # +# # # # +######################################### + +``` + +Our program is supposed to parse this input and display its solution provided it exists: +``` +######################################### +#********* # # # +# * # # # +###########* ####### ########### # +# * # # **** # # +# * #####################* # +#### * # # # ***** # +# *########## ################* # +# ****************************** # +# # # # +######################################### +``` + +We will use the type constructor `Parser` that I explained in the lecture. Below you can find its definition and definitions of all its instances +for `Functor`, `Applicative`, `Monad` and `Alternative`. So you can directly copy them into your source file. + +Let me recall the info on `Parser` shortly. A parser over type `a` is a function taking an input string, consuming a part of it, and returning +the parsed value of type `a` and the remaining unused input string. The parsing can fail. That's why it returns a value of type +`Maybe (a, String)`. For instance, if you want to parse an integer and the input string starts with a letter, the parsing fails. + +The accessor function `parse` just helps us to remove the data constructor `P`. So if you want to apply a parser `p` to an input `inp`, call +`parse p inp`. + +As we want to make `Parser` an instance of `Monad` so that we can sequence parsers, we have to define also instances for super-classes +`Applicative` and `Functor`. Functor instances over data type `a` implements a function `fmap` allowing to lift +a map `f :: a -> b` to a map of type `Parser a -> Parser b`. The function `fmap` always +keeps the functor structure untouched only changes values of type parameter `a`. So for `Parser a` it just keeps the parsing +function the same expect of modifying the output value `v :: a` by `f v`. + +Functors allow lifting unary maps to the functorial context. E.g. we can lift `(+1)` to `Parser Int` but we cannot lift binary `(+)`. +If we lift `(+) :: Int -> Int -> Int` to `Parser Int` by `fmap`, we obtain a function +`Parser Int -> Parser (Int -> Int)`. However, to lift `(+)`, we need type +`Parser Int -> Parser Int -> Parser Int`. Applicative functors implement `<*>` that can transform +`Parser (Int -> Int)` to `Parser Int -> Parser Int`. +The function `pure` just wraps a value into the `Parser` context. It is, in fact, a synonym for the monadic `return`. + +The monad instance for `Parser` has to define the bind operator `>>=`. Its implementation first parses a value `v :: a`. +If the parsing fails, then the whole parsing fails. Otherwise, we apply `f v` obtaining the next parser applied to the unused +input `out`. + +Finally, we define the instance of `Alternative`. It consists of `empty` and `<|>`. The first is the always failing parser. +The second operator allows trying two parsers for the same input, and the first successful returns its result. + +```haskell +newtype Parser a = P { parse :: String -> Maybe (a, String) } + +instance Functor Parser where + -- fmap :: (a -> b) -> Parser a -> Parser b + fmap f p = P (\inp -> case parse p inp of + Nothing -> Nothing + Just (v,out) -> Just (f v, out)) + +instance Applicative Parser where + -- (<*>) :: Parser (a -> b) -> Parser a -> Parser b + pg <*> px = P (\inp -> case parse pg inp of + Nothing -> Nothing + Just (g,out) -> parse (fmap g px) out) + pure v = P (\inp -> Just (v,inp)) + +instance Monad Parser where + -- (>>=) :: Parser a -> (a -> Parser b) -> Parser b + p >>## f + P (\inp -> case parse p inp of + Nothing -> Nothing + Just (v,out) -> parse (f v) out) + +instance Alternative Parser where + -- empty :: Parser a + empty = P (\_ -> Nothing) + -- (<|>) :: Parser a -> Parser a -> Parser a + p <|> q = P (\inp -> case parse p inp of + Nothing -> parse q inp + Just (v,out) -> Just (v,out)) +``` + +## Parsing + + +Now we are ready to implement the parser for our BFS application. We start with simple parsers, out of which we compose the final one. +The structure of the input `` is specified by the following grammar. The first line contains a definition of the start position +and the second one defines the goal position. The start definition starts with `"start"` followed possibly by spaces, +then `"="`, again possibly followed by spaces, and then a position followed by the new-line character `"\n"`. +The goal definition is analogous. The position is just a tuple of numbers in parentheses separated by a comma and possibly by spaces. +The maze `` consists of rows followed by `"\n"`. Each row is a (possibly empty) sequence of the wall `"#"` and free `" "` blocks. +```haskell + -> + + -> "start" * "=" * "\n" + -> "goal" * "=" * "\n" + + -> "(" * + * "," * + * ")" + + -> * + -> ( | )* "\n" + + -> "#" + -> 0 | 1 | ... | 9 + -> " " +``` + +First, we create a basic parser `item` consuming a single character and failing if there is none. +Based on that we can define a parser `sat` parsing a character satisfying a given predicate. If you need extra exercises, reimplement +the following parsers using the operators `>>=` and `>>`. +```haskell +item :: Parser Char +item = P (\inp -> case inp of + "" -> Nothing + (x:xs) -> Just (x,xs)) + +sat :: (Char -> Bool) -> Parser Char +sat pr = do x <- item + if pr x then return x + else empty +``` +/* +sat :: (Char -> Bool) -> Parser Char +sat pr = item >>= \x -> if pr x then return x + else empty +*/ + +To parse numbers, we need a parser for a single digit. The predicate `isDigit` from `Data.Char` recognizes digits. Further, we need parsers +for a specific character and even a specific string like `"start"`. +```haskell +digit :: Parser Char +digit = sat isDigit + +char :: Char -> Parser Char +char c = sat (== c) + +string :: String -> Parser String +string [] = return [] +string (x:xs) = do char x + string xs + return (x:xs) +-- string (x:xs) = char x *> string xs *> pure (x:xs) -- alternative definition using Applicative + +> parse digit "34abc" +Just ('3',"4abc") + +> parse (string "start") "start = (1,2)" +Just ("start"," = (1,2)") +``` +The above function `string` returns a parser whose output value is known in advance (it is `x:xs`). Its only reason is to +check if the parsing does not fail. + +As we define `Parser` to be an instance of `Alternative`, we have for free two parser combinators `many` and `some`. Both of them +repeatedly apply a given parser until it fails. The parser `many p` always succeeds even if `p` fails for the first time. +On the other hand, `some p` succeeds only if the first application of `p` succeeds. + +```haskell +> parse (many (char 'a')) "aaabc" +Just ("aaa","bc") + +> parse (many (char 'a')) "bc" +Just ("","bc") + +> parse (some (char 'a')) "aaabc" +Just ("aaa","bc") + +> parse (some (char 'a')) "bc" +Nothing +``` +Thus `many` can handle (possibly empty) sequences (e.g., an arbitrary series of spaces) and `some` non-empty sequences +(e.g., non-empty sequences of digits representing an integer). To disregard sequences of spaces, we define the following parser +together with the function `token` that transforms any parser to omit spaces at the beginning and the end. + +```haskell +space :: Parser () +space = do many (sat isSpace) + return () +-- some (sat isSpace) *> pure () -- alternative definition by Applicative combinators + +token :: Parser a -> Parser a +token p = do space + x <- p + space + return x +-- token p = space *> p <* space -- alternative definition by Applicative combinators + +> parse (token (char '=')) " = (1,2)" +Just ('=',"(1,2)") +``` + +/* +string :: String -> Parser String +string [] = return [] +string (x:xs) = char x + >> string xs + >> return (x:xs) + +space :: Parser () +space = many (sat isSpace) >> return () + +token :: Parser a -> Parser a +token p = space + >> p + >>= \x -> space + >> return x +*/ + +Now we will follow the grammar. We start with a parser for a position. +```haskell +pos :: Parser Pos +pos = do char '(' -- it has to start with '(' + space -- possibly followed by spaces + x <- some digit -- then parses a nonempty sequence of digits + token (char ',') -- then comma possible surrounded by spaces + y <- some digit -- then a second non-empty sequence of digits + space -- possibly spaces + char ')' -- then the closing ')' + return (read x, read y) -- the position is returned, sequences of digits are converted by read + +> parse pos "( 343, 55 )" +Just ((343,55),"") + +> parse pos "(1 2)" +Nothing +``` + +Using the above parsers, try to define the following function by taking a string and returning the parser of a definition. +```haskell +def :: String -> Parser Pos +... +``` +::: details Solution: `def` +```haskell +def :: String -> Parser Pos +def str = do string str + token (char '=') + p <- pos + char '\n' + return p +``` +::: + +Example: +```haskell +> parse (def "start") "start = (3,2)\n" +Just ((3,2),"") +``` + +Next, we focus on maze parsing. We define simple parsers for blocks. Out of them, we can create a parser for rows. Using the operator +`<|>`, we can define the parser `wall <|> free` which parses either the wall or free block. +```haskell +wall :: Parser Block +wall = do char '#' + return W +-- wall = char '#' *> pure W -- Applicative approach + +free :: Parser Block +free = do char ' ' + return F + +row :: Parser [Block] +row = do bs <- many (wall <|> free) + char '\n' + return bs +-- row = many (wall <|> free) <* char '\n' -- Applicative approach + +> parse row " ### # \n# #\n" +Just ([F,F,W,W,W,F,W,F],"# #\n") +``` + +A maze is just a (possibly empty) sequence of rows. The input starts with the start and goal definitions, followed by a maze. +```haskell +mapP :: Parser Maze +mapP = do rs <- many row + return (M rs) +-- mapP = M <$> many row -- Functor approach + +file :: Parser Task +file = do p <- def "start" + q <- def "goal" + m <- mapP + return (p,q,m) +-- Applicative approach +-- file = (,,) <$> def "start" +-- <*> def "goal" +-- <*> mapP +``` + +## IO actions + + +Finally, we put all the pieces together. We start with a function taking a task and returning an IO action that +either displays the found solution or informs that there is no solution. Note that the function `print` is just the composition of `show` followed by `putStrLn`. +```haskell +solveTask :: Task -> IO () +solveTask t@(p,q,m) = case solve t of + Nothing -> putStrLn "No solution exists." + Just ps -> print $ drawSol m ps +``` + +We need to create a `main` function returning the main IO action to be executed. It reads completely the input by `getContents`. +Then it parses the input. If the parser fails or does not consume the whole input, it prints an error message. +Otherwise, we have a task `t` and `solveTask t` can be executed. + +```haskell +main :: IO () +main = do str <- getContents + case parse file str of + Nothing -> putStrLn "Incorrect task!" + Just (t, "") -> solveTask t + Just (_, out) -> putStrLn $ "Unused input: " ++ out +``` + +Now, if we have a text file `maze.txt` with the input, we can run our source code by +```bash +$ runghc lab12.hs < maze.txt +``` + +Alternatively, we can compile it and then run the compiled executable file. +```bash +$ ghc lab12.hs +$ ./lab12 < maze.txt +``` \ No newline at end of file diff --git a/labs/lab13.md b/labs/lab13.md new file mode 100644 index 0000000..7ca3403 --- /dev/null +++ b/labs/lab13.md @@ -0,0 +1,325 @@ +# Lab 13: State Monad + +This lab is focused on the state monad `State`. In the lecture, I show you how it is implemented. In this lab, we are going to use the implementation from the lecture [State.hs](https://drive.google.com/file/d/10lPsFg__39AQBT5schwiqI9FHKxpPXDY/view?usp=sharing). So include the following lines in your source file: + +```haskell +import Control.Monad +import State +import System.Random +import Data.List +``` + +The third import is important as we are going to work with pseudorandom numbers. The last import allows us to use some extra functions to manipulate lists. + +::: tip Hint +If `import System.Random` doesn't work for you, you need to install the package `random` as follows: + - either locally into the current directory by ```bashcabal install --lib random --package-env .``` + - or globally by ```bashcabal install --lib random``` + +If you don't have `cabal` (e.g. computers in labs), put the file [Random.hs](https://drive.google.com/file/d/11C-EC-5uhlBCTHlPF-tVdHT_aY2xauSM/view?usp=sharing) into the directory containing your Lab-13 code and replace `import System.Ramdom` with `import Random`. +::: + +The state monad `State s a` is a type constructor taking two parameters `s` and `a` representing type of states and output, respectively. +You can imagine this type as +```haskell +newtype State s a = State { runState :: s -> (a, s) } +``` +The unary type constructor `State s` is an instance of `Monad`. +The values enclosed in this monadic context are functions taking a state and returning a pair whose first component is an output value and the second one is a new state. Using the bind operator, we can compose such functions in order to create more complex stateful computations out of +simpler ones. +The function `runState :: State s a -> s -> (a, s)` is the accessor function extracting the actual function from +the value of type `State s a`. + +As `State s` is a monad, we can use all generic functions working with monads, including the do-notation. Apart from that, +the implementation of the state monad comes with several functions allowing to handle the state. + +```haskell +get :: State s s -- outputs the state but doesn't change it +put :: s -> State s () -- set the state to the given value, outputs empty value +modify :: (s -> s) -> State s () -- modifies the state by the given function, outputs empty value + +evalState :: State s a -> s -> a -- computes just the output +evalState p s = fst (runState p s) + +execState :: State s a -> s -> s -- computes just the final state +execState p s = snd (runState p s) +``` + +States in purely functional languages must be handled via accumulators added into function signatures. Using the state monad allows us to abstract +away those accumulators. + +## Exercise 1 + +Consider the function `reverse` reversing a given list. We can implement it as a tail-recursive function in the same way as in Scheme +using an accumulator. +```haskell +reverseA :: [a] -> [a] +reverseA xs = iter xs [] where + iter [] acc = acc + iter (y:ys) acc = iter ys (y:acc) +``` + +Now we try to implement that via the state monad. The above accumulator is a list. So we will use it as our state. We don't have to output anything +as the resulting reversed list is stored in the accumulator/state. Thus we are interested in the type `State [a] ()` whose values contain functions +of type `[a] -> ((), [a])`. We will implement a function `reverseS :: [a] -> State [a] ()` which takes +a list and returns a stateful computation reversing the given list (i.e., a monadic value enclosing a function of type `[a] -> ((), [a])` reversing the given list). + +I will show several variants. The first copies more or less the tail recursive function `reverseA`. +::: details Solution: `reverseS` +```haskell +reverseS :: [a] -> State [a] () +reverseS [] = return () -- if the list is empty, keep the state untouched and return the empty value +reverseS (x:xs) = do ys <- get -- if not, extract the state into ys + put (x:ys) -- change the state to x:ys + reverseS xs -- recursive call on the rest xs +``` +::: + +Now we can execute the returned computation as follows: +```haskell +> runState (reverseS [1,2,3,4]) [] +((),[4,3,2,1]) + +> execState (reverseS [1,2,3,4]) [] +[4,3,2,1] +``` + +The above variant just strips off the first element `x` and modifies the state by the function `(x:)`. Thus we can rewrite it as follows: +::: details Solution: `reverseS` +```haskell +reverseS :: [a] -> State [a] () +reverseS [] = return () -- if the list is empty, keep the state untouched and return the empty value +reverseS (x:xs) = do modify (x:) -- if not, update the state + reverseS xs -- recursive call on the rest xs +``` +::: + +Finally, the above variant is just applying the action `modify (x:)` for every `x` in the list. Thus we can use the monadic function +`mapM_ :: (a -> m b) -> [a] -> m ()` taking a function creating a monadic action from an argument of type `a` and a list of values of type `a`. The resulting action outputs the empty value. Once executed, it executes all the actions +returned by applying the given function to each element in the list. + +::: details Solution: `reverseS` +```haskell +reverseS :: [a] -> State [a] () +reverseS = mapM_ (modify . (:)) +``` +::: + +## Task 1 + Suppose you are given a list of elements. Your task is to return a list of all its pairwise different elements together with the number +of their occurrences. E.g. for `"abcaacbb"` it should return `[('a',3),('b',3),('c',2)]` in any order. A typical imperative approach to this problem is to keep a map from elements to their number of occurrences in memory (as a state). This state is updated as we iterate through the list. With the state monad, we can implement this approach in Haskell. + +First, we need a data structure representing a map from elements to their numbers of occurrences. We can simply represent it as a list of pairs +`(el, n)` where `el` is an element and `n` is its number of occurrences. We also define a type representing a stateful computation over +the map `Map a Int`. + +```haskell +type Map a b = [(a,b)] +type Freq a = State (Map a Int) () +``` + +::: tip Hint + First implement the following pure function taking an element `x` and a map `m` and returning an updated map. If the element +`x` is already in `m` (i.e., there is a pair `(x,n)`), then return the updated map, which is the same as `m` except the pair `(x,n)` +is replaced by `(x,n+1)`. If `x` is not in `m`, return the map extending `m` by `(x,1)`. To check that `x` is in `m`, +use the function `lookup :: Eq a => a -> [(a, b)] -> Maybe b` that returns `Nothing` if `x` is not in `m` and otherwise +`Just n` where `n` is the number of occurrences of `x`. +::: + +```haskell +update :: Eq a => a -> Map a Int -> Map a Int +update x m = case lookup x m of + Nothing -> (x,1):m + Just n -> (x,n+1):[p | p <- m, fst p /= x] +``` + +Once you have that, take the inspiration from Exercise 1 and implement a function `freqS`, taking a list and returning the stateful computation +that computes the map of occurrences once executed. E.g. + +```haskell +> execState (freqS "Hello World") [] +[('d',1),('l',3),('r',1),('o',2),('W',1),(' ',1),('e',1),('H',1)] +``` + +```haskell +freqS :: Eq a => [a] -> State (Map a Int) () +freqS = mapM_ (modify . update) +``` +::: details Alternatively you can do this +```haskell +freqS [] = return () +freqS (x:xs) = do m <- get + let m' = update x m + put m' + --modify (update x) -- or replace the first 3 lines with this + freqS xs +``` +::: + +## Exercise 2 + Recall that pseudorandom numbers from a given interval $(x,y)$ can be generated by the function +```haskell +randomR :: (RandomGen g, Random a) => (a, a) -> g -> (a, g) +``` +located in the module `System.Random`. It takes an interval and a generator and returns a random value of type `a` +in the given interval, together with +a new generator. `Random` is a type class collecting types whose random values can be generated by `randomR`. +A first generator can be created by `mkStdGen :: Int -> StdGen` from a given seed. + +If we want to generate a sequence of random numbers, we have to use in each step the new generator obtained from the previous step. +To abstract the generators away, we use the state monad whose states are generators, i.e., `State StdGen a` where `StdGen` is the type +of generators. The type `a` serves as the type of the generated random numbers. To shorten the type annotations, we introduce a new name: +```haskell +type R a = State StdGen a +``` + +Our task is to implement a function that integrates a function $f\colon\mathbb{R}\to\mathbb{R}$ on the given interval $(a,b)$ +by the Monte-Carlo method, i.e., we want to compute approximately $\int_a^b f(x)\mathrm{d}x$. +For simplicity, we assume that $f(x)\geq 0$ for all $x\in (a,b)$. The Monte-Carlo method is a sampling method. If we know an upper bound $u$ for $f$ on +the interval $(a,b)$, we can estimate the area below the graph of $f$ by generating a sequence of random points in the rectangle +$(a,b)\times(0,u)$. Then we count how many points are below $f$. The integral equals approximately $\frac{k}{n}(b-a)u$ where +$k$ is the number of points below the graph of $f$, and $n$ is the number of all generated points (see the picture). +![](/img/montecarlo.png){class="inverting-image" style="width: 100%; margin: auto;" } + +### Solution + We first prepare a stateful computation, generating a sequence of random points in a given rectangle. We define two types: +```haskell +type Range a = (a,a) +type Pair a = (a,a) +``` +The first one represents intervals and the second one points. Next, we define a function taking an interval and returning a stateful computation +generating a single random value in the given interval. + +::: details Solution: `randR` +```haskell +randR :: Random a => Range a -> R a +randR r = do g <- get -- get the current state, i.e. generator + let (x, g') = randomR r g -- generate a random number x together with a new generator g' + put g' -- change the state to g' + return x -- output x +``` +::: +The above function can be simplified using the constructor `state :: (s -> (a,s)) -> State s a` as was shown in the lecture. +```haskell +randR:: Random a => Range a -> R a +randR r = state (randomR r) +``` + +Since we need to generate points, we define a function taking two intervals and returning a stateful computation generating a random point in their Cartesian product. +::: details Solution: `randPair` +```haskell +randPair :: Random a => Range a -> Range a -> R (Pair a) +randPair xr yr = do + x <- randR xr -- generate x-coordinate + y <- randR yr -- generate y-coordinate + return (x,y) -- output the generated point +``` +::: + +Note that we don't have to deal with generators when sequencing `randR xr` with `randR yr`. Now if we want to generate a random point, we can +execute the stateful computation returned by `randPair`. E.g., we create an initial state/generator by `mkStdGen seed` and then use the `evalState` function because we are interested only in the output not the final generator. +```haskell +> evalState (randPair (0,1) (4,5)) (mkStdGen 7) +(0.6533518674031419,4.888537398010264) +``` +To simplify the above call, we define a function executing any stateful computation of type `R a`. +```haskell +runRandom :: R a -> Int -> a +runRandom action seed = evalState action $ mkStdGen seed +``` +Now we need a sequence of random points. We can define a recursive function doing that as follows: +::: details Solution: `randSeq` +```haskell +randSeq :: Random a => Range a -> Range a -> Int -> R [Pair a] +randSeq _ _ 0 = return [] -- if the number of points to be generated is 0, returns [] +randSeq xr yr n = do p <- randPair xr yr -- otherwise, generate a point p + ps <- randSeq xr yr (n-1) -- recursively generate the rest of points ps + return (p:ps) -- output p:ps + +> runRandom (randSeq (0,1) (4,5) 3) 7 +[(0.6533518674031419,4.888537398010264),(0.9946813218691467,4.707024867915484),(0.8495826522836318,4.720133514494717)] +``` +::: + +The function `randSeq` just sequences the actions `randPair` and collects their results. So we can use `sequence` +allowing to take a list of monadic actions and return the action, which is the sequence of those actions returning the list +of their outputs. To create a list of `randPair` actions, use the function `replicate`. +```haskell +> replicate 5 3 +[3,3,3,3,3] + +> runRandom (sequence $ replicate 3 (randPair (0,1) (0,1))) 7 +[(0.6533518674031419,0.8885373980102645),(0.9946813218691467,0.7070248679154837),(0.8495826522836318,0.7201335144947166)] +``` +There is a monadic version of `replicate`. So we can rewrite the last call as follows: +```haskell +> runRandom (replicateM 3 (randPair (0,1) (0,1))) 7 +[(0.6533518674031419,0.8885373980102645),(0.9946813218691467,0.7070248679154837),(0.8495826522836318,0.7201335144947166)] +``` + +Now we are ready to finish the Monte-Carlo integration. It takes as arguments a function $f$, an interval $(a,b)$, an upper bound $u$, and a number of points to be generated. +::: details Solution: `integrate` +```haskell +integrate :: (Double -> Double) -> Range Double -> Double -> Int -> Double +integrate f xr@(a,b) u n = whole * fromIntegral (length below) / (fromIntegral n) where -- compute the area below f + below = [(x,y) | (x,y) <- samples, y <= f x] -- get the list of points below f + whole = (b-a)*u -- area of the rectangle + samples = runRandom (replicateM n (randPair xr (0,u))) 123 -- generate samples +``` +::: + +You can test it on functions you know their integrals. +```haskell +> integrate id (0,1) 1 10000 -- f(x)=x on (0,1) should be 0.5 +0.499 + +> integrate (^2) (0,1) 1 10000 -- f(x)=x^2 on (0,1) should be 1/3 +0.3383 + +> integrate sin (0,pi) 1 10000 -- f(x)=sin x on (0,pi) should be 2 +2.0065352278478006 + +> integrate exp (0,1) 3 10000 -- f(x)=e^x on (0,1) should e-1 +1.7226 +``` + +## Task 2 + Implement a function generating a random binary tree having $n$ many nodes. To be more specific, consider the following type: +```haskell +data Tree a = Nil | Node a (Tree a) (Tree a) deriving (Eq, Show) +``` +The values of `Tree a` are binary trees having a value of type `a` in their nodes together with left and right children. +The `Nil` value indicates that there is no left (resp. right) child. Leaves are of the form `Node x Nil Nil`. + +Your task is to implement a function `randTree` taking a number of nodes `n` and natural number `k` and returning a stateful +computation generating a random binary tree having `n` many nodes containing values from $\{0,1,\ldots,k-1\}$. + +::: tip Hint + To generate random integers in a given interval, use the above function `randR`. Generating a random binary tree can be done recursively. In each node, you generate a random integer $m$ from $\{0,\ldots,n-1\}$. This is the number of nodes of the left subtree. +So you recursively generate the left subtree `ltree` with `m` many nodes. Then you recursively generate the right subtree `rtree` +with $n-m-1$ many nodes. Finally, you return `Node x ltree rtree` where `x` is a randomly generated integer from $\{0,1,\ldots,k-1\}$. +The base case for $n=0$ just returns `Nil`, i.e., no subtree. +::: + +```haskell +randTree :: Int -> Int -> R (Tree Int) +randTree 0 _ = return Nil +randTree n k = do m <- randR (0,n-1) + ltree <- randTree m k + rtree <- randTree (n-m-1) k + x <- randR (0,k-1) + return $ Node x ltree rtree +``` + +You can use your function to generate a random binary tree with 10 nodes containing integers from $\{0,1,2\}$ as follows: +```haskell +> runRandom (randTree 10 3) 1 +Node 1 (Node 0 (Node 2 Nil Nil) (Node 1 (Node 2 Nil Nil) (Node 1 Nil Nil))) (Node 1 (Node 1 Nil Nil) (Node 2 Nil (Node 2 Nil Nil))) +``` + +You can also check that the method does not provide a uniform distribution. +```haskell +> trees = runRandom (replicateM 10000 (randTree 3 2)) 1 +> execState (freqS trees) [] +[387,234,210,448,221,187,207,223,200,214,403,428,218,409,222,379,199,199,235,206,215,209,184,223,206,187,222,416,187,213,190,193,438,231,222,221,205,204,209,196] +``` \ No newline at end of file