From 61465178d395c9bcc21a771595f27d6280eb4d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Hurlin?= Date: Thu, 26 Sep 2024 10:45:39 +0200 Subject: [PATCH] Prepare course 5 --- slides/Course03.hs | 47 -------------------- slides/Course05.hs | 27 ++++++++++++ slides/course-03.md | 99 ------------------------------------------- slides/course-04.md | 20 ++++++++- slides/course-05.html | 31 ++++++++++++++ slides/course-05.md | 44 ++++++++++++++++++- tn-fp-course.cabal | 1 + 7 files changed, 120 insertions(+), 149 deletions(-) create mode 100644 slides/course-05.html diff --git a/slides/Course03.hs b/slides/Course03.hs index 1e29dd1..e8209cd 100644 --- a/slides/Course03.hs +++ b/slides/Course03.hs @@ -117,13 +117,6 @@ balance' = foldr (\op soFar -> toInt op + soFar) 0 where toInt = \case Debit x -> -x; Credit x -> x -class Functor f => Applicative f where - -- | Wraps a function in the functor - pure :: a -> f a - - -- | - (<*>) :: f (a -> b) -> f a -> f b - -- | @initials "Clément" "Hurlin"@ returns "CH" initials :: String -> String -> String initials firstname lastname = @@ -147,43 +140,3 @@ mkEmail firstName lastName domain ext = let right = domain ++ "." ++ ext in left ++ "@" ++ right -mkEmailSafe :: String -> String -> String -> Either String String -mkEmailSafe user host ext = - checkUsername user - >>= \(username :: String) -> - checkExt ext - >>= \(extension :: String) -> - Right (username ++ "@" ++ host ++ "." ++ extension) - where - checkUsername :: String -> Either String String - checkUsername s = - if all isLower s - then Right s - else Left ("Username should be lowercase, but found: " ++ s) - checkExt :: String -> Either String String - checkExt "com" = Right "com" - checkExt "fr" = Right "fr" - checkExt s = - Left ("Unexpected extension: " - ++ show s - ++ ". Expected one of: [\"com\", \"fr\"]") - -mkEmailSafe' :: String -> String -> String -> Either String String -mkEmailSafe' user host ext = do - username <- checkUsername user - extension <- checkExt ext - pure (username ++ "@" ++ host ++ "." ++ extension) - where - checkUsername :: String -> Either String String - checkUsername s = - if all isLower s - then Right s - else Left ("Username should be lowercase, but found: " ++ s) - checkExt :: String -> Either String String - checkExt "com" = Right "com" - checkExt "fr" = Right "fr" - checkExt s = - Left ("Unexpected extension: " - ++ show s - ++ ". Expected one of: [\"com\", \"fr\"]") - diff --git a/slides/Course05.hs b/slides/Course05.hs index 98781dc..ba91243 100644 --- a/slides/Course05.hs +++ b/slides/Course05.hs @@ -1,6 +1,33 @@ module Course05 where import Control.Monad.IO.Class +import Data.Char import Data.Word import Prelude hiding ((==), Bounded, Enum, Eq, Ordering, Show) +mkEmailSafe :: String -> String -> String -> Either String String +mkEmailSafe user host ext = + checkUsername user + >>= \(username :: String) -> + checkExt ext + >>= \(extension :: String) -> + Right (username ++ "@" ++ host ++ "." ++ extension) + +checkUsername :: String -> Either String String +checkUsername s | all isLower s = Right s + | otherwise = Left ("Username should be lowercase, but found: " ++ s) +checkExt :: String -> Either String String +checkExt = + \case + "com" -> Right "com" + "fr" -> Right "fr" + s -> Left ("Unexpected extension: " + ++ show s + ++ ". Expected one of: [\"com\", \"fr\"]") + +mkEmailSafe' :: String -> String -> String -> Either String String +mkEmailSafe' user host ext = do + username <- checkUsername user + extension <- checkExt ext + pure (username ++ "@" ++ host ++ "." ++ extension) + diff --git a/slides/course-03.md b/slides/course-03.md index 79329e9..9d54374 100644 --- a/slides/course-03.md +++ b/slides/course-03.md @@ -563,105 +563,6 @@ Its syntax is: `let varName = expression in expression` - What is the type of `mkEmail`? - How does inference work? ---- - -# More composition - -```bash -> import Data.Functor -> :type (<&>) -(<&>) :: Functor f => f a -> (a -> b) -> f b -> :type fmap -fmap :: Functor f => (a -> b) -> f a -> f b -``` - -- Given an element of type `a` wrapped in something (`f`), and a function from `a` to `b`, apply the function inside the wrapping. - -- What can be `f`? - -??? - -```bash -> import Data.List.Extra -> :type upper -upper :: String -> String -> applyUpper = fmap upper -> applyUpper (Just "foo") -> applyUpper (Right "foo" :: Either Int String) -``` - -??? - -If done at this point and time remains: - -- Explain `foldr` -- Explain things defined in terms of `foldr`: - - `sum` - - `and :: [Bool] -> Bool` - - `any :: (a -> Bool) -> [a] -> Bool` - ---- - -# More composition: monads - -```bash -> :type (>>=) -(>>=) :: Monad m => m a -> (a -> m b) -> m b -``` - -```hs -mkEmailSafe :: String -> String -> String -> Either String String -mkEmailSafe user host ext = - checkUsername user - >>= \(username :: String) -> - checkExt ext - >>= \(extension :: String) -> - Right (username ++ "@" ++ host ++ "." ++ extension) - where - checkUsername :: String -> Either String String - checkUsername s = - if all isLower s - then Right s - else Left ("Username should be lowercase, but found: " ++ s) - checkExt :: String -> Either String String - checkExt "com" = Right "com" - checkExt "fr" = Right "fr" - checkExt s = - Left ("Unexpected extension: " - ++ show s - ++ ". Expected one of: [\"com\", \"fr\"]") -``` - ---- - -# User friendly monads: the `do` notation - -```bash -> :type (>>=) -(>>=) :: Monad m => m a -> (a -> m b) -> m b -``` - -```hs -mkEmailSafe' :: String -> String -> String -> Either String String -mkEmailSafe' user host ext = do - username <- checkUsername user - extension <- checkExt ext - pure (username ++ "@" ++ host ++ "." ++ extension) - where - checkUsername :: String -> Either String String - checkUsername s = - if all isLower s - then Right s - else Left ("Username should be lowercase, but found: " ++ s) - checkExt :: String -> Either String String - checkExt "com" = Right "com" - checkExt "fr" = Right "fr" - checkExt s = - Left ("Unexpected extension: " - ++ show s - ++ ". Expected one of: [\"com\", \"fr\"]") -``` - + + + + + diff --git a/slides/course-05.md b/slides/course-05.md index 139a9dc..dfc1be4 100644 --- a/slides/course-05.md +++ b/slides/course-05.md @@ -19,6 +19,7 @@ Clément Hurlin module Course05 where import Control.Monad.IO.Class +import Data.Char import Data.Word import Prelude hiding ((==), Bounded, Enum, Eq, Ordering, Show) ``` @@ -39,7 +40,7 @@ class Course05 { In this course:
- Advanced Type System + Mastering the Type System

@@ -48,9 +49,48 @@ In this course: # Monads +```bash +> :type (>>=) +(>>=) :: Monad m => m a -> (a -> m b) -> m b +``` + +```hs +mkEmailSafe :: String -> String -> String -> Either String String +mkEmailSafe user host ext = + checkUsername user + >>= \(username :: String) -> + checkExt ext + >>= \(extension :: String) -> + Right (username ++ "@" ++ host ++ "." ++ extension) + +checkUsername :: String -> Either String String +checkUsername s | all isLower s = Right s + | otherwise = Left ("Username should be lowercase, but found: " ++ s) +checkExt :: String -> Either String String +checkExt = + \case + "com" -> Right "com" + "fr" -> Right "fr" + s -> Left ("Unexpected extension: " + ++ show s + ++ ". Expected one of: [\"com\", \"fr\"]") +``` --- -# Type Applications +# User friendly monads: the `do` notation + +```bash +> :type (>>=) +(>>=) :: Monad m => m a -> (a -> m b) -> m b +``` + +```hs +mkEmailSafe' :: String -> String -> String -> Either String String +mkEmailSafe' user host ext = do + username <- checkUsername user + extension <- checkExt ext + pure (username ++ "@" ++ host ++ "." ++ extension) +``` --- diff --git a/tn-fp-course.cabal b/tn-fp-course.cabal index 3c30766..aefb2a6 100644 --- a/tn-fp-course.cabal +++ b/tn-fp-course.cabal @@ -60,6 +60,7 @@ library slides Course02 Course03 Course04 + Course05 executable TP1.hs import: common-all