Haskell 写文件

标签 haskell types io

初学者。有一个名为 HHtml 的模块输出:

  setDoc = "<!DOCTYPE = <html><head>"
  setTitle = "<title>" ++ htmlTitle generator ++ "</title>"
  setHeader = "<header>" ++ htmlHeader generator ++ "</header>"
  setMeta = "<meta>" ++ htmlMeta generator ++ "</meta></head>"
  setBody = "<body>" ++ htmlBody generator ++ "</body>"
  setFooter = "<footer>" ++ htmlFooter generator ++ "</footer>"
  setEOF = "</html>"

  setHTML = [setDoc, setTitle, setHeader, setMeta, setBody, setFooter, setEOF]

主文件:

import HHtml
import System.IO

main = do
  let content = mapM_ putStrLn setHTML
  writeFile "index.html" content

现在,无论我怎么看,我总是收到 Couldn't match type IO() with [Char] 或任何与此相关的变体。我理解该错误消息,但我对修复它感到非常困惑。谢谢指点!

最佳答案

mapM_ putStrLn setHTMLIO () 类型的操作,您将其分配给带有 的名称 content let 语句。执行时,此操作将打印 setHTML 的每一行,不返回任何内容。您可以通过编写如下内容来执行此操作:

main = do
  let content = mapM_ putStrLn setHTML
  content

如果没有变量,这只是:

main = mapM_ putStrLn setHTML

但是 content 是一个不透明的值 - 您可以用它做的唯一事情就是从 main 执行它,将其加入到其他使用 >>= (或 do 表示法)的 IO 操作,并将其存储在数据结构中(此处不需要)。特别是,它不“存储”页面的内容,它只是向运行时描述它应该如何打印该内容。无论如何,您注意到类型不匹配: writeFile 接受 String,又名 [Char],这显然不是 IO ( )

但是由于您显然希望使用 writeFilesetHTML 的每一行写入文件,而不是标准输出,因此您不希望执行打印的操作行——你需要行本身,用换行符连接在一起。有几种可能的方法可以做到这一点,具体取决于您希望如何扩展此代码。

一种方法是使用 unlines::[String] -> String 函数将行与换行符连接在一起,然后使用 writeFile 写入生成的 字符串“index.html”:

main = writeFile "index.html" (unlines setHTML)

如果您想将连接的内容放入变量中,您当然可以这样做:

main = do
  let content = unlines setHTML
  writeFile "index.html" content

(事实上,如果您不需要 setHTML 成为 ,您可以将 unlines 调用移至 setHTML 的定义中[字符串]。)

现在 writeFile 将接受 content,因为它是一个 String 值,而不是 IO () 操作。这是一个很好的方法,因为它保持构建页面的逻辑纯粹,并且仅根据实际编写页面的需要使用IO

或者,您可以采取更命令式的方法,留在 IO 中。那么一个很好用的函数是 withFile (来自 System.IO),它具有以下类型:

FilePath -> IOMode -> (Handle -> IO r) -> IO r

它需要一个FilePath来打开,一个IOMode(例如ReadModeWriteMode)来指示您是否将读取或写入句柄,以及一个接受句柄并执行一些IO并返回某种类型r的结果的函数>;它返回一个 IO 操作,该操作打开文件,运行您的函数,自动确保文件关闭(即使抛出异常),并返回结果。

然后,您将按照与现有方式类似的方式使用 mapM_,将每一行打印到该句柄 - 为此,有 hPutStrLn::Handle -> String -> IO () 写入特定句柄,而不是 putStrLn 写入标准输出。紧凑版本:

main = withFile "index.html" WriteMode $ \file -> do
  mapM_ (hPutStrLn file) setHTML

或者如果您不喜欢 lambda 的外观,可以使用更详细的版本:

main = withFile "index.html" WriteMode writeContents
  where writeContents file = mapM_ (hPutStrLn file) setHTML

关于Haskell 写文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52290934/

相关文章:

haskell - 为什么突然找不到模块?

algorithm - 将 Haskell 反转计数器移植到 Scala

performance - Haskell Foldl' 性能不佳 (++)

haskell - 堆栈解释器选项 - 添加外部依赖项

Php 类型提示不适合接口(interface)和抽象类?

java - 在 Java 中,当使用 DataOutputStream 写入文件时,如何定义正在写入的数据的 Endian?

基于对象类型的WPF触发器

ios - 在 "as!"之后发送类类型作为参数

Java 是否 InputSream.read(byte[] b, int offset, int length) 等待指定的全部字节数

python - 在Python中多次计算文件中的行数