Skip to content

Commit a386cef

Browse files
committed
Published Handling Errors lesson
1 parent e01ea67 commit a386cef

File tree

9 files changed

+2185
-19
lines changed

9 files changed

+2185
-19
lines changed

Homework/Homework15/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Revision history for Homework15
2+
3+
## 0.1.0.0 -- YYYY-mm-dd
4+
5+
* First version. Released on an unsuspecting world.

Homework/Homework15/Homework15.cabal

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cabal-version: 3.0
2+
name: Homework15
3+
version: 0.1.0.0
4+
license: MIT
5+
license-file: LICENSE
6+
author: Robertino Martinez
7+
maintainer: robertino.martinez@iohk.io
8+
build-type: Simple
9+
extra-doc-files: CHANGELOG.md
10+
11+
common warnings
12+
ghc-options: -Wall
13+
14+
executable Homework15A
15+
import: warnings
16+
main-is: Homework15A.hs
17+
build-depends: base ^>=4.16.4.0
18+
hs-source-dirs: app
19+
default-language: Haskell2010
20+
21+
22+
library
23+
import: warnings
24+
build-depends: base ^>=4.16.4.0
25+
hs-source-dirs: src
26+
exposed-modules: Homework15B
27+
default-language: Haskell2010

Homework/Homework15/LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2023 Robertino Martinez
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included
12+
in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Homework/Homework15/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
## Homework
3+
4+
1. Read the [Data.Maybe](https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Maybe.html) and [Data.Either](https://hackage.haskell.org/package/base-4.18.0.0/docs/Data-Either.html) modules.
5+
2. Read the [Control.Exception](https://hackage.haskell.org/package/base-4.18.0.0/docs/Control-Exception.html) module skipping the "Asynchronous Exceptions" section.
6+
3. Solve Homework15A (inside `app` directory) and Homework15B (inside `src`).
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
module Main where
2+
3+
import Control.Exception (catch, try)
4+
import Text.Read (readMaybe)
5+
6+
--------------------------------------------------------------------------------
7+
--------------------------------------------------------------------------------
8+
-- IMPORTANT: Read the README.md file before completing the homework.
9+
--------------------------------------------------------------------------------
10+
--------------------------------------------------------------------------------
11+
12+
-- This is a CLI application that allows the user to manage a TODO list.
13+
-- The user can add and remove items from the list and save and load the list
14+
-- from a file.
15+
-- It's a working prototype, but it has some bugs. Specifically, it doesn't
16+
-- handle errors very well. Your mission, should you choose to accept it, is to
17+
-- fix those bugs and make the application more robust. Hint: Try to interact
18+
-- with the application in unexpected ways and see what happens! You should be
19+
-- able to find and fix 3 bugs.
20+
21+
printTodoItem :: (Int, String) -> IO ()
22+
printTodoItem (n, todo) = putStrLn (show n ++ ": " ++ todo)
23+
24+
prompt :: [String] -> IO ()
25+
prompt todos = do
26+
putStrLn ""
27+
putStrLn "Current TODO list:"
28+
foldr (\x k -> printTodoItem x >> k) (return ()) (zip [0 ..] todos)
29+
command <- getLine
30+
interpretCommand command todos
31+
32+
delete :: Maybe Int -> [a] -> [a]
33+
delete Nothing as = as
34+
delete _ [] = []
35+
delete (Just 0) (_ : as) = as
36+
delete (Just n) (a : as) = a : delete (Just (n - 1)) as
37+
38+
interpretCommand :: String -> [String] -> IO ()
39+
interpretCommand cmd todos = case cmd of
40+
"q" -> return ()
41+
('+' : ' ' : todo) -> prompt (todo : todos)
42+
('-' : ' ' : num) -> prompt $ delete (readMaybe num) todos
43+
('s' : ' ' : fn) ->
44+
writeFile fn (show todos) `catch` \e -> do
45+
putStrLn $ "Could not write to file because: " ++ show (e :: IOError)
46+
prompt todos
47+
-- There's no reason as to why this and the previous case should handle
48+
-- errors differently. I did it this way so you can see how to handle errors
49+
-- in different ways.
50+
('l' : ' ' : fn) -> do
51+
contents <- try $ readFile fn >>= return . read
52+
case contents of
53+
Left e -> do
54+
putStrLn $ "Could not read from file because: " ++ show (e :: IOError)
55+
prompt todos
56+
Right todos' -> prompt todos'
57+
_ -> do
58+
putStrLn ("Invalid command: `" ++ cmd ++ "`")
59+
prompt todos
60+
61+
printCommands :: IO ()
62+
printCommands = do
63+
putStrLn "Commands:"
64+
putStrLn "+ <Item Name> - Add a TODO entry"
65+
putStrLn "- <Item Number> - Delete the numbered entry"
66+
putStrLn "s <File Name> - Save the current list of TODOs"
67+
putStrLn "l <File Name> - Load the saved list of TODOs"
68+
putStrLn "q - Quit without saving"
69+
70+
main :: IO ()
71+
main = do
72+
printCommands
73+
prompt []

Homework/Homework15/hye.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cradle:
2+
cabal:
3+
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{-# LANGUAGE ScopedTypeVariables #-}
2+
3+
module Homework15B where
4+
5+
import Control.Exception (IOException, try)
6+
7+
--------------------------------------------------------------------------------
8+
--------------------------------------------------------------------------------
9+
-- IMPORTANT: Read the README.md file before completing the homework.
10+
--------------------------------------------------------------------------------
11+
--------------------------------------------------------------------------------
12+
13+
-- 1. Write a function that takes a list and returns the head if the list is not empty.
14+
-- If the list is empty, return Nothing.
15+
16+
headMaybe :: [a] -> Maybe a
17+
headMaybe [] = Nothing
18+
headMaybe (x : _) = Just x
19+
20+
-- 2. Write a function that takes a list of Maybe values and returns a list of all the Just values.
21+
-- If there are no Just values, return an empty list.
22+
23+
catMaybes :: [Maybe a] -> [a]
24+
catMaybes [] = []
25+
catMaybes (Nothing : xs) = catMaybes xs
26+
catMaybes (Just x : xs) = x : catMaybes xs
27+
28+
-- 3. Write a function that tries to read from a file and returns the contents of the file.
29+
-- If the file does not exist, return Nothing.
30+
31+
readFileMaybe :: FilePath -> IO (Maybe String)
32+
readFileMaybe path = do
33+
contents <- try $ readFile path
34+
case contents of
35+
Left (_ :: IOException) -> return Nothing
36+
Right c -> return (Just c)
37+
38+
-- 4. Write a function that checks all the requirements for a password using the
39+
-- Either type with a custom data type for errors.
40+
-- The requirements are:
41+
-- - The password must be at least 10 characters long.
42+
-- - The password must contain at least one digit.
43+
-- - The password must contain at least one uppercase letter.
44+
-- - The password must contain at least one lowercase letter.
45+
46+
data PasswordError
47+
= NotLongEnough
48+
| NoDigit
49+
| NoUppercase
50+
| NoLowercase
51+
deriving (Eq, Show)
52+
53+
passwordLongEnough :: String -> Either PasswordError String
54+
passwordLongEnough password =
55+
if length password >= 10
56+
then Right password
57+
else Left NotLongEnough
58+
59+
passwordHasDigit :: String -> Either PasswordError String
60+
passwordHasDigit password =
61+
if any (`elem` ['0' .. '9']) password
62+
then Right password
63+
else Left NoDigit
64+
65+
passwordHasUppercase :: String -> Either PasswordError String
66+
passwordHasUppercase password =
67+
if any (`elem` ['A' .. 'Z']) password
68+
then Right password
69+
else Left NoUppercase
70+
71+
passwordHasLowercase :: String -> Either PasswordError String
72+
passwordHasLowercase password =
73+
if any (`elem` ['a' .. 'z']) password
74+
then Right password
75+
else Left NoLowercase
76+
77+
--------------------------------------------------------------------------------
78+
--------------------------------------------------------------------------------
79+
-- As you can see, the passwordRequirements function is very repetitive.
80+
-- This is one of the downsides of using nested optional values.
81+
-- We're going to solve this problem in the "Basic Abstractions" section of the coruse.
82+
--------------------------------------------------------------------------------
83+
--------------------------------------------------------------------------------
84+
85+
passwordRequirements :: String -> Either PasswordError String
86+
passwordRequirements password =
87+
case passwordLongEnough password of
88+
Left err -> Left err
89+
Right _ -> case passwordHasDigit password of
90+
Left err -> Left err
91+
Right _ -> case passwordHasUppercase password of
92+
Left err -> Left err
93+
Right _ -> case passwordHasLowercase password of
94+
Left err -> Left err
95+
Right _ -> Right password

README.md

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Haskell Course
22

3-
[Versión en 🇪🇸](https://github.com/input-output-hk/haskell-course/tree/main/ES-translation)
3+
[Versión en 🇪🇸 traducida por la comunidad](https://github.com/input-output-hk/haskell-course/tree/main/ES-translation)
4+
5+
> *The easiest way to learn Haskell* - R.M.
46
57
**This course is designed to teach non-engineers (e.g., self-taught/bootcamp coders) Haskell from zero to productive in an interactive, easy-to-follow way.** The course doesn't contain content specific to [Marlowe](https://marlowe.iohk.io/) or [Plutus](https://plutus.readthedocs.io/en/latest/), but it will cover everything needed to work with them.
68

@@ -242,7 +244,7 @@ In this section, we learn about Haskell tooling and the necessary concepts to st
242244
- Controlling environments
243245
- Controlling namespaces
244246
- Creating our own Modules
245-
- The Prelude and Standard Libraries
247+
- The `Prelude` and Standard Libraries
246248

247249
### 14. Cabal and language extensions [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/input-output-hk/haskell-course/HEAD?labpath=%2Flessons%2F14-Cabal_and_language_extensions.ipynb) [![YouTube](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=flat&logo=YouTube&logoColor=white)](https://www.youtube.com/watch?v=AvpMOMSSZHs&list=PLNEK_Ejlx3x1D9Vq5kqeC3ZDEP7in4dqb&index=15)
248250

@@ -253,29 +255,37 @@ In this section, we learn about Haskell tooling and the necessary concepts to st
253255
- Building and running our executable
254256
- Language extensions and Pragmas
255257
- Introduction
256-
- NumericUnderscores
257-
- TypeApplications
258-
259-
### 14. Handling Errors
260-
261-
- TODO
258+
- `NumericUnderscores`
259+
- `TypeApplications`
260+
261+
### 14. Handling Errors [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/input-output-hk/haskell-course/HEAD?labpath=%2Flessons%2F15-Handling-Errors.ipynb) [![YouTube](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=flat&logo=YouTube&logoColor=white)](https://www.youtube.com/watch?v=QkUCHFG1hK8&list=PLNEK_Ejlx3x1D9Vq5kqeC3ZDEP7in4dqb&index=16)
262+
263+
- There're always `Exception`s to the rule
264+
- Speed-running `Exception`s with a dumb self-driving 🤖 car 🚗
265+
- I'm the `Exception` cause I have `class` 😎
266+
- `throw` all the `Exception`s you want. I'll `catch` them all!
267+
- `Maybe` give me a value? 🙏
268+
- Benefits of optional values
269+
- Ok, you `Either` give me a value or a reason why you didn't!
270+
- From `Exception`s to optional values
271+
- Tradeoffs
272+
- So, what should I use?
262273

263274
### 15. Learning on your own and Map
264275

265276
- Using GHCi to find out more
266277
- Hoogle
267278
- HaskellWiki
268279
- Walking through while teaching Map module
280+
- TODO
269281

270282
---
271283

272-
#### Congratulations! 🥳 You can call yourself a (beginner) Haskell developer!
273-
274-
#### YOU'RE READY FOR THE MARLOWE PIONEER PROGRAM! 🥳🎉 (Keep going for Plutus.)
284+
#### YOU'RE READY FOR MARLOWE! 🥳🎉 (Keep going for Plutus)
275285

276286
---
277287

278-
### INTERMEDIATE SECTION - BASIC ABSTRACTIONS - 🐥⟶🐓
288+
### BEGINNER SECTION - BASIC ABSTRACTIONS - 🐥⟶🐓
279289
In this section, we learn about a few of the most useful and talked about Abstractions in Haskell.
280290

281291
---
@@ -301,7 +311,7 @@ In this section, we learn about a few of the most useful and talked about Abstra
301311
- Extracting the pattern
302312
- Complete definition (with all the details/laws)
303313

304-
### x. Aeson
314+
### x. Aeson?
305315

306316
- TODO (some project using Aeson)
307317

@@ -341,17 +351,22 @@ In this section, we learn about a few of the most useful and talked about Abstra
341351
- mapM and mapM\_
342352
- filterM
343353
- foldM
354+
- ...
344355

345356
---
346357

347-
### TODO: It keeps going, but I'm not sure about the outline yet. 😬
358+
#### 🥳 CONGRATULATIONS! 🥳 You can call yourself a (beginner) Haskell developer!
348359

360+
---
361+
362+
### TODO: It keeps going, but I'm not sure about the outline yet. 😬
349363
Possible subjects:
350-
- Testing
351-
- TLP
352-
- Template Haskell
353-
- More abstractions
354-
- Programming patterns
364+
- More abstractions?
365+
- Testing?
366+
- Concurrency and Parallelism?
367+
- TLP?
368+
- Template Haskell?
369+
- ...
355370

356371
---
357372

0 commit comments

Comments
 (0)