Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
pp:2025:l11 [2025/05/18 13:01] cata_chiru |
pp:2025:l11 [2025/05/18 13:35] (current) cata_chiru [11.3. Nice to read] |
||
---|---|---|---|
Line 97: | Line 97: | ||
Applicates, as monads, are used preponderantly for type construction and validation. | Applicates, as monads, are used preponderantly for type construction and validation. | ||
- | 1. For the first task we will want to validate a database of users. | + | 5. For the first task we will want to validate a database of users. |
Being given the following data types: | Being given the following data types: | ||
Line 114: | Line 114: | ||
</code> | </code> | ||
- | 1.1. Create the instance of Applicative for Validation. | + | 5.1. Create the instance of Applicative for Validation. |
- | 1.2. Create functions to validate each attribute of a user. | + | 5.2. Create functions to validate each attribute of a user. |
<code haskell> | <code haskell> | ||
Line 130: | Line 130: | ||
Balance can also be negative. | Balance can also be negative. | ||
- | 1.3. Make use of the above functions, and the functions from Applicative, as well as infixed fmap ''(<$>)'' to create a validation function for the user. | + | 5.3. Make use of the above functions, and the functions from Applicative, as well as infixed fmap ''(<$>)'' to create a validation function for the user. |
<code haskell> | <code haskell> | ||
Line 136: | Line 136: | ||
</code> | </code> | ||
- | 1.4 Create unpackUser that takes a tuple and returns a User: | + | 5.4 Create unpackUser that takes a tuple and returns a User: |
<code haskell> | <code haskell> | ||
Line 142: | Line 142: | ||
</code> | </code> | ||
- | 1.5 Being given the following list of user data: | + | 5.5 Being given the following list of user data: |
<code haskell> | <code haskell> | ||
Line 156: | Line 156: | ||
</code> | </code> | ||
- | 1.6 Filter the users with a negative balance. | + | 5.6 Filter the users with a negative balance. |
<code haskell> | <code haskell> | ||
filter_debtors :: BankAccount -> BankAccount | filter_debtors :: BankAccount -> BankAccount | ||
+ | </code> | ||
+ | |||
+ | 6. Recall what a parser is from the course lecture: | ||
+ | |||
+ | <code haskell> | ||
+ | import Data.Char | ||
+ | import Control.Applicative | ||
+ | |||
+ | data Expr = Var String | Val Int | Plus Expr Expr deriving Show | ||
+ | |||
+ | data Parser a = Parser (String -> [(a,String)]) | ||
+ | |||
+ | parse (Parser p) s = p s | ||
+ | |||
+ | instance Monad Parser where | ||
+ | -- (>>=) :: Parser a -> (a -> Parser b) -> Parser b | ||
+ | mp >>= f = Parser $ \s -> | ||
+ | case parse mp s of | ||
+ | [] -> [] | ||
+ | [(v,r)] -> parse (f v) r | ||
+ | return x = Parser $ \s -> [(x,s)] | ||
+ | |||
+ | instance Applicative Parser where | ||
+ | af <*> mp = | ||
+ | do | ||
+ | f <- af | ||
+ | v <- mp | ||
+ | return $ f v | ||
+ | pure = return | ||
+ | |||
+ | instance Functor Parser where | ||
+ | fmap f mp = | ||
+ | do | ||
+ | x <- mp | ||
+ | return $ f x | ||
+ | |||
+ | |||
+ | charParser :: Char -> Parser Char | ||
+ | charParser c = Parser $ \s -> | ||
+ | case s of | ||
+ | [] -> [] | ||
+ | (x:xs) -> if (x == c) then [(x,xs)] else [] | ||
+ | |||
+ | predicateParser :: (Char -> Bool) -> Parser Char | ||
+ | predicateParser p = Parser $ \s -> | ||
+ | case s of | ||
+ | [] -> [] | ||
+ | (x:xs) -> if p x then [(x,xs)] else [] | ||
+ | |||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | 6.1 Try to understand and reimplement the instances for Functor, Applicative and Monad for Parser yourself. | ||
+ | |||
+ | 6.2 Using the definitions above and functions from Data.Char [5], implement letter - that parses one letter of the input, and digit - that parses one digit (given as a char) of the input. | ||
+ | |||
+ | <code haskell> | ||
+ | letter :: Parser Char | ||
+ | letter = undefined | ||
+ | |||
+ | digit :: Parser Char | ||
+ | digit = undefined | ||
+ | </code> | ||
+ | |||
+ | 6.3 Use letter, digit and functions from the classes studied in this laboratory to define letterDigit that parses one letter and one digit one after the other: | ||
+ | |||
+ | <code haskell> | ||
+ | letterDigit :: Parser (Char,Char) | ||
+ | letterDigit = undefined | ||
+ | |||
+ | positive_parse_ex = parse letterDigit "a1b2c3" -- by calling this in the command line we should get [(('a','1'),"b2c3")] | ||
+ | negative_parse_ex = parse letterDigit "aa2a" -- by calling this in the command line we should get [] | ||
</code> | </code> | ||
Line 173: | Line 246: | ||
4. https://www.youtube.com/watch?v=FLAPIgvlVnE&t=1945s&ab_channel=JamesHobson | 4. https://www.youtube.com/watch?v=FLAPIgvlVnE&t=1945s&ab_channel=JamesHobson | ||
+ | 5. [Data.Char Library](https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Char.html) | ||