我刚刚制作了一个脚本,它从 TSV 文件中获取一些值并以不同的方式格式化它们。该脚本如下所示:
{-# 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
, "\"}]}"
]
Run Code Online (Sandbox Code Playgroud)
但我正在努力思考如何重构主函数中的所有内容。我想做的是:
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
Run Code Online (Sandbox Code Playgroud)
这行不通,因为我猜它是将 IO 操作与纯函数混合在一起。我应该在这里使用一些神奇的单子绑定运算符吗?
您正在寻找的 monadic 绑定运算符<=<来自Control.Monad. 它的作用类似于 monad 运算符的函数组合。你还需要将你的升级map到一个 monadic 映射函数mapM_。例如,忽略tsvToPat位,你可以写:
main = mapM_ (TIO.putStr <=< TIO.readFile) maps
Run Code Online (Sandbox Code Playgroud)
弄清楚如何像tsvToPat在那里一样挤压纯函数可能有点棘手。一种方法是通过编写使其成为 monadic return . tsvToPat,所以你得到:
main' :: IO ()
main' = mapM_ (TIO.putStr <=< return . tsvToPat <=< TIO.readFile) maps
Run Code Online (Sandbox Code Playgroud)
请注意,.此处的优先级高于<=<。
尽管该版本使一切都非常清楚,但实际上可以简化为:
main :: IO ()
main = mapM_ (TIO.putStr . tsvToPat <=< TIO.readFile) maps
Run Code Online (Sandbox Code Playgroud)