Reputation: 11321
I just made a script that takes some values from a TSV file and formats them differently. The script looks like this:
{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
tsvToPat tsv = T.unlines $ map (makePat . (T.replace "-" " ") . head . (T.splitOn "\t")) (T.lines tsv)
main :: IO ()
main = do
pantone <- TIO.readFile "../data/maps/pantone/pantone.tsv"
xkcd <- TIO.readFile "../data/maps/xkcd/rgb.txt"
jaffer <- TIO.readFile "../data/maps/jaffer/master.tsv"
TIO.putStr $ tsvToPat pantone
TIO.putStr $ tsvToPat xkcd
TIO.putStr $ tsvToPat jaffer
makePat :: T.Text -> T.Text
makePat pat = T.concat [ "{\"label\":\"COLOR\",\"pattern\":[{\"lower\":\""
, pat
, "\"}]}"
]
but I'm struggling with thinking about how to refactor everything in the main function. What I want to do is something like:
maps :: [FilePath]
maps = [ "../data/maps/pantone/pantone.tsv"
, "../data/maps/xkcd/rgb.txt"
, "../data/maps/jaffer/master.tsv"
]
main = map (TIO.putStr . tsvToPat . TIO.readFile) maps
Which won't work, because I'm guessing it's mixing IO operations with pure functions. Is there some magic monadic bind operator I should be using here?
Upvotes: 2
Views: 77
Reputation: 50819
The monadic binding operator you're looking for is <=<
from Control.Monad
. It acts like function composition for monad operators. You would also need to upgrade your map
to a monadic mapping function mapM_
. For example, ignoring the tsvToPat
bit, you could write:
main = mapM_ (TIO.putStr <=< TIO.readFile) maps
It can be a little tricky to figure out how to squeeze a pure function like tsvToPat
in there. One way is to make it monadic by writing return . tsvToPat
, so you get:
main' :: IO ()
main' = mapM_ (TIO.putStr <=< return . tsvToPat <=< TIO.readFile) maps
Note that the precedence of .
here is higher than <=<
.
Even though that version makes everything pretty clear, it can actually be simplified to:
main :: IO ()
main = mapM_ (TIO.putStr . tsvToPat <=< TIO.readFile) maps
Upvotes: 6
Reputation: 48572
Actions in do
blocks desugar to calls to >>=
, and there's a flipped version of that called =<<
. To run a list of IO actions, use mapM_
. Put those concepts together and you get this:
main = mapM_ (\x -> TIO.putStr . tsvToPat =<< TIO.readFile x) maps
Upvotes: 4