将抽象数据类型保存并加载到 json 文件并从游戏中的文件读取 Haskell
Saving and loading abstract data type to json file and reading from file in the game for Haskell
我正在 Haskell 中编写一个游戏,其中我想将抽象数据类型的列表保存到 JSON 格式的文本文件中,然后重新加载该保存的文件。即将该文件读回到抽象数据类型的列表中,然后在我的游戏中正常使用该重新加载的列表。我对 Haskell 和一般编程还很陌生,所以我一开始有点不确定这是否可行。
我相信我已经正确设置了我的数据类型(房间)。但我不确定 FromJson 和 toJSON (语法正确吗?)。
此外,我目前保存的方式并没有以我想要的格式保存 JSON 文件:
[{"reward":"treasure","enemy":"enemyOne","description":"this is a room"}]
而描述、敌人和奖励应该是顺序。
(我还认为 Room 数据类型应该在 JSON 文件中的所有内容之前,对吗?)。
如果您需要更多说明,请告诉我。谢谢!
{-# LANGUAGE
OverloadedStrings
, DeriveGeneric
#-}
module Game where
--import System.IO
import Text.Read
import Data.Char
import Prelude hiding (readFile, writeFile)
import Data.Aeson
import Data.Text as T hiding (length, tail)
import Data.ByteString.Lazy as B hiding (putStrLn, length, tail, writeFile, readFile)
import Data.ByteString.Lazy.Char8 as BC hiding (putStrLn, length, tail)
import GHC.Generics
data Room = Room
{ description :: String
, enemy :: String
, reward :: String
} deriving (Show, Generic)
-- is this syntax correct for parseJSON?
instance FromJSON Room where
parseJSON (Object v) = Room <$> v .: "description" <*> v .: "enemy" <*> v .: "reward"
-- is this syntax correct for toJSON?
instance ToJSON Room where
toJSON (Room desc enem reward) = object ["description" .= desc, "enemy" .= enem, "reward" .= reward]
save lst =
do
writeFile "savegame.txt" (encode lst)
return()
load =
do
lst <- readFile "savegame.txt"
let new = decode lst
start new
start :: [Room] -> IO()
start lst =
putStrLn("Starting the game, need to use the lst as a list of rooms")
这些是我收到的错误消息:
forWhosebug.hs:46:14:
No instance for (FromJSON a0) arising from a use of ‘decode’
The type variable ‘a0’ is ambiguous
Relevant bindings include
new :: Maybe a0 (bound at forWhosebug.hs:46:8)
Note: there are several potential instances:
instance FromJSON DotNetTime
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
instance FromJSON Value
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
instance FromJSON a => FromJSON (Control.Applicative.Const a b)
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
...plus 89 others
In the expression: decode lst
In an equation for ‘new’: new = decode lst
In the expression:
do { lst <- readFile "savegame.txt";
let new = decode lst;
start new }
forWhosebug.hs:47:10:
Couldn't match expected type ‘[Room]’ with actual type ‘Maybe a0’
Relevant bindings include
new :: Maybe a0 (bound at forWhosebug.hs:46:8)
In the first argument of ‘start’, namely ‘new’
In a stmt of a 'do' block: start new
Failed, modules loaded: none.
Prelude>
Data.Aeson
中的函数 decode
,从 its documentation 中可以清楚地看出,returns 不是目标类型(无论您尝试解码哪种类型),但是Maybe
中包含的目标类型。在您的情况下,这将是 Maybe [Room]
,而不仅仅是 [Room]
。
这反映了解码可能失败的事实(即不正确的格式或其他),在这种情况下函数 returns Nothing
.
这就是编译器在说“相关绑定包括:new :: Maybe a0”时告诉您的内容 - 它表示变量 new
已被推断具有类型 Maybe a0
,其中 a0
是一些未知类型。
然后继续告诉您它不能将 Maybe a0
作为参数传递给 start
,因为 start
需要类型 [Room]
的参数: “无法将预期类型 [Room] 与实际类型 'Maybe a0' 匹配......在 'start' 的第一个参数中”
要解决此问题,您需要处理 decode
返回 Nothing
的可能性,如果 returns Just
,则将其内容传递给 start
。像这样:
load =
do
lst <- readFile "savegame.txt"
let new = decode lst
case new of
Nothing ->
error "Incorrect file format"
Just n ->
start n
(注意调用error
不是处理意外情况的好方法;我只是用它作为例子)
我正在 Haskell 中编写一个游戏,其中我想将抽象数据类型的列表保存到 JSON 格式的文本文件中,然后重新加载该保存的文件。即将该文件读回到抽象数据类型的列表中,然后在我的游戏中正常使用该重新加载的列表。我对 Haskell 和一般编程还很陌生,所以我一开始有点不确定这是否可行。
我相信我已经正确设置了我的数据类型(房间)。但我不确定 FromJson 和 toJSON (语法正确吗?)。
此外,我目前保存的方式并没有以我想要的格式保存 JSON 文件:
[{"reward":"treasure","enemy":"enemyOne","description":"this is a room"}]
而描述、敌人和奖励应该是顺序。
(我还认为 Room 数据类型应该在 JSON 文件中的所有内容之前,对吗?)。
如果您需要更多说明,请告诉我。谢谢!
{-# LANGUAGE
OverloadedStrings
, DeriveGeneric
#-}
module Game where
--import System.IO
import Text.Read
import Data.Char
import Prelude hiding (readFile, writeFile)
import Data.Aeson
import Data.Text as T hiding (length, tail)
import Data.ByteString.Lazy as B hiding (putStrLn, length, tail, writeFile, readFile)
import Data.ByteString.Lazy.Char8 as BC hiding (putStrLn, length, tail)
import GHC.Generics
data Room = Room
{ description :: String
, enemy :: String
, reward :: String
} deriving (Show, Generic)
-- is this syntax correct for parseJSON?
instance FromJSON Room where
parseJSON (Object v) = Room <$> v .: "description" <*> v .: "enemy" <*> v .: "reward"
-- is this syntax correct for toJSON?
instance ToJSON Room where
toJSON (Room desc enem reward) = object ["description" .= desc, "enemy" .= enem, "reward" .= reward]
save lst =
do
writeFile "savegame.txt" (encode lst)
return()
load =
do
lst <- readFile "savegame.txt"
let new = decode lst
start new
start :: [Room] -> IO()
start lst =
putStrLn("Starting the game, need to use the lst as a list of rooms")
这些是我收到的错误消息:
forWhosebug.hs:46:14:
No instance for (FromJSON a0) arising from a use of ‘decode’
The type variable ‘a0’ is ambiguous
Relevant bindings include
new :: Maybe a0 (bound at forWhosebug.hs:46:8)
Note: there are several potential instances:
instance FromJSON DotNetTime
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
instance FromJSON Value
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
instance FromJSON a => FromJSON (Control.Applicative.Const a b)
-- Defined in ‘aeson-1.4.5.0:Data.Aeson.Types.FromJSON’
...plus 89 others
In the expression: decode lst
In an equation for ‘new’: new = decode lst
In the expression:
do { lst <- readFile "savegame.txt";
let new = decode lst;
start new }
forWhosebug.hs:47:10:
Couldn't match expected type ‘[Room]’ with actual type ‘Maybe a0’
Relevant bindings include
new :: Maybe a0 (bound at forWhosebug.hs:46:8)
In the first argument of ‘start’, namely ‘new’
In a stmt of a 'do' block: start new
Failed, modules loaded: none.
Prelude>
Data.Aeson
中的函数 decode
,从 its documentation 中可以清楚地看出,returns 不是目标类型(无论您尝试解码哪种类型),但是Maybe
中包含的目标类型。在您的情况下,这将是 Maybe [Room]
,而不仅仅是 [Room]
。
这反映了解码可能失败的事实(即不正确的格式或其他),在这种情况下函数 returns Nothing
.
这就是编译器在说“相关绑定包括:new :: Maybe a0”时告诉您的内容 - 它表示变量 new
已被推断具有类型 Maybe a0
,其中 a0
是一些未知类型。
然后继续告诉您它不能将 Maybe a0
作为参数传递给 start
,因为 start
需要类型 [Room]
的参数: “无法将预期类型 [Room] 与实际类型 'Maybe a0' 匹配......在 'start' 的第一个参数中”
要解决此问题,您需要处理 decode
返回 Nothing
的可能性,如果 returns Just
,则将其内容传递给 start
。像这样:
load =
do
lst <- readFile "savegame.txt"
let new = decode lst
case new of
Nothing ->
error "Incorrect file format"
Just n ->
start n
(注意调用error
不是处理意外情况的好方法;我只是用它作为例子)