Quick actions

cmd+k|ctrl+k

Navigation

Languages

Writer Monad

Snippet info

Language

Haskell

Visibility

public

Author

francesquini

Created

2024-08-28T18:02:04.769202Z

Updated

2024-08-28T18:02:33.699657Z

module Main where

import Data.Monoid
import Control.Monad ((>=>))

data Writer w a = Writer a w

runWriter :: Writer w a -> (a, w)
runWriter (Writer a w) = (a, w)

tell :: w -> Writer w ()
tell s = Writer () s

instance (Monoid w) => Functor (Writer w) where
  -- fmap :: (a -> b) -> Writer w a -> Writer w b
  fmap f (Writer a w) = Writer (f a) w

instance (Monoid w) => Applicative (Writer w) where
  -- pure :: a -> Writer w a
  pure x = Writer x mempty

  -- (<*>) :: Writer w (a -> b) -> Writer w a -> Writer w b
  (Writer f m1) <*> (Writer a m2) = Writer (f a) (m1 <> m2)

instance (Monoid w) => Monad (Writer w) where
  -- (Writer w a) -> (a -> Writer w b) -> (Writer w b)
  (Writer a w) >>= k = let (b, w') = runWriter (k a)
                       in  Writer b (w <> w')


-- Exemplo
isEvenW x = (even x, " even ")
notW b = (not b, " not ")
isOddW x = let (b1, w1) = isEvenW x
               (b2, w2) = notW b1
           in (b2, w1 <> w2)


isEvenW' :: Integer -> Writer String Bool
isEvenW' x = do tell " even "
                return (even x)

notW' :: Bool -> Writer String Bool
notW' b = do tell " not " 
             return (not b)

{-
isOddW' x = do b1 <- isEvenW' x
               b2 <- notW' b1
               return b2
-}

isOddW' :: Integer -> Writer String Bool
isOddW' = (isEvenW' >=> notW')

-- outro exemplo
fiboW :: Int -> Writer (Sum Int) Int
fiboW 0 = do tell (Sum 1)
             return 0
fiboW 1 = do tell (Sum 1)
             return 1
fiboW n = do tell (Sum 1)
             f1 <- fiboW (n-1)
             f2 <- fiboW (n-2)
             return (f1+f2)
             
main = do
  print $ runWriter $ isOddW' 3
  mapM_ (print . runWriter . fiboW) [1..10]
  
INFO