代码之家  ›  专栏  ›  技术社区  ›  Tim Perry

在Haskell中更好地读取数据流

  •  2
  • Tim Perry  · 技术社区  · 14 年前

    我试图解析一个输入流,其中第一行告诉我有多少行数据。我最终得到了下面的代码,它是有效的,但我认为有更好的方法。有?

    main = do
        numCases <- getLine
        proc $ read numCases
    
    proc :: Integer -> IO ()
    proc numCases
         | numCases == 0 = return ()
         | otherwise = do
             str <- getLine
             putStrLn $ findNextPalin str
             proc (numCases - 1)
    

    注意:代码解决了球体问题 https://www.spoj.pl/problems/PALIN/ 但是我不认为发布其余的代码会影响到在这里做什么的讨论。

    4 回复  |  直到 11 年前
        1
  •  7
  •   dave4420    14 年前

    使用 replicate sequence_ .

    main, proc :: IO ()
    
    main = do numCases <- getLine
              sequence_ $ replicate (read numCases) proc
    
    proc = do str <- getLine
              putStrLn $ findNextPalin str
    

    序列 获取操作列表,并按顺序逐个运行它们。(然后它将丢弃结果;如果您对操作的返回值感兴趣,则可以使用 sequence )

    replicate n x 列出长度 n ,每个元素 x . 所以我们使用它来构建我们想要运行的操作列表。

        2
  •  3
  •   C. A. McCann Ravikant Cherukuri    14 年前

    戴夫辛顿 答案是正确的,但作为旁白,这里有另一种编写相同代码的方法:

    import Control.Applicative
    
    main = (sequence_ . proc) =<< (read <$> getLine)
    
    proc x = replicate x (putStrLn =<< (findNextPalin <$> getLine))
    

    只是提醒大家 do 不需要块!请注意,在上述两个方面 =<< <$> 站在老地方 功能应用 . 如果忽略这两个操作符,代码的读操作将与结构类似的纯函数完全相同。我加了一些无缘无故的括号,使事情更加明确。

    他们的目的是 <$GT; 在monad中应用正则函数,而 = & lt;& lt; 相同,但随后压缩Monad的额外层(例如,旋转 IO (IO a) 进入之内 IO a )

    以这种方式查看代码的有趣部分是,您可以忽略monad等的位置;通常很少有方法可以放置“函数应用程序”操作符来使类型工作。

        3
  •  0
  •   Thomas M. DuBuisson    14 年前

    您(以及前面的答案)应该更加努力地将IO与逻辑分开。使MAIN收集输入并单独(如果可能,完全是)完成工作。

    import Control.Monad -- not needed, but cleans some things up
    main = do
        numCases <- liftM read getLine
        lines <- replicateM numCases getLine
        let results = map findNextPalin lines
        mapM_ putStrLn results
    
        4
  •  0
  •   rtperson    14 年前

    在解决haskell中的spoj问题时,尽量不要使用标准字符串。字节串要快得多,我发现您通常可以忽略测试的数量,只需在所有内容上运行一个映射 但是 第一行,就像这样:

    {-# OPTIONS_GHC -O2 -optc-O2 #-}
    
    import qualified Data.ByteString.Lazy.Char8 as BS
    
    main :: IO ()
    main = do
        (l:ls) <- BS.lines `fmap` BS.getContents
        mapM_ findNextPalin ls
    

    这个 SPOJ page in the Haskell Wiki 给出了许多关于如何从字节串中读取整数以及如何处理大量输入的好指针。这有助于你避免超过时限。