代码之家  ›  专栏  ›  技术社区  ›  Joe

如何堵住这类孔3

  •  0
  • Joe  · 技术社区  · 5 年前

    从…开始 my last question 我现在能得到我想要的结果,但是完全邪恶的方式:使用 unsafePerformIO . 我知道这不是解决这个问题的正确方法(尽管为了我的辩护,我是从hoogle检查类型,然后从kmett的repos中的ag搜索中得到这个想法的,看看他什么时候使用 不安全性能 在一百个左右的回购协议中。我读过关于黑客攻击的警告,我知道这很糟糕。

    我现在想要的是成为一种不用 不安全性能

    代码如下:

    module Main where
    
    import Control.Monad (liftM)
    import Data.List (isSubsequenceOf)
    import qualified Data.Text as T
    import System.Directory (listDirectory)
    import System.FilePath ((</>), takeExtension)
    import System.IO.Unsafe (unsafePerformIO)
    import Text.PDF.Info
    
    title :: FilePath -> IO String
    title path = do
      result <- pdfInfo path
      case result of
        Left someError -> do
          return "no title"
        Right info -> do
          case (pdfInfoTitle info) of
            Nothing -> return "no title"
            Just title -> return (T.unpack title)
    
    titleString :: FilePath -> String
    titleString s = unsafePerformIO (title s)
    {-# NOINLINE titleString #-}
    
    dir = "/some/path"
    
    main :: IO ()
    main = do
      print =<<
        liftM
          (filter
             (\path ->
                (isSubsequenceOf "annotated" (titleString (dir </> path))) &&
                (takeExtension path == ".pdf")))
          (listDirectory dir)
    

    一路上,我试着用打孔打孔和很多Hoogle来从工具中得到帮助(教一个人钓鱼)。我需要指导,让发现过程中使用的工具和文件更拨号。如果你知道如何处理这些事情,或者至少想象一下,如果你失去了对哈斯凯尔的所有长期记忆,除了打字和胡言乱语,你会怎么做,让我知道你将如何进行。我计划很快就看布莱恩·麦肯纳的《数据61》视频,但在那之前。提前谢谢!

    1 回复  |  直到 5 年前
        1
  •  3
  •   Joseph Sible-Reinstate Monica    5 年前

    首先,我们将过滤功能分为:

    isAnnotatedPdf :: FilePath -> Bool
    isAnnotatedPdf path = (isSubsequenceOf "annotated" (titleString (dir </> path))) && (takeExtension path == ".pdf")
    
    main :: IO ()
    main = do
      print =<<
        liftM
          (filter isAnnotatedPdf)
          (listDirectory dir)
    

    现在,用一些语法糖来清理 main :

    main :: IO ()
    main = do
      dirList <- listDirectory dir
      let filteredList = filter isAnnotatedPdf dirList
      print filteredList
    

    接下来,改变 isAnnotatedPdf 将结果返回到 IO ,然后修改 主要的 这样就可以了:

    isAnnotatedPdf :: FilePath -> IO Bool
    isAnnotatedPdf path = do
      return $ (isSubsequenceOf "annotated" (titleString (dir </> path))) && (takeExtension path == ".pdf")
    
    main :: IO ()
    main = do
      dirList <- listDirectory dir
      filteredList <- filterM isAnnotatedPdf dirList
      print filteredList
    

    提取变量 pdfTitle 里面 ISanotateDPDF 为了更清楚地说明下一步:

    isAnnotatedPdf :: FilePath -> IO Bool
    isAnnotatedPdf path = do
      let pdfTitle = titleString (dir </> path)
      return $ (isSubsequenceOf "annotated" pdfTitle) && (takeExtension path == ".pdf")
    

    最后,改变 ISanotateDPDF 使用新的 输入输出 上下文而不是使用 unsafePerformIO 包装材料:

    isAnnotatedPdf :: FilePath -> IO Bool
    isAnnotatedPdf path = do
      pdfTitle <- title (dir </> path)
      return $ (isSubsequenceOf "annotated" pdfTitle) && (takeExtension path == ".pdf")
    

    你完了!现在你可以摆脱 titleString 所有你提到的 不安全性能 .


    作为奖励,你现在可以很容易地避免需要呼叫。 pdfInfo 通过移动纯 takeExtension 在单子标题检查之前检查到,如下所示:

    isAnnotatedPdf :: FilePath -> IO Bool
    isAnnotatedPdf path = if takeExtension path == ".pdf"
      then do
        pdfTitle <- title (dir </> path)
        return $ isSubsequenceOf "annotated" pdfTitle
      else return False
    

    或使用 <$> 而不是 do :

    isAnnotatedPdf :: FilePath -> IO Bool
    isAnnotatedPdf path = if takeExtension path == ".pdf"
      then isSubsequenceOf "annotated" <$> title (dir </> path)
      else return False