我还是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)
谢谢:)
该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 的工作方式,这是一件好事。如果您想让用户在任意时间执行不纯的操作,您必须针对这样的功能进行设计。这是我对纯交互的介绍- 这是一个起点。
是的,您可以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)