是否可以在主函数之外(在 haskell 中)使用 writeFile ?

yam*_*yam 1 haskell

我还是Haskell的初学者,所以看了writefile网上的一些教程,看到writefile网上的例子大部分都是在main函数里面使用的(main = IO())

我想知道是否可以编写一个函数,在计算结果writefile时使用它将结果写入文件?在某些程序(尤其是游戏)中,用户可能希望通过将内容保存到 .txt 文件来在游戏的特定点停止。

例如这样的:(这个功能不起作用,只是想知道如何使它起作用)

concat :: FilePath -> [[a]] -> [a]
concat txt [] = []`
concat txt (xs : xss) = do
y <- xs ++ concat xss
writeFile txt (unlines y)
Run Code Online (Sandbox Code Playgroud)

谢谢:)

Mar*_*ann 9

writeFile函数具有 type FilePath -> String -> IO (),这意味着它必须在IO上下文中运行。

它不具有在运行的main功能,但涉及的任何功能IO,其中包括writeFile,将有包括返回类型IO。所以你绝对可以做这样的事情:

myFunc :: String -> IO ()
myFunc contents = do
  -- do something else
  writeFile "foo.txt" contents
  -- do more stuff here
Run Code Online (Sandbox Code Playgroud)

但是,您不能调用IO a从纯函数返回的函数(或者,您不能从 IO 容器中提取值)。那是设计使然;这就是 Haskell 的工作方式,这是一件好事。如果您想让用户在任意时间执行不纯的操作,您必须针对这样的功能进行设计。这是我对纯交互的介绍- 这是一个起点。


Sim*_*ine 7

是的,您可以writeFile在 之外的其他地方使用main,但IO要使地方符合条件,类型必须是该地方的类型签名的一部分。(我说place的原因是因为main它不是一个函数,而你的concat 却是一个函数。而你想查看writeFile调用的地方必须是一个IO action,它可以是函数的结果,也可以不是函数的结果。 )

您提到将与游戏相关的内容保存到 .txt 文件中。一个例子可能是:

saveGame :: FilePath -> GameState -> IO ()
saveGame gameFile gameState =
  writeFile gameFile (serializeGame gameState)

serializeGame :: GameState -> String
serializeGame (GameState ...) = ...

runGame :: GameState -> IO ()
runGame gameState = do
  ...
  if wantsToSaveGame
    then saveGame gameFile gameState
    else ...
  ...
  runGame updatedGameState

main :: IO ()
main = do
  ...
  runGame initialGameState
Run Code Online (Sandbox Code Playgroud)

在这个人为的例子中,serializeGame不适合调用,saveGame因为它是一个纯函数,而是runGame一个IO ()能够影响文件系统上文件的自递归操作。

一个不是函数的相关IO操作的例子可能是这个:

resetSaveGame :: IO ()
resetSaveGame =
  saveGame defaultGameFile initialGameState
Run Code Online (Sandbox Code Playgroud)