如何在非 IO 函数中使用 IO 操作的结果?

How can I use the result of an IO action in an non-IO-function?

提问人:not_existent 提问时间:1/17/2023 更新时间:1/17/2023 访问量:93

问:

此函数采用文件路径并返回文件的内容。 此文件包括一组相同长度的线条。 -- 它曾经是一张原始的图片。

parsePicture :: FilePath -> IO()
parsePicture fileName = do
    content <- lines <$> readFile fileName
    print content

现在,我尝试实现一个垂直翻转“图片”的函数:

type Picture = [[Char]]

flipVertical :: IO() -> Picture
flipVertical xs = map reverse xs

但我只收到以下错误代码:

zuP12.hs:24:31: error:
    • Couldn't match expected type ‘[[Char]]’ with actual type ‘IO ()’
    • In the second argument of ‘map’, namely ‘xs’
      In the expression: map reverse xs
      In an equation for ‘flipVertical’: flipVertical xs = map reverse xs
   |
24 | flipVertical xs = map reverse xs
   |                               ^^
Failed, no modules loaded.

如何在parsePicture的结果上使用我的函数flipVertical?

Haskell 类型 函数式编程 IO

评论

0赞 user253751 1/17/2023
首先,您的“读取图片”功能必须返回图片而不是打印图片
4赞 chi 1/17/2023
请注意,可以说,的主要设计目标是防止具有像 这样的(有意义的)函数。通过禁止这一点,我们可以知道任何执行 IO 的函数都必须涉及其类型。例如,非 IO 函数(如)永远无法执行任何 IO;如果需要 IO,则类型必须为 。这有助于清楚地标记哪些是 IO,哪些不是。IOIO Something -> NonIOTypeIOf :: Int -> Intf :: Int -> IO Int
3赞 Daniel Wagner 1/18/2023
“如何在非 IO 函数中使用 IO 操作的结果?”你不需要,你使用非 IO 函数来构造一个(甚至更大的)IO 操作。

答:

5赞 leftaroundabout 1/17/2023 #1

这个功能...返回文件的内容。

不,它没有。它将文件的内容打印到 STDOUT。在大多数情况下,您应该认为您放入 STDOUT 的信息已经消失——该信息已经离开您的程序,现在位于终端屏幕上,或者用户选择放置它的任何位置,但程序无法再访问。

(严格来说,可以将 STDOUT 重定向回您自己的程序,但这是一个很大的黑客,不要这样做。

相反,您应该更改函数,以便它实际上返回内容:

parsePicture :: FilePath -> IO Picture
parsePicture fileName = do
    content <- lines <$> readFile fileName
    return content

...或者干脆

parsePicture fileName = lines <$> readFile fileName

其行为完全相同(根据 Monad 定律)。

另外,我宁愿称之为:解析不应该涉及文件读取。loadPicture

当然,您以后仍然可以打印内容,例如

main = do
   ...
   fooPicture <- parsePicture "foofilename"
   print fooPicture
   ...

至于,这应该与此完全无关。它只是一个纯函数flipVerticalIO

flipVertical :: Picture -> Picture
flipVertical xs = map reverse xs

例如,可以像这样使用

main = do
   ...
   fooPicture <- parsePicture "foofilename"
   print $ flipVertical fooPicture
   ...

main = do
   ...
   fooVFPicture <- flipVertical <$> parsePicture "foofilename"
   ...

评论

1赞 user253751 1/17/2023
吹毛求疵:您打印的信息仍在程序中 - 但前提是您将其保留在某个变量中 - 打印它没有区别。