Comment

Comment by gamegoblin

This is a good post in that it illustrates how it's possible to write useful Haskell that interacts with the real world without weaving IO through the entire codebase (as many beginners end up doing).

I still find myself preferring to use a dependency injection style when writing Haskell. The code ends up looking similar, and more flexible, in my opinion (you can inject different dependencies based on runtime values).

Here is an example using the method described in the article vs. dependency injection to print out the current time.

Article:

    class MonadTime m where
        getTime :: m Integer

    class MonadPrint m a where
        doPrint :: a -> m ()

    instance MonadTime IO where
        getTime = do
            TOD s _ <- getClockTime
            return s

    instance Show a => MonadPrint IO a where
        doPrint = print

    printTime :: (Monad m, MonadPrint m Integer, MonadTime m) => m ()
    printTime = getTime >>= doPrint

    main :: IO ()
    main = printTime
Dependency injected:

    data MonadPrint m a = MonadPrint { doPrint :: a -> m () }

    data MonadTime m = MonadTime { getTime :: m Integer }

    ioMonadTime :: IO Integer
    ioMonadTime = do
        TOD s _ <- getClockTime
        return s

    printTime :: Monad m => MonadPrint m Integer -> MonadTime m -> m ()
    printTime MonadPrint{..} MonadTime{..} = getTime >>= doPrint

    main :: IO ()
    main = printTime (MonadPrint print) (MonadTime ioMonadTime)
 
    
Good read on the subject of being careful with overusing typeclasses:

http://www.haskellforall.com/2012/05/scrap-your-type-classes...

parent gamegoblin 11 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton