Hacker News new | ask | show | jobs
by poorlyknit 934 days ago
In Haskell you have a lot of options to type your functions in a more granular way. Consider the type class MonadIO, which lets you specify that your function works on any monad that can do side effects, not just IO specifically:

    -- Before
    captureAudioDuration :: DeviceID -> DiffTime -> IO WaveData
    -- After
    captureAudioDuration' :: MonadIO m => DeviceID -> DiffTime -> m WaveData
You can build the same thing, but for logging!

    class Monad m => MonadLog m where
        log :: String -> m ()
    -- In IO, just log to stdout.
    -- Other implementations might be a state/writer monad
    -- or a library/application-specific monad for business logic.
    instance MonadLog IO where
        log msg = putStrLn ("log: " ++ msg)
    -- Before: Bad, doesn't actually do any IO but logging
    findShortestPath :: Node -> Node -> Graph -> IO [Node]
    -- After: Better, type signature gives us more details on what's happening.
    -- We can still use this in an IO context because IO has a MonadLog instance.
    -- However, trying to capture audio in this function using either
    -- of the functions above will lead to a type error.
    findShortestPath' :: MonadLog m => Node -> Node -> Graph -> m [Node]
As you can imagine this can get quite verbose and there's other patterns one can use. Feel free to ask any follow-up questions :)