如何在 Haskell 中重构这些 IO 操作?

Jon*_*han 3 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
                       , "\"}]}"
                       ]
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 操作与纯函数混合在一起。我应该在这里使用一些神奇的单子绑定运算符吗?

K. *_*uhr 6

您正在寻找的 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)