Haskell 如何在递归IO操作中使用累加器
我有以下问题: 我想逐行读取文件,然后将这些行写入另一个文件。但是,我想返回行数 因此,在纯函数中,我将使用如下累加器:Haskell 如何在递归IO操作中使用累加器,haskell,io-monad,Haskell,Io Monad,我有以下问题: 我想逐行读取文件,然后将这些行写入另一个文件。但是,我想返回行数 因此,在纯函数中,我将使用如下累加器: function parameters=method 0 ...... method accu {end case scenario} =accu method accu {not end case} = accu+1 //and other stuff main :: IO () main
function parameters=method 0 ......
method accu {end case scenario} =accu
method accu {not end case} = accu+1 //and other stuff
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
count <- loop inHandle outHandle 0
hClose inHandle
hClose outHandle
putStrLn (show count) -- could just write @print count@
如何在不使用其他函数的情况下在do块中实现相同的功能
具体例子
module Main where
import System.IO
import Data.Char(toUpper)
main::IO()
main=do
let inHandle=openFile "in.txt" ReadMode
let outHandle=openFile "out.txt" WriteMode
inHandle>>= \a ->outHandle>>= \b ->loop a b 0>>=print . show
loop::Handle->Handle->Int->IO Int
loop inh outh cnt=hIsEOF inh>>= \l ->if l then return elem
else
do
hGetLine inh>>=hPutStrLn outh
loop inh outh (cnt+1)
编辑
以循环
获取其参数的方式进行重构
p.S.2(在K.A.布尔的彻底回应之后)
I.我真正想要实现的是main
方法的最后一个表达式。我想执行多个IO操作
s并将其结果绑定到一个方法。具体而言:
inHandle>>= \a ->outHandle>>= \b ->loop a b 0>>=print . show
在这种情况下,我不理解的是:
如果将inHandle>=
提供给\a->
,然后将结果传递给..>=\b
,是否在\b
中关闭外部范围内的变量
如果不是,它不应该是>=\a->..>=\ab
?内部范围不应该包含与外部范围的结果相对应的参数吗
在助手方法中消除do
我想知道的是,是否有一种方法可以将多个动作粘合在一起,而不必将它们放在do
块中
就我而言:
loop::Handle->Handle->Int->IO Int
loop inh outh cnt=hIsEOF inh>>= \l ->if l then return elem
else
do
hGetLine inh>>=hPutStrLn outh
loop inh outh (cnt+1)
难道我不能说:
如果。。。然后…
否则
hPutStrLn=看起来您最后一个问题的答案仍然让您感到困惑
tl;dr:停止使用>=
和=
首先,我建议避免使用代码>=
和=这看起来你上一个问题的答案仍然让你感到困惑
tl;dr:停止使用>=
和=
首先,我建议避免使用代码>=
和=为什么不想使用其他函数?在Haskell中,这是执行类似操作的“正常”方式。您在使用let inHandle=(=使用loop::Handle->Handle->Int->IO Int
作为类型,并将0作为初始整数累加器传递。在递归调用中,您可以使用loop ioIn ioOut(accu+1)
你不能用>=
>=
创建一个新的绑定,因为它只是一个函数(所以它的参数必须已经存在)。在do
块中,你只能用let
或inHandle>=\a->outHandle>=\b->loop a b 0>=print创建一个新绑定。show
实际上是inHandle>=(\a->outHandle>>=(\b->loop a b 0>>=(print.show))
因此,当我们到达(print.show)
时,b
和a
都在范围内——第二个(\b->…
)lambda嵌套在第一个(\a->…
)lambda。为什么不想使用另一个函数?在Haskell中,这是执行类似操作的“正常”方式。在let inHandle=(=改用loop::Handle->Handle->Int->IO Int
作为类型,并将0作为初始整数累加器传递。在递归调用中,您可以使用loop ioIn ioOut(accu+1)
您无法使用>=
=
创建新绑定,因为它只是一个函数(因此它的参数必须已经存在)。在do
块中,您只能使用let
或=\a->outHandle>=\b->loop a b 0>>=print创建一个新绑定。show
实际上是inHandle>=(\a->outHandle>=(\b->loop a b 0>=(print.show))
所以当我们到达(print.show)时
b
和a
都在范围内——第二个(\b->…
)lambda嵌套在第一个(\a->…
)lambda中。IORef
对于初学者来说比StateT
imo更容易处理,但如果不是这样的话,这是一个很好的回答,我发现“是一个IO操作”语言极为混乱,即使直接限定词是“配方”。我认为只要马上说“是IO操作配方”就清楚多了。对于从do符号开始,我非常同意。(只是想了一件事——对单子使用“Doable”作为“Mappable”的平行词怎么样对于函子…?当然是给新手的提示,而不是一个严肃的命名建议。)续。因此,它将读作“(1)在Haskell中,IO a
类型的任何值都是I/O操作配方。该配方描述了一些可以执行的I/O操作,以执行一些实际的输入/输出,从而产生一些a
类型的值。因此,IO String
类型的值是一个I/O操作配方,如果执行,将执行这些输入/输出a操作并生成一个类型为String
的值,因此…(3)可以使用do符号将多个I/O操作配方组合成一个组合I/O操作配方“…供您考虑:”(尚未阅读其余内容…(参见Conor McBride的a,带图片).但是,在阅读了你更多的优秀答案后,我发现这一变化需要相当广泛的重写,所以,没关系。:(澄清一下:“行动”让我感到困惑,因为对我来说,“行动”是已经在执行的东西,已经在执行了)对于初学者来说,IORef
比StateT
imo更容易处理,但除此之外,这是一个很好的回答。我发现“是一个IO操作”的语言非常令人困惑,即使是即时操作
myAction :: IO ()
myAction = do
putStrLn "Your name?"
x <- getLine
let stars = "***"
putStrLn (stars ++ x ++ stars)
import System.IO
myAction :: IO ()
myAction = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
loop inHandle outHandle
hClose outHandle
hClose inHandle
> :t openFile "in.txt" ReadMode
openFile "in.txt" ReadMode :: IO Handle
>
let inHandle = openFile "in.txt" ReadMode
inHandle <- openFile "in.txt" ReadMode
loop :: Handle -> Handle -> IO ()
loop inHandle outHandle = do
end <- hIsEOF inHandle
if end
then return ()
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle
end <- hIsEOF inHandle
main :: IO ()
main = myAction
import System.IO
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
loop inHandle outHandle
hClose inHandle
hClose outHandle
loop :: Handle -> Handle -> IO ()
loop inHandle outHandle = do
end <- hIsEOF inHandle
if end
then return ()
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle
end <- hIsEOF inHandle
if end
then ...
if hIsEOF inHandle
then ...
loop inHandle outHandle
count <- loop inHandle outHandle 0
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
count <- loop inHandle outHandle 0
hClose inHandle
hClose outHandle
putStrLn (show count) -- could just write @print count@
loop :: Handle -> Handle -> Int -> IO Int
loop inHandle outHandle count = do
end <- hIsEOF inHandle
if end
then return count
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
import System.IO
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
count <- loop inHandle outHandle 0
hClose inHandle
hClose outHandle
putStrLn (show count) -- could just write @print count@
loop :: Handle -> Handle -> Int -> IO Int
loop inHandle outHandle count = do
end <- hIsEOF inHandle
if end
then return count
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
import Control.Monad.Loops
import System.IO
main :: IO ()
main =
withFile "in.txt" ReadMode $ \inHandle ->
withFile "out.txt" WriteMode $ \outHandle ->
whileM_ (not <$> hIsEOF inHandle) $ do
line <- hGetLine inHandle
hPutStrLn outHandle line
import Control.Monad.State
import Control.Monad.Loops
import System.IO
main :: IO ()
main = do
n <- withFile "in.txt" ReadMode $ \inHandle ->
withFile "out.txt" WriteMode $ \outHandle ->
flip execStateT 0 $
whileM_ (not <$> liftIO (hIsEOF inHandle)) $ do
line <- liftIO (hGetLine inHandle)
liftIO (hPutStrLn outHandle line)
modify succ
print n
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
else hGetLine inHandle >>= hPutStrLn outHandle >> loop inHandle outHandle (count + 1)