haskell - 在 do block 内迭代

标签 haskell monads

我写了这段代码:

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

我想知道我是否可以仅使用一个函数重写此代码,使用类似于此模式的内容:
function x = do ...
                label
                .....
                if ... then label else exit

最佳答案

通过以不必要的命令方式进行编程,您正在使生活变得困难。您正在使用漂亮的 Haskell 语言进行编程,并且正在寻找 goto构造!

为什么不只是 import Control.Applicative (<$>)和写

readAndChange' = writeFile "couples.txt" =<< 
    unlines.map (show.extractNameAndId).lines <$> readFile "deletedId.csv" 

(是的,这几乎是一个单行。它是干净的、功能性的风格,并且没有被读写行的机制弄乱。尽可能多的处理是在纯代码中完成的,只有输入和输出是基于 IO 的。)

说明:

这里unlines.map (show.extractNameAndId).lines通过将输入切割成行来处理您的输入,应用 extractNameAndId然后 show给每一个使用 map ,然后使用 unlines 将它们重新组合在一起.
unlines.map (show.extractNameAndId).lines <$> readFile "deletedId.csv"将读取文件并应用处理函数。 <$> fmap 的语法令人愉快.
writeFile "couples.txt" =<< getanswergetanswer >>= writeFile "couples.txt" 相同- 得到上述答案,然后将其写入文件。

试试写 greet xs = "hello " ++ xs然后在 ghci 中为了好玩而做这些
greet "Jane"        -- apply your pure function purely
greet $ "Jane"      -- apply it purely again
greet <$> ["Jane","Craig","Brian"]  -- apply your function on something that produces three names
greet <$> Just "Jane"               -- apply your function on something that might have a name
greet <$> Nothing                   -- apply your function on something that might have a name
greet <$> getLine                   -- apply your function to whatever you type in 
greet <$> readFile "deletedId.csv"  -- apply your function to your file 

最后一个是我们如何使用 <$>readAndChange .如果里面有很多数据
删除Id.csv 你会想念你好,但当然你可以这样做
greet <$> readFile "deletedId.csv" >>= writeFile "hi.txt"
take 4.lines <$> readFile "hi.txt"

查看前 4 行。

所以$允许你在你给它的参数上使用你的函数。 greet :: String -> String所以如果你写 greet $ person , person必须是 String 类型, 而如果你写 greet <$> someone , someone可以是任何产生 String 的东西- 字符串列表,一个 IO String , Maybe String .从技术上讲,someone :: Applicative f => f String ,但你应该先阅读类型类和应用仿函数。 Learn You a Haskell for Great Good 是一个很好的资源。

更有趣的是,如果你有一个有多个参数的函数,你仍然可以使用可爱的 Applicative 风格。
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"

在这里您使用 <$>后功能和<*>在它需要的参数之间。它的工作原理起初有点令人兴奋,但它是编写有效计算的最实用的风格。

接下来阅读 Applicative Functors。他们很棒。
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
http://en.wikibooks.org/wiki/Haskell/Applicative_Functors

关于haskell - 在 do block 内迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12376623/

相关文章:

haskell - Haskell子类的解释

haskell - 为什么 <$> 和 <*> 以与 >>= 相反的顺序接受输入?

haskell - 在守卫中使用一元 bool 值? (图案 guard )

haskell - 函数类型的 Applicative 和 Monad 实例?

haskell - 界定 IO 单子(monad)

haskell - 如何在 Haskell 中以隐藏的方式初始化状态(就像 PRNG 一样)?

haskell - 变量不在嵌套 where 的范围内

haskell - Monads如何被认为是纯的?

windows - 如何更改 stack.yaml 在 Windows 上的默认位置?

haskell - 什么编程任务为您提供了 monad 的突破?