[英]How can I refactor these IO operations in Haskell?
我刚刚制作了一个脚本,它从 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
, "\"}]}"
]
但我正在努力思考如何重构主要 function 中的所有内容。 我想做的是:
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
这是行不通的,因为我猜它是将 IO 操作与纯函数混合在一起。 我应该在这里使用一些神奇的单子绑定运算符吗?
您正在寻找的一元绑定运算符是<=<
来自Control.Monad
。 它的作用类似于 monad 运算符的 function 组合。 您还需要将map
升级到一元映射 function mapM_
。 例如,忽略tsvToPat
位,您可以编写:
main = mapM_ (TIO.putStr <=< TIO.readFile) maps
弄清楚如何将纯 function 像tsvToPat
挤进去可能有点棘手。 一种方法是通过编写return. tsvToPat
return. tsvToPat
,所以你得到:
main' :: IO ()
main' = mapM_ (TIO.putStr <=< return . tsvToPat <=< TIO.readFile) maps
注意 的优先级.
这里高于<=<
。
尽管该版本使一切都非常清楚,但实际上可以简化为:
main :: IO ()
main = mapM_ (TIO.putStr . tsvToPat <=< TIO.readFile) maps
do
中的操作阻止对>>=
的调用进行脱糖,并且有一个名为=<<
的翻转版本。 要运行 IO 操作列表,请使用mapM_
。 把这些概念放在一起,你会得到:
main = mapM_ (\x -> TIO.putStr . tsvToPat =<< TIO.readFile x) maps
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.