Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pp:2025:l10 [2025/05/11 21:56]
ldaniel created
pp:2025:l10 [2025/05/11 21:58] (current)
ldaniel
Line 1: Line 1:
-====== Lab 11. Functors & Monads ======+====== Lab 10. Functors & Monads ======
  
-===== 11.0. Understanding Functors and Monads =====+===== 10.0. Understanding Functors and Monads =====
  
 ==== Functor ===== ==== Functor =====
Line 92: Line 92:
 </​code>​ </​code>​
  
-===== 11.1. Working with '​Maybe'​ =====+===== 10.1. Working with '​Maybe'​ =====
  
 ''​Maybe''​ is already defined as a Functor and Monad: ''​Maybe''​ is already defined as a Functor and Monad:
Line 112: Line 112:
 This section is meant to accommodate you to using Functors and Monads by playing around with an already implemented and familiar Monad: Maybe. This section is meant to accommodate you to using Functors and Monads by playing around with an already implemented and familiar Monad: Maybe.
  
-**11.1.1.** Implement a function ''​add5''​ that adds 5 to a ''​Maybe Int'',​ use ''​fmap''​ instead of ''​case''​ or pattern matching.+**10.1.1.** Implement a function ''​add5''​ that adds 5 to a ''​Maybe Int'',​ use ''​fmap''​ instead of ''​case''​ or pattern matching.
 <code haskell> <code haskell>
 add5 :: Maybe Int -> Maybe Int add5 :: Maybe Int -> Maybe Int
 </​code>​ </​code>​
  
-**11.1.2.** Implement functions ''​add'',​ ''​sub''​ and ''​mult''​ that add, substract and multiply ''​Maybe Int'',​ use ''​do''​ notation instead of ''​case''​ or pattern matching.+**10.1.2.** Implement functions ''​add'',​ ''​sub''​ and ''​mult''​ that add, substract and multiply ''​Maybe Int'',​ use ''​do''​ notation instead of ''​case''​ or pattern matching.
 <code haskell> <code haskell>
 add :: Maybe Int -> Maybe Int -> Maybe Int add :: Maybe Int -> Maybe Int -> Maybe Int
Line 124: Line 124:
 </​code>​ </​code>​
  
-===== 11.2. Working with IO =====+===== 10.2. Working with IO =====
  
 We can finally learn about IO in Haskell. Because it's a pure functional language, where we have no side-effects,​ IO is not really possible, reading external values or printing values is inherently a side-effect. Because of this, IO is defined as a Monad, where the context is the external world. We can finally learn about IO in Haskell. Because it's a pure functional language, where we have no side-effects,​ IO is not really possible, reading external values or printing values is inherently a side-effect. Because of this, IO is defined as a Monad, where the context is the external world.
Line 148: Line 148:
 </​note>​ </​note>​
  
-**11.2.1.** Write a ''​Hello World''​ program and execute it.+**10.2.1.** Write a ''​Hello World''​ program and execute it.
  
-**11.2.2.** Write a program that reads a value ''​n''​ and prints the ''​n-th''​ fibonacci number.+**10.2.2.** Write a program that reads a value ''​n''​ and prints the ''​n-th''​ fibonacci number.
  
 <​note>​ You can use ''​read''​ to convert from strings to certain types (is the opposite of ''​show''​).</​note>​ <​note>​ You can use ''​read''​ to convert from strings to certain types (is the opposite of ''​show''​).</​note>​
  
-**11.2.3.** Write a program that reads a value ''​n'',​ a vector of ''​n''​ numbers and prints them in sorted order.+**10.2.3.** Write a program that reads a value ''​n'',​ a vector of ''​n''​ numbers and prints them in sorted order.
  
 <​note>​ Don't forget ''​IO''​ is also a ''​Functor'',​ we can ''​fmap''​ over yet '​unread'​ values. </​note>​ <​note>​ Don't forget ''​IO''​ is also a ''​Functor'',​ we can ''​fmap''​ over yet '​unread'​ values. </​note>​
  
-**11.2.4.** Write a program that reads a value ''​n'',​ and prints the sequences given by the **Collatz conjecture**. If the current number ''​x''​ is even, the next number is ''​x / 2'',​ if ''​x''​ is odd the next number is ''​3 * x + 1'',​ the sequence stops when you hit the number 1.+**10.2.4.** Write a program that reads a value ''​n'',​ and prints the sequences given by the **Collatz conjecture**. If the current number ''​x''​ is even, the next number is ''​x / 2'',​ if ''​x''​ is odd the next number is ''​3 * x + 1'',​ the sequence stops when you hit the number 1.
  
-===== 11.3. Lists =====+===== 10.3. Lists =====
  
 Let's take a moment and think about lists, we already experimented with Functors over lists a lot. It's simply the ''​map''​ function we are extremely familiar with, but what would mean to **sequence** 2 lists using $(>>​=)$?​ \\ Let's take a moment and think about lists, we already experimented with Functors over lists a lot. It's simply the ''​map''​ function we are extremely familiar with, but what would mean to **sequence** 2 lists using $(>>​=)$?​ \\
Line 182: Line 182:
 </​code>​ </​code>​
  
-**11.3.1.** Make a function that given a position, tells you where a Knight might be able to move ([[https://​youtu.be/​gjMsHsd7N1Y?​si=3xUvCE2iGbevyELV&​t=14| how a Knight moves]]).+**10.3.1.** Make a function that given a position, tells you where a Knight might be able to move ([[https://​youtu.be/​gjMsHsd7N1Y?​si=3xUvCE2iGbevyELV&​t=14| how a Knight moves]]).
 <code haskell> <code haskell>
 moveKnight :: Pos -> [Pos] moveKnight :: Pos -> [Pos]
Line 189: Line 189:
 </​code>​ </​code>​
  
-**11.3.2.** Make a function that given a start position and a target position, tells you if a Knight can get to the target position in exactly 3 moves.+**10.3.2.** Make a function that given a start position and a target position, tells you if a Knight can get to the target position in exactly 3 moves.
 <code haskell> <code haskell>
 canReachIn3 :: Pos -> Pos -> Bool canReachIn3 :: Pos -> Pos -> Bool
Line 195: Line 195:
 </​code>​ </​code>​
  
-**11.3.3.(* * *)** Make a function that given a number ''​k'',​ a start position and a target position, tell you if a Knight can get to the target position in exactly ''​k''​ moves.+**10.3.3.(* * *)** Make a function that given a number ''​k'',​ a start position and a target position, tell you if a Knight can get to the target position in exactly ''​k''​ moves.
 <code haskell> <code haskell>
 canReachInK :: Int -> Pos -> Pos -> Bool canReachInK :: Int -> Pos -> Pos -> Bool
Line 201: Line 201:
 </​code>​ </​code>​
  
-===== 11.4. Probability Distributions (M3 flashbacks) =====+===== 10.4. Probability Distributions (M3 flashbacks) =====
  
 Let's also try to define our own Monads. Keep in mind that we should never have the goal of making something a monad, rather we should define types that model aspects of our problem, and if we notice that they represent types with context that can be abstracted using monads, use them for simplicity. Let's also try to define our own Monads. Keep in mind that we should never have the goal of making something a monad, rather we should define types that model aspects of our problem, and if we notice that they represent types with context that can be abstracted using monads, use them for simplicity.
Line 211: Line 211:
 </​code>​ </​code>​
  
-**11.4.1.** Define a ''​Functor''​ instance for ''​Prob'',​ mapping over a probability should change the value, but not affect the probability. Check that the functor laws apply.+**10.4.1.** Define a ''​Functor''​ instance for ''​Prob'',​ mapping over a probability should change the value, but not affect the probability. Check that the functor laws apply.
 <code haskell> <code haskell>
 instance Functor Prob where instance Functor Prob where
Line 222: Line 222:
 </​code>​ </​code>​
  
-**11.4.2.** Define a auxiliary function ''​flatten''​ that takes a probability of probabilities (''​Prob (Prob a)''​) and returns a probability (''​Prob a''​).+**10.4.2.** Define a auxiliary function ''​flatten''​ that takes a probability of probabilities (''​Prob (Prob a)''​) and returns a probability (''​Prob a''​).
 <code haskell> <code haskell>
 flatten :: Prob (Prob a) -> Prob a flatten :: Prob (Prob a) -> Prob a
Line 233: Line 233:
 </​code>​ </​code>​
  
-**11.4.3.** Using ''​flatten'',​ define a ''​Monad''​ instance for ''​Prob''​ (it should behave in a similar fashion with the List monad, but also keep the probability context). Check that the monad laws apply.+**10.4.3.** Using ''​flatten'',​ define a ''​Monad''​ instance for ''​Prob''​ (it should behave in a similar fashion with the List monad, but also keep the probability context). Check that the monad laws apply.
 <code haskell> <code haskell>
 instance Monad Prob where instance Monad Prob where
Line 266: Line 266:
 </​code>​ </​code>​
  
-**11.4.4.** Make a function that returns the probability distribution of a fair **n**-sided die.+**10.4.4.** Make a function that returns the probability distribution of a fair **n**-sided die.
 <code haskell> <code haskell>
 die :: Int -> Prob Int die :: Int -> Prob Int
Line 274: Line 274:
 </​code>​ </​code>​
  
-**11.4.5.** Let's use this framework to solve a M3 problem: "Jo has took a test for a disease. The result of the test is either positive or negative and the test is 95% reliable: in 95% of cases of people who really have the disease, a positive result is returned, and in 95% of cases of people who do not have the disease, a negative result is obtained. 1% of people of Jo’s age and background have the disease. Jo took the test, and the result is positive. What is the probability that Jo has the disease?"​+**10.4.5.** Let's use this framework to solve a M3 problem: "Jo has took a test for a disease. The result of the test is either positive or negative and the test is 95% reliable: in 95% of cases of people who really have the disease, a positive result is returned, and in 95% of cases of people who do not have the disease, a negative result is obtained. 1% of people of Jo’s age and background have the disease. Jo took the test, and the result is positive. What is the probability that Jo has the disease?"​