Using Maybe and Writer Together

Here is my factory egg packaging:

type Eggs = Int
data Carton = Carton Eggs deriving Show

add :: Eggs -> Carton -> Maybe Carton
add e (Carton c)
    | c + e <= 12 = Just (Carton $ c + e)
    | otherwise = Nothing

main = do
    print $ pure(Carton 2) >>= add 4 >>= add 4 >>= add 3

It seems to work well, I can perfectly chain the functions add.

But I want to write a journal about how many eggs were added at each step. So I do this:

import Control.Monad.Writer

type Eggs = Int
data Carton = Carton Eggs deriving Show

add :: Eggs -> Carton -> Writer [String] (Maybe Carton)
add e (Carton c)
    | c + e <= 12 = do
        tell ["adding " ++ show e]
        return (Just (Carton $ c + e))
    | otherwise = do
        tell ["cannot add " ++ show e]
        return Nothing

main = do
    let c = add 4 $ Carton 2
    print $ fst $ runWriter c
    mapM_ putStrLn $ snd $ runWriter c

This gives me what I want: I see a summary card and a record for adding 4 eggs.

But I seem to have lost the chain ability add, as I did before:

let c = pure(Carton 2) >>= add 4 -- works
let c = pure(Carton 2) >>= add 4 >>= add 2 -- does not work

How can I associate my new features addwith recording support? Is there a better way to do this?

+4
source share
3 answers

>>= Monad Maybe, - Monad Writer. , >>= Carton -> Maybe Carton, add 2, >>= Maybe Carton -> Writer [String] (Maybe Carton). pure (Carton 2) → = add 4 , pure (Carton 2) Maybe Carton add 4 Carton -> <something>, . >>= , >>= , >>=. add, Eggs -> Maybe Carton -> Writer [String] (Maybe Carton):

add :: Eggs -> Maybe Carton -> Writer [String] (Maybe Carton)
add e Nothing = return Nothing
add e (Just (Carton c))
    | c + e <= 12 = do
        tell ["adding " ++ show e]
        return (Just (Carton $ c + e))
    | otherwise = do
        tell ["cannot add " ++ show e]
        return Nothing

, , pure (Carton 2), pure (Just $ Carton 2):

 > pure (Just $ Carton 2) >>= add 2 >>= add 5
 WriterT (Identity (Just (Carton 9),["adding 2","adding 5"]))

, monad transformers Maybe Writer, .

import Control.Monad.Trans.Maybe
import Control.Monad.Writer

type Eggs = Int
data Carton = Carton Eggs deriving Show

add :: Eggs -> Carton -> MaybeT (Writer [String]) Carton
add e (Carton c)
    | c + e <= 12 = do
        lift $ tell ["adding " ++ show e]
        return (Carton $ c + e)
    | otherwise = do
        lift $ tell ["cannot add " ++ show e]
        mzero

main = do
    let c = return (Carton 2) >>= add 4 >>= add 2
    let result = runWriter $ runMaybeT c
    print $ fst $ result
    mapM_ putStrLn $ snd $ result

:

  • MaybeT m a - . m - Writer [String], a - Carton. , runMaybeT, Writer [String] (Maybe Carton), runWriter , .
  • Writer MaybeT (Writer [String]), lift . lift $ tell ["something"]
  • return carton Just Carton, mzero Nothing

: Maybe Writer WriterT [String] Maybe Carton, , 12 runWriterT Nothing

import Control.Monad
import Control.Monad.Trans
import Control.Applicative
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Writer

type Eggs = Int
data Carton = Carton Eggs deriving Show

add :: Eggs -> Carton -> WriterT [String] Maybe Carton
add e (Carton c)
    | c + e <= 12 = do
        tell ["adding " ++ show e]
        lift $ Just $ Carton $ c + e
    | otherwise = do
        tell ["cannot add " ++ show e]
        lift Nothing

main = do
    let c = return (Carton 2) >>= add 4 >>= add 20
    case runWriterT c of
      Nothing ->
        print "nothing to print"
      Just (carton, history) -> do
        print carton
        mapM_ putStrLn $ history
+1

add MaybeT:

import Control.Trans.Monad.Maybe

test = pure (Carton 2) >>= MaybeT . add 3
                       >>= MaybeT . add 4
                       >>= MaybeT . add 5

runTest = do
  print $ fst $ runWriter (runMaybeT test)

: http://lpaste.net/169070

+5

I would modify add& c to use MaybeT (Writer [String]):

import Control.Monad.Writer
import Control.Monad.Trans.Maybe

type Eggs = Int
data Carton = Carton Eggs deriving Show

main = do
    let c = add 4 $ Carton 2
        (result, log) = runWriter $ runMaybeT c
    print result
    mapM_ putStrLn log

add :: Eggs -> Carton -> MaybeT (Writer [String]) Carton
add e (Carton c)
    | c + e <= 12 = do
          tell ["adding " ++ show e]
          return $ Carton $ c + e
    | otherwise = do
          tell ["cannot add " ++ show e]
          mzero

this will allow you to use your source code

pure (Carton 2) >>= add 4 >>= add 2

work as expected.

+5
source

All Articles