<!-- .slide: data-background-image="./2025-07-16T12_22_49.jpg" data-background-opacity="0.15" --> <h1 id="monad-stacking">Monad Stacking</h1> <!-- .element: class="r-fit-text" --> <h4 id="learning-to-read-and-write">Learning to read <strong>and</strong> write</h4> <!--s--> <h2 id="quick-refresher">Quick refresher</h2> <!--s--> <h3 id="monads-as-actions-in-a-context">Monads as actions in a context</h3> <pre><code class="language-haskell" >-- Maybe Int dropState = \ x -> Nothing incrementState = \ x -> Just (x + 2) replaceState = \ x -> Just 5</code></pre> <pre><code class="language-haskell" data-line-numbers="1-2|4-5|7|9-10|">> (Just 4) >>= dropState Nothing > (Just 4) >>= incrementState >>= incrementState Just 8 > combined = incrementState >=> incrementState >=> incrementState > (Just 4) >>= combined Just 10</code></pre> <!-- .element: class="fragment" data-fragment-index="1" --> <!--s--> <!-- .slide: data-background-image="./2025-07-17T10_21_34.jpg" data-background-opacity="0.15" --> <h3 id="monads-as-side-effects">Monads as side-effects</h3> <!-- .element: class="r-fit-text" --> <!--s--> <h3 id="examples">Examples</h3> <pre><code class="language-haskell" >teller :: W.Writer [String] Int teller = do W.tell ["Log msg #1"] W.tell ["Log msg #1"] return 0</code></pre> <!-- .element: class="fragment" data-fragment-index="0" --> <pre><code class="language-haskell" >stater :: S.State Int String stater = do x <- S.get S.put 40 return $ show x</code></pre> <!-- .element: class="fragment" data-fragment-index="1" --> <pre><code class="language-haskell" >errorer :: E.Except String Int errorer = E.throwError "OH NO!"</code></pre> <!-- .element: class="fragment" data-fragment-index="2" --> <!--s--> <!-- .slide: data-auto-animate --> <pre><code class="language-haskell" >together :: <secret> together = do x <- S.get W.tell [x] S.put 40 return x</code></pre> <!-- .element: data-id="secret-type" --> <!--s--> <!-- .slide: data-auto-animate --> <pre><code class="language-haskell" >together :: ??? W.MonadWriter Int ??? together = do x <- S.get -- error W.tell [x] S.put 40 -- error return x</code></pre> <!-- .element: data-id="secret-type" --> <!--s--> <!-- .slide: data-auto-animate --> <pre><code class="language-haskell" >together :: ??? S.MonadState ??? together = do x <- S.get W.tell [x] -- error S.put 40 return x</code></pre> <!-- .element: data-id="secret-type" --> <!--s--> <!-- .slide: data-auto-animate --> <pre><code class="language-haskell" >together :: (W.MonadWriter [Int] m, S.MonadState Int m) => m Int together = do x <- S.get W.tell [x] S.put 40 return x</code></pre> <!-- .element: data-id="secret-type" --> <!--s--> <pre><code class="language-haskell" >callN :: (Monad m) => m Int call1 = S.execStateT (W.execWriterT together) 0 call2 = W.execWriterT (S.execStateT together 0)</code></pre> <!--s--> <!-- .slide: data-background-image="./2025-07-16T12_08_39.jpg" data-background-opacity="0.15" --> <h1 id="what-is-this-mystery-monad">What is this mystery monad?</h1> <!--s--> <!-- .slide: data-background-image="./2025-07-16T12_24_25.jpg" data-background-opacity="0.15" --> <h1 id="why-can-state-act-as-a-writer">Why can State act as a Writer ?!?!?</h1> <!--s--> <pre><code class="language-haskell" >-- Taken directly from the mtl sources instance MonadWriter w m => MonadWriter w (ExceptT e m) where writer = lift . writer tell = lift . tell listen = Except.liftListen listen pass = Except.liftPass pass instance MonadWriter w m => MonadWriter w (IdentityT m) where writer = lift . writer tell = lift . tell listen = Identity.mapIdentityT listen pass = Identity.mapIdentityT pass instance MonadWriter w m => MonadWriter w (MaybeT m) where writer = lift . writer tell = lift . tell listen = Maybe.liftListen listen pass = Maybe.liftPass pass instance MonadWriter w m => MonadWriter w (ReaderT r m) where writer = lift . writer tell = lift . tell listen = mapReaderT listen pass = mapReaderT pass</code></pre> <!--s--> <!-- .slide: data-background-image="./IMG_20250714_225216703.jpg" data-background-opacity="0.15" --> <h1 id="the-n2-instances-problem">“The n² Instances Problem”</h1> <!-- .element: class="r-fit-text" --> <!--s--> <h1 id="one-of-the-many-attempts-at-a-solution">One of the many attempts at a solution:</h1> <!-- .element: class="r-fit-text" --> <!--s--> <!-- .slide: data-background-image="./2025-07-13T14_35_26.jpg" data-background-opacity="0.15" --> <h1 id="polysemy"><em>Polysemy</em></h1> <h2 id="monads-as-dsls">Monads as DSLs</h2> <!-- .element: class="fragment" --> <!--s--> <h2 id="dsl">DSL:</h2> <pre><code class="language-haskell" >data Semaphore = Red | Green | Blue</code></pre> <h2 id="interpreter">Interpreter:</h2> <!-- .element: class="fragment" data-fragment-index="2" --> <pre><code class="language-haskell" >\case Red -> print "Gone Red" Green -> print "Gone Green" Blue -> return 0</code></pre> <!-- .element: class="fragment" data-fragment-index="2" --> <h2 id="program">Program:</h2> <!-- .element: class="fragment" data-fragment-index="3" --> <pre><code class="language-haskell" >do red red green x <- blue print x</code></pre> <!-- .element: class="fragment" data-fragment-index="3" --> <!--s--> <pre><code class="language-haskell" >data Semaphore = Red | Green | Blue data Human = Eat | Sleep data ProgTest = Finish | Cry</code></pre> <pre><code class="language-haskell" >do red cry eat sleep finish</code></pre> <!--s--> <!-- .slide: data-background-image="./2025-07-17T15_59_06.jpg" data-background-opacity="0.15" --> <h2 id="tangent-1">Tangent #1:</h2> <h1 id="datakinds">DataKinds</h1> <!--v--> <!-- .slide: data-background-image="./2025-07-13T16_43_29.jpg" data-background-opacity="0.15" --> <h2 id="tangent-2">Tangent #2:</h2> <h1 id="what-are-kinds">What are Kinds???</h1> <!--s--> <h2 id="tangent-3">Tangent #3:</h2> <h1 id="type-families">Type Families</h1> <!--s--> <pre><code class="language-haskell" >class Foo where bar :: Int -> Int instance Foo where bar x = x + 1</code></pre> <pre><code class="language-haskell" >type family F a where F Int = Bool F String = Int</code></pre> <!-- .element: class="fragment" --> <pre><code class="language-haskell" >ghci> 4 :: F String 4 ghci> 4 :: F Int <interactive>:35:1: error: [GHC-39999] • No instance for ‘Num Bool’ arising from the literal ‘4’ • In the expression: 4 :: F Int In an equation for ‘it’: it = 4 :: F Int</code></pre> <!-- .element: class="fragment" --> <!--s--> <h3 id="why-do-datakinds-help">Why do DataKinds help?</h3> <pre><code class="language-haskell" >type family First a where First (x ': xs) = x</code></pre> <pre><code class="language-haskell" >ghci> ("l" :: F '[String, Bool]) "l" ghci> ("l" :: F '[String, Int]) "l" ghci> ("l" :: F '[Int]) <interactive>:31:2: error: [GHC-83865] • Couldn't match type ‘[Char]’ with ‘Int’ Expected: F '[Int] Actual: String • In the expression: "l" :: F '[Int] In an equation for ‘it’: it = ("l" :: F '[Int])</code></pre> <!-- .element: class="fragment" --> <!--s--> <h2 id="our-magic-monad">Our Magic Monad:</h2> <h1 id="sem-r-a"><strong>Sem r a</strong></h1> <!--s--> <pre><code class="language-haskell" >Sem r -- DataKind Monad Stack a -- Return Type</code></pre> <!--s--> <h1 id="sem-int"><strong>Sem '[] Int</strong></h1> <!--s--> <h2 id="leaving">Leaving?</h2> <ol> <li>No effects left</li> <li>One known Monadic effect left</li> </ol> <!--s--> <pre><code class="language-haskell" data-line-numbers="1-2|">semFive :: Sem '[] Int semFive = return 5 run semFive > 5</code></pre> <!--v--> <pre><code class="language-haskell" >Sem [] Int -- issue ?</code></pre> <ul> <li> <p>Expecting one more argument to ‘[]’</p> <p>Expected kind ‘*’, but ‘[]’ has kind ‘* -> *’</p> </li> <li> <p>In the first argument of ‘Sem’, namely ‘[]’</p> <p>In an expression type signature: Sem [] Int</p> </li> </ul> <!--s--> <pre><code class="language-haskell" data-line-numbers="1|2-4|">semList :: Sem '[Embed []] Int semList = do x <- embed [1, 2] y <- embed [3, 4] return $ x + y runM semList > 5</code></pre> <!--s--> <h2 id="member-lang1-r-sem-r-int"><code>Member Lang1 r => Sem r Int</code></h2> <!-- .element: class="r-fit-text" --> <p>How? TypeFamilies</p> <!--s--> <h4 id="surprisingly-important">Surprisingly important</h4> <p>(<code>Sem '[A, B] a</code>) != (<code>Sem '[B, A] a</code>)</p> <!--s--> <p>Yet:</p> <p><code>Member A '[B, A]</code></p> <p><code>Member B '[B, A]</code></p> <p>and</p> <p><code>Members '[A, B] '[B, A]</code></p> <p><code>Members '[B, A] '[B, A]</code></p> <!--s--> <h2 id="defers-specifying-order">Defers specifying order</h2> <!--s--> <h2 id="now-for-the-full-code">Now for the full code</h2> <!--s--> <h3 id="gadt">GADT</h3> <pre><code class="language-haskell" >data Semaphore m a where Red :: Semaphore m () Green :: Semaphore m () Blue :: Semaphore m Int</code></pre> <!--s--> <h3 id="generate-verbs">Generate verbs</h3> <pre><code class="language-haskell" >makeSem ''Semaphore</code></pre> <p>Creates <code>red</code>, <code>green</code>, <code>blue</code> from <code>Red</code>, <code>Green</code>, <code>Blue</code></p> <!--s--> <pre><code class="language-haskell" data-line-numbers="|1-2|3-7|">semaphoreInterpreter :: Member (Embed IO) r => Sem (Semaphore : r) a -> Sem r a semaphoreInterpreter = interpret $ \case Red -> embed $ print "Gone Red" Green -> embed $ print "Gone Green" Blue -> return 5</code></pre> <!--s--> <pre><code class="language-haskell" >prog = do red red green x <- blue return $ x * 2</code></pre> <!--s--><!-- .slide: data-auto-animate --> <p> <pre><code class="language-haskell" >prog</code></pre> <!-- .element: data-id="prog" --> <code>:: Members [Semaphore, Embed IO] r => Sem r Int</code><!-- .element: class="r-fit-text" --></p> <!--s--><!-- .slide: data-auto-animate --> <p> <pre><code class="language-haskell" >prog & semaphoreinterpreter</code></pre> <!-- .element: data-id="prog" --> <code>:: Members [Embed IO] r => Sem r Int</code><!-- .element: class="r-fit-text" --></p> <!--s--><!-- .slide: data-auto-animate --> <p> <pre><code class="language-haskell" >prog & semaphoreinterpreter & runM</code></pre> <!-- .element: data-id="prog" --> <code>:: IO Int</code><!-- .element: class="r-fit-text" --></p> <!--s--> <blockquote> <p>"Gone Red"</p> <p>"Gone Red"</p> <p>"Gone Green"</p> <p>10</p> </blockquote> <!--s--> <pre><code class="language-haskell" >prog :: Members '[Human, Semaphore] r => Sem r Int prog = do red red green cry x <- blue return $ x * 2</code></pre> <!--s--> <pre><code class="language-haskell" >prog & interpretHuman & interpretSemaphore & runM</code></pre> <pre><code class="language-haskell" >prog & interpretSemaphore & interpretHuman & runM</code></pre> <!--s--> <pre><code class="language-plaintext" >• Could not deduce ‘Member Human r’ arising from a use of ‘...’</code></pre> <!--s--> <h3 id="i-just-scratched-the-surface-however">I just scratched the surface, however ...</h3> <ul> <li>Higher-order effects</li> <li>Tagged effects</li> </ul> <!--s--> <h3 id="dekuju-za-porornost">Děkuju za porornost</h3> <h1 id="otazky">Otázky?</h1>