如何在Haskell中使用withAsync在文本文件中搜索子字符串?

时间:2016-06-15 12:59:31

标签: haskell concurrency

我想要实际实现的是在haskell中编写程序。该程序是一个多线程文本文件搜索引擎,它将文本文件分成行列表。每行必须使用模块 Data.List 中的函数 isInfixOf ,该函数应放在模块 Control中的 withAsync 函数内。 Concurrent.Async 。如果在文件中找到我想要搜索的单词,则结果将为True。

我知道以下代码不正确但我正走在正确的道路上。我希望有人为我解决这个问题:

import System.Directory
import Control.Concurrent
import System.FilePath
import Control.Concurrent.Async
import System.Environment
import Data.List hiding (find)
import Control.Monad
import Control.Exception

loop [] = return Nothing
loop (a:as) = do                     -- <4>
  r <- wait a
  case r of
    Nothing -> loop as
    Just a  -> return (Just a)



main = do
         let lines =readFile ("myfile.txt")
         let keyword="to_be_found"
         let asyncs=[]

         forM lines $ \line -> do 
                                     asyncs <- async (print $ isInfixOf keyword line) ++ asyncs


         loop asyncs

2 个答案:

答案 0 :(得分:1)

关于monads

忘记IO一分钟,而您可能认为do符号与IO有关,这是一种常见的误解。 IO只是一个单子,允许你描述与现实世界有关的行为。了解monad是目前的重要部分。 简而言之,monads定义了顺序组合,或者&#34;这样做,然后是#34;,由(>>=) :: Monad m => m a -> (a -> m b) -> m b证明。在命令式语言中,IO内的所有内容和>>=内的所有内容都与;相同。 Read up on how monads and bind (>>=) works.

一些评论

具体而言,您希望在fold操作列表上async进行提前终止。

确保您理解asyncContainsPrefix,因为fileContainsPrefix是微不足道的部分。实质上,joinAsync False (\r -> if r then pure True else Nothing)any的短路和并发版本。该函数的另一部分是关于描述async计算。

代码

我有以下工作......它使用pointfree样式的Haskell并且(几乎)eta-reduced形式:

import Data.List (isInfixOf)

import Control.Monad (forM, mapM_, liftM2)

import Control.Concurrent.Async

import Test.QuickCheck
import Test.QuickCheck.Monadic (monadicIO, run)

main :: IO ()
main = do
    contains <- fileContainsPrefix "to_be_found" "myfile.txt"
    putStrLn $ if contains then "yes" else "no"

--------------------------------------------------------------------------------
-- API:
--------------------------------------------------------------------------------

fileContainsPrefix :: FilePath -> String -> IO Bool
fileContainsPrefix file prefix = lines <$> readFile file >>=
                                 asyncContainsPrefix prefix

asyncContainsPrefix :: Eq a => [a] -> [[a]] -> IO Bool
asyncContainsPrefix prefix ls =
    forM ls (async . pure . isInfixOf prefix)
    >>= joinAsync False (\r -> if r then pure True else Nothing)

joinAsync :: b -> (a -> Maybe b) -> [Async a] -> IO b
joinAsync z handler []     = pure z
joinAsync z handler (a:as) =
    handler <$> wait a >>=
    maybe (joinAsync z handler as) ((mapM_ cancel as >>) . pure)

--------------------------------------------------------------------------------
-- Tests:
--------------------------------------------------------------------------------

prop_async_seq :: Eq a => [a] -> [[a]] -> Property
prop_async_seq prefix ls = monadicIO $
    liftM2 (==) (pure $ containsPrefix prefix ls)
                (run  $ asyncContainsPrefix   prefix ls)

containsPrefix :: Eq a => [a] -> [[a]] -> Bool
containsPrefix = any . isInfixOf

QuickCheck testing

$ ghci Mult.hs
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Mult.hs, interpreted )
Ok, modules loaded: Main.
λ> quickCheck prop_async_seq
+++ OK, passed 100 tests.

答案 1 :(得分:0)

我不知道你是如何顺序阅读文件的每一行的。但是这里有一个函数来确定文件是否包含具有给定前缀的行:

containsPrefix :: FilePath -> String -> IO Bool
filePath `containsPrefix` prefix
  = any (isInfixOf prefix) . lines <$> readFile filePath

免责声明:文件将按顺序读取。