# Lecture 4

## Maybe, yes? Maybe, no?

maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = case ma of
Nothing -> Nothing
Just a  -> case mb of
Nothing -> Nothing
Just b  -> Just (a + b)

🥺👉👈 Awkward pattern matching

andThen :: Maybe Int -> (Int -> Maybe Int) -> Maybe Int
andThen ma f = case ma of
Nothing -> Nothing
Just x  -> f x
maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = andThen ma (\a -> andThen mb (\b -> Just (a + b)))

💊 Ordinary helper function

🛠 Refactoring

andThen :: Maybe a -> (a -> Maybe b) -> Maybe b
andThen ma f = case ma of
Nothing -> Nothing
Just x  -> f x

## Either way

eitherPlus :: Either String Int -> Either String Int -> Either String Int
eitherPlus ea eb = case ea of
Left err -> Left err
Right a  -> case eb of
Left err -> Left err
Right b  -> Right (a + b)

🥺👉👈 Awkward pattern matching strikes again

andThen :: Either String Int
-> (Int -> Either String Int)
-> Either String Int
andThen ea f = case ea of
Left err -> Left err
Right x  -> f x
eitherPlus :: Either String Int -> Either String Int -> Either String Int
eitherPlus ea eb = andThen ea (\a -> andThen eb (\b -> Right (a + b)))

💊 Ordinary helper function

🛠 Refactoring

andThen :: Either e a
-> (a -> Either e b)
-> Either e b
andThen ea f = case ea of
Left err -> Left err
Right x  -> f x

## Multiple combinations

listPlus :: [Int] -> [Int] -> [Int]
listPlus la lb = case la of
[]     -> []
a : as -> case lb of
[] -> []
bs -> map (+ a) bs ++ listPlus as bs

🥺👉👈 Even more awkward pattern matching

andThen :: [Int] -> (Int -> [Int]) -> [Int]
andThen l f = case l of
[]     -> []
x : xs -> f x ++ andThen xs f
listPlus :: [Int] -> [Int] -> [Int]
listPlus la lb = andThen la (\a -> andThen lb (\b -> [a + b]))

💊 Ordinary helper function

🛠 Refactoring

andThen :: [a] -> (a -> [b]) -> [b]
andThen l f = case l of
[]     -> []
x : xs -> f x ++ andThen xs f

🐌 The function became slower after refactoring!

## Is there a pattern?

andThen :: Maybe    a  -> (a -> Maybe    b)  -> Maybe    b
andThen :: Either e a  -> (a -> Either e b)  -> Either e b
andThen ::         [a] -> (a ->         [b]) ->         [b]

🔍 Very similar type signatures

maybePlus  ma mb = andThen ma (\a -> andThen mb (\b -> Just  (a + b)))
eitherPlus ea eb = andThen ea (\a -> andThen eb (\b -> Right (a + b)))
listPlus   la lb = andThen la (\a -> andThen lb (\b ->       [a + b]))

👀 Almost the same implementations

## What to do when we see a pattern?

### 3. Copy-paste

📜 Monad is a generalization of the "andThen" pattern

### How to generalize? 🤔

We need:

1. Polymorphic andThen
2. Polymorphic constructor
maybePlus  ma mb = andThen ma (\a -> andThen mb (\b -> Just  (a + b)))
eitherPlus ea eb = andThen ea (\a -> andThen eb (\b -> Right (a + b)))
listPlus   la lb = andThen la (\a -> andThen lb (\b ->       [a + b]))

class Monad m where
return :: a -> m a
(>>=)  :: m a -> (a -> m b) -> m b

🧑‍🎓 What we can already learn from the definition

🚫 What we can't see from the above

2. It has two methods
3. The second method is an operator (it's called bind)
4. It's a typeclass for type constructors like Maybe and not e.g. Int
1. Instances implemementations
2. Laws
3. How to use this abstraction efficiently

## Instances

instance Monad Maybe where
return :: a -> Maybe a
return x = Just x

(>>=) :: Maybe a
-> (a -> Maybe b)
-> Maybe b
Nothing >>= _ = Nothing
Just x  >>= f = f x

ℹ️ Maybe

class Monad m where
return :: a -> m a
(>>=)  :: m a -> (a -> m b) -> m b
instance Monad (Either e) where
return :: a -> Either e a
return x = Right x

(>>=) :: Either e a
-> (a -> Either e b)
-> Either e b
Left e  >>= _ = Left e
Right x >>= f = f x
instance Monad [] where
return :: a -> [a]
return x = [x]

(>>=) :: [a] -> (a -> [b]) -> [b]
l >>= f = concatMap f l

ℹ️ Either

ℹ️ List

## Laws

instance Monad Maybe where
return :: a -> Maybe a
return x = Just x

...

🍏 Correct Monad instance for Maybe

Left identity

Right identity

Associativity

\mathrm{return} \ a\ \gg =\ f \equiv f \ a
m \ \gg = \ \mathrm{return} \equiv m
(m \gg = f) \gg = g \equiv m \gg = (\lambda x \rightarrow f \ x \gg = g)
instance Monad Maybe where
return :: a -> Maybe a
return x = Nothing

...

🐛 Incorrect Monad instance for Maybe

## Generalizing

andThen ::            Maybe    a  -> (a -> Maybe    b)  -> Maybe    b
andThen ::            Either e a  -> (a -> Either e b)  -> Either e b
andThen ::                    [a] -> (a ->         [b]) ->         [b]

🔍 Similar chaining functions

(>>=)   :: Monad m => m        a  -> (a -> m        b)  -> m        b

🔍 Similar constructors

Just   ::            a -> Maybe    a
Right  ::            a -> Either e a
(:[])  ::            a ->         [a]    -- robot monkey operator
return :: Monad m => a -> m        a

## Refactoring

maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = andThen ma (\a -> andThen mb (\b -> Just (a + b)))

0️⃣ Starting with the basics

maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = ma andThen (\a -> mb andThen (\b -> Just (a + b)))
maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = ma andThen \a -> mb andThen \b -> Just (a + b)

1️⃣ Using infix form of andThen

2️⃣ Removing redundant ()

maybePlus :: Maybe Int -> Maybe Int -> Maybe Int
maybePlus ma mb = ma >>= \a -> mb >>= \b -> return (a + b)
monadPlus :: Monad m => m Int -> m Int -> m Int
monadPlus ma mb = ma >>= \a -> mb >>= \b -> return (a + b)

3️⃣ Replacing andThen with >>= and Just with return

4️⃣Generalizing the type and changing the name

class Functor f where
fmap :: (a -> b) -> f a -> f b

class Functor f => Applicative f where
pure  :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b

class Applicative m => Monad m where
return :: a -> m a
return = pure

(>>=) :: m a -> (a -> m b) -> m b

ℹ️ Monad is a part of FAMily

# Real World

## Purity 💧

map :: (a -> b) -> [a] -> [b]

📜 Pure functions — functions without side-effects that depend only on their explicit input arguments.

## 💧 Purity + Laziness 🦥

getLine :: String

🤔 How would a function that reads a line would look like?

ghci> getTwoLines !! 1
???????

getTwoLines :: [String]
getTwoLInes = [getLine, getLine]

🤔🤔🤔 How this should work???

### Conclusion

💡 We can't have side effects in Haskell without changing at least something. Otherwise, we'll lose the remainings of our sanity while working with the language.

## Input/Output (IO)

data IO a = ...

ℹ️ Opaque data type IO

ℹ️ Functions with side-effects

getLine :: IO String

👩‍🔬 getLine is a function that returns a value of type String and also performs some side-effects

ℹ️ IO has the Monad instance

instance Monad IO where
return :: a -> IO a
(>>=)  :: IO a -> (a -> IO b) -> IO b
...

👩‍🔬 The Monad instance for IO allows to chain effectful actions

getTwoLines :: IO [String]
getTwoLines =
getLine >>= \line1 -> getLine >>= \line2 -> pure [line1, line2]

## Concept of IO

String
IO String

## How to run IO?

ℹ️ A helper function to print to the terminal

putStrLn :: String -> IO ()

👩‍🔬 putStrLn is a function that takes a value of type String, prints it the terminal and doesn't return any meaningful value.

ghci> ()  -- a unit type
()
ghci> :t ()
() :: ()
ghci> putStrLn "Hi! 👋"
Hi! 👋
ghci> :t getLine
getLine :: IO String
ghci> getLine
Alice
"Alice"
ghci> fmap length getLine
Bob
3

## How to run Haskell programs?

module Main where

main :: IO ()
main = ... your program goes here ...

👩‍🔬 Haskell program starts with the main function in the module Main

module Main where

main :: IO ()
main = putStrLn "Hello, world!"

## Printing twice

❓We want to print two different lines

putStrLn :: String -> IO ()

👩‍🔬 We use the bind operator (>>=) and ignore the putStrLn resutl

module Main where

main :: IO ()
main = putStrLn "Hello, Alice!" >>= \_ -> putStrLn "Hello, Bob!"
(>>) :: Monad m => m a -> m b -> m b
action1 >> action2 = action1 >>= \_ -> action2

ℹ️ A helper function

main :: IO ()
main = putStrLn "Hello, Alice!" >> putStrLn "Hello, Bob!"

ℹ️ Slightly shorter version

## do

📜 do-notation — syntax sugar for >>=, >> and let-in

example1 =
fun1 >>= \result -> fun2 result
example1 = do
result <- fun1
fun2 result

ℹ️ >>= rule

example1 = fun1 >>= fun2

Eta-reduced example1 with >>=

ℹ️ >> rule

example2 = fun1 >> fun2
example2 = do
fun1
fun2

ℹ️ let-in rule

example3 = let x = f y in fun x
example3 = do
let x = f y
fun x

## Example with do

⚙️ Write a program that reads a line and prints its reverse

main :: IO ()
main =
getLine >>= \line ->
let rev = reverse line in
putStrLn rev
main :: IO ()
main = do
line <- getLine
let rev = reverse line
putStrLn rev

### ⛔️ Common mistake #1

let line = getLine
rev <- reverse line

🏖 do-Style

# Cabal

## Cabal

📜 Cabal — format for describing structure of Haskell packages.

my-project/
├── app/
│   └── Main.hs
├── src/
│   ├── MyModule.hs
│   └── AnotherModule.hs
└── my-project.cabal
cabal-version:      2.4
name:               my-project
version:            1.0.0.0

library
hs-source-dirs:      src
exposed-modules:     MyModule
AnotherModule

build-depends:       base ^>= 4.14

executable my-project
hs-source-dirs:   app
main-is:          Main.hs

build-depends:    my-project
, base

📜 Files with the .cabal file extension describe the package.

📜 cabal-install — a Haskell build tool that works with Cabal packages.

## Typical main

module Main (main) where

import qualified MyModule

main :: IO ()
main = MyModule.main

## build-depends

library
hs-source-dirs:      src
exposed-modules:     MyModule

build-depends:       base       ^>= 4.14
, containers ^>= 0.6
, text       ^>= 1.2
, time       ^>= 1.9

📜 The build-depends field in the .cabal file specifies external Haskell packages and their versions you want to use.

📦 base — standard Haskell library

📦 containers — Map and Set data structures

📦 text — efficient UTF-16 strings (UTF-8 since version 2.0)

📦 bytestring — byte arrays

📦 time — time, clocks and calendar data types and functions

📦 aeson — JSON parsing

ℹ️ Hackage has 16K+ packages

## Functional 🌽, Imperative 🐚

readFile   :: FilePath -> IO Text
countWords :: Text -> IO (Map Text Int)
printWord  :: Map Text Int -> IO ()

👩‍🔬 Haskell allows controlling side effects. Separate pure logic from effectful computations and require IO only when needed.

⚙️ Write a program that finds the most frequent word in a file

🔢 Imperative style

🤸 Functional style

readFile      :: FilePath -> IO Text

countWords    :: Text -> Map Text Int
findFrequent  :: Map Text Int -> Maybe (Text, Int)
displayResult :: Maybe (Text, Int) -> Text

putStrLn      :: Text -> IO ()