diff options
author | Teddy Wing | 2017-08-27 00:40:55 +0200 |
---|---|---|
committer | Teddy Wing | 2017-08-27 00:40:55 +0200 |
commit | 8e5b862c9171af8af7c6c0d0456ae67a9e737633 (patch) | |
tree | 4c01da6c2381882eaecac3bb7a6139cf77b99931 /src/IRC.hs | |
parent | 46f05f8e4d87b2f9e09959bdfc0c890278568db2 (diff) | |
download | sorbot-8e5b862c9171af8af7c6c0d0456ae67a9e737633.tar.bz2 |
privmsgFromPlugin: Rewrite using MaybeT monad transformer
OMG it works!!! This took me a week of off-and-on tinkering, learning,
procrastinating, and struggling. So awesome that it's finally working!
The `liftMaybe` was key, learned that from:
https://stackoverflow.com/questions/8684252/how-to-inject-a-maybe-value-into-maybet
This article on monad transformers by 'kqr' also helped quite a bit:
https://github.com/kqr/gists/blob/master/articles/gentle-introduction-monad-transformers.md
A Wikibooks article on the same was somewhat useful:
https://en.wikibooks.org/wiki/Haskell/Monad_transformers
And this was an interesting look at Alternatives, which I didn't end up
using but was interesting nonetheless:
http://www.parsonsmatt.org/2016/11/18/clean_alternatives_with_maybet.html
When I learned about monad transformers I thought: "Yes! This is what I
need to clean up the `privmsgFromPlugin` function.". I wasn't liking the
nested `case` statements there, and since everything was a `Maybe`, I
thought, why can't we chain the `Maybe`s like we're supposed to be able
to with monads? Well, turns out we can. It just involved a lot of tricky
`lift`ing. This gets rid of the nesting, resulting in a much cleaner-
looking function. So cool!
Diffstat (limited to 'src/IRC.hs')
-rw-r--r-- | src/IRC.hs | 37 |
1 files changed, 19 insertions, 18 deletions
@@ -6,6 +6,8 @@ module IRC import Control.Monad (sequence_) import Control.Monad.IO.Class (liftIO) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT) import qualified Data.ByteString as B import qualified Data.Text as T @@ -33,13 +35,14 @@ handlePrivmsg = IRC.EventHandler , IRC._eventFunc = \evt -> dispatchEvent evt } where + dispatchEvent :: IRC.UnicodeEvent -> IRC.StatefulIRC s () dispatchEvent (IRC.Event _ (IRC.User nick) (IRC.Privmsg _ (Right msg))) = do let message = Message { text = msg , channel = nick , nick = nick } - response <- liftIO $ privmsgFromPlugin message + response <- lift $ runMaybeT $ privmsgFromPlugin message case response of Nothing -> return () Just r -> sequence_ r @@ -53,29 +56,27 @@ handlePrivmsg = IRC.EventHandler case messageForBot message of Nothing -> return () Just message -> do - response <- liftIO $ privmsgFromPlugin message + response <- lift $ runMaybeT $ privmsgFromPlugin message case response of Nothing -> return () Just r -> sequence_ r -privmsgFromPlugin :: Message -> IO (Maybe [IRC.StatefulIRC s ()]) +privmsgFromPlugin :: Message -> MaybeT IO [IRC.StatefulIRC s ()] privmsgFromPlugin message = do - case matchPlugin message of - Nothing -> return Nothing - Just plugin -> do - response <- liftIO $ performPlugin plugin message - return $ case response of - Left err -> Just $ - [IRC.send $ IRC.Privmsg - (toChannel plugin message) - (Right err)] - Right r -> Just $ - map (\r -> - IRC.send $ IRC.Privmsg - (toChannel plugin message) - (Right r) ) - (splitAtNewlines $ splitLongLines r) + plugin <- liftMaybe $ matchPlugin message + response <- liftIO $ performPlugin plugin message + return $ case response of + Left err -> [IRC.send $ IRC.Privmsg + (toChannel plugin message) + (Right err)] + Right r -> map + (\r -> IRC.send $ IRC.Privmsg + (toChannel plugin message) + (Right r) ) + (splitAtNewlines $ splitLongLines r) where + liftMaybe = MaybeT . return + -- IRC only permits 512 bytes per line. Use less to allow for protocol -- information that gets sent in addition to the message content. splitLongLines txt = T.chunksOf 400 txt |