Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 在do块内迭代_Haskell_Monads - Fatal编程技术网

Haskell 在do块内迭代

Haskell 在do块内迭代,haskell,monads,Haskell,Monads,我写了这段代码: toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode outputFile <- openFile "couples.txt" WriteMode readAndChange inputFile outputFile readAndChange i o = do iseof <- hIsEOF i

我写了这段代码:

toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
                   outputFile <- openFile "couples.txt" WriteMode
                   readAndChange inputFile outputFile

readAndChange i o = do iseof <- hIsEOF i
                       if iseof then (return o)
                       else do line <- hGetLine i
                               hPutStrLn o (show (extractNameAndId line))
                               readAndChange i o
import-Control.Monad
进口管制.Monad.Trans
进口控制。单子。反式
读取并更改IO=do

结果您可以使用
let
模式进行递归,但这类似于单独定义递归函数:

main = do 
    let x = 10 
    let loop = do 
        print 1 
        when (x<20) loop 
    loop
你所说的是一种
goto标签
模式。我不知道您是否可以实现这种行为,但上面使用的
fix
let
可以轻松帮助您实现递归

[编辑] 还有一些模式可以实现类似的结果,比如使用
Cont
monad,如中所示

getCC' :: MonadCont m => a -> m (a, a -> m b)
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f))

main = (`runContT` return) $ do 
    (x, loopBack) <- getCC' 0
    lift (print x)
    when (x < 10) (loopBack (x + 1))
    lift (putStrLn "finish")
getCC'::MonadCont m=>a->m(a,a->mb)
getCC'x0=callCC(\c->让fx=c(x,f)作为回报(x0,f))
main=(`runContT`return)$do

(x,loopBack)你以一种不必要的方式编程,让生活变得困难。您正在使用漂亮的Haskell语言编程,您正在寻找一个
goto
构造

为什么不直接导入Control.Applicative()
并编写

readAndChange' = writeFile "couples.txt" =<< 
    unlines.map (show.extractNameAndId).lines <$> readFile "deletedId.csv" 
最后一个问题是我们如何在
readAndChange
中使用
。如果数据量很大 deletedId.csv您将错过hello,但您当然可以这样做

greet <$> readFile "deletedId.csv" >>= writeFile "hi.txt"
take 4.lines <$> readFile "hi.txt"
试一试

侮辱“弗雷德”“巴尼”
侮辱“弗雷德”$“巴尼”
侮辱[“弗雷德”、“巴尼”][“威尔玛”、“贝蒂”]
侮辱只是“Fred”没什么
侮辱只是“弗雷德”只是“威尔玛”
侮辱readFile“someone.txt”readFile“someone.txt”
这里在函数后面使用
,在所需的参数之间使用
。它的工作原理一开始有点令人兴奋,但它是编写有效计算的最实用的风格

接下来请阅读有关应用函子的内容。他们很棒。


与命令式编程语言不同,也与其他函数式编程语言不同,Haskell不包含用于编写循环或while循环的语法结构,这正是您在这里要求的

其思想是递归过程和迭代过程可以统一地被递归函数捕获。只是迭代过程被捕获为特定类型的递归函数:这些函数是尾部递归的。命令式代码(如do块中出现的代码)也不例外。您可能会发现这种缺乏显式循环构造的做法很烦人,因为您必须为每个循环定义一个新函数,因此在某种意义上必须命名该循环。然而,这对于Haskell方法的统一性和简单性来说是一个微不足道的代价,原因有三:

  • 您不必定义表示顶级循环的函数。您可以在本地定义它

  • 在Haskell中,许多人通常对这类循环使用相同的名称。这里流行的选择是
    go
    aux
    。因此,您的代码可以重写如下:

    toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
                       outputFile <- openFile "couples.txt" WriteMode
                       let go = do
                            iseof <- hIsEOF inputFile
                            if iseof then (return outputFile)
                            else do line <- hGetLine inputFile
                                    hPutStrLn outputFile (show (extractNameAndId line))
                                    go
                       go
    

    toCouplesFile=do inputFile您应该做的第一件事是阅读模块的文档,这对于编写Haskell代码是绝对必要的。当你这么做的时候,安装Hackage的软件包,并阅读上面的文档;您可能特别感兴趣的是
    whileM\u
    函数:

    import Data.Functor ((<$>)
    import Control.Monad.Loops (whileM_)
    
    readAndChange i o = 
        whileM_ notEOF $ do line <- hGetLine i
                            hPutStrLn o (show (extractNameAndId line))
            where notEOF = not <$> (hIsEOF i)
    

    尽管如此,我还是同意你写这篇文章的方式过于迫切。试着这样想:您的程序基本上是将输入字符串转换为输出字符串。这立即表明程序逻辑的核心应具有以下类型:

    transformInput :: String -> String
    transformInput = ...
    
    您的转换是逐行进行的。这意味着您可以通过这种方式优化草图(函数
    lines
    将字符串拆分为多行;
    取消线
    重新加入列表):

    现在,您已经在
    transformInput
    函数中找到了逻辑的核心,因此您只需要以某种方式将其连接到输入和输出句柄。如果您正在处理stdin和stdout,则可以使用该函数来完成此操作。但我们实际上可以窃取它的实现并修改它:

    hInteract       ::  Handle -> Handle -> (String -> String) -> IO ()
    hInteract i o f =   do s <- hGetContents i
                           hPutStr o (f s)
    
    hinterract::Handle->Handle->(字符串->字符串)->IO()
    
    hinterract i o f=我个人非常喜欢
    fix
    方法。注意,它在道德上等同于“递归
    let
    ”方法,因为
    fix
    是定义递归的一种方法。(事实上,我刚刚将一些代码切换为使用
    fix
    而不是递归的
    let
    )另外,请注意
    fix
    也可以在
    Data.Function
    中使用;这一点也不奇怪
    Control.Monad.Fix
    还提供了
    MonadFix
    类型类,该类提供了
    mfix::MonadFix m=>(a->ma)->ma
    。对于喜欢“循环组合器”方法的任何人,你都可以在中找到比
    Fix
    更复杂的循环。它非常整洁。令人惊讶:)你可以猜到我是哈斯克尔的新手;你能解释一下
    $
    之间有什么不同吗?@Aslan986我现在又加了一点。不可能不接受你的回答。非常感谢安德鲁。
    insult :: String -> String -> String
    insult a b = a ++ ", you're almost as ugly as " ++ b
    
    insult "Fred" "Barney"
    insult "Fred" $ "Barney"
    insult <$> ["Fred","Barney"] <*> ["Wilma","Betty"]
    insult <$> Just "Fred" <*> Nothing
    insult <$> Just "Fred" <*> Just "Wilma"
    insult <$> readFile "someone.txt" <*> readFile "someoneElse.txt"
    
    toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
                       outputFile <- openFile "couples.txt" WriteMode
                       let go = do
                            iseof <- hIsEOF inputFile
                            if iseof then (return outputFile)
                            else do line <- hGetLine inputFile
                                    hPutStrLn outputFile (show (extractNameAndId line))
                                    go
                       go
    
    import Data.Functor ((<$>)
    import Control.Monad.Loops (whileM_)
    
    readAndChange i o = 
        whileM_ notEOF $ do line <- hGetLine i
                            hPutStrLn o (show (extractNameAndId line))
            where notEOF = not <$> (hIsEOF i)
    
    -- |Execute an action repeatedly as long as the given boolean expression
    -- returns True.  The condition is evaluated before the loop body.
    -- Discards results.
    whileM_ :: (Monad m) => m Bool -> m a -> m ()
    whileM_ p f = do
            x <- p
            if x
                    then do
                            f
                            whileM_ p f
                    else return ()
    
    transformInput :: String -> String
    transformInput = ...
    
    transformInput :: String -> String
    transformInput input = unlines (map transformLine (lines input))
    
    transformLine :: String -> String
    transformLine line = show (extractNameAndId line)
    
    hInteract       ::  Handle -> Handle -> (String -> String) -> IO ()
    hInteract i o f =   do s <- hGetContents i
                           hPutStr o (f s)
    
    toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
                       outputFile <- openFile "couples.txt" WriteMode
                       hInteract inputFile outputFile transformInput