Сохранение и загрузка абстрактного типа данных в файл json и чтение из файла в игре для Haskell - PullRequest
0 голосов
/ 18 октября 2019

Я пишу игру на Haskell, в которой я хотел бы сохранить список абстрактных типов данных в текстовый файл в формате JSON, а затем перезагрузить этот сохраненный файл. то есть считайте этот файл обратно в список абстрактного типа данных, а затем используйте этот перезагруженный список в моей игре как обычно. Я совершенно новичок в Haskell и в программировании в целом, поэтому я немного не уверен, возможно ли это вообще.

Мне кажется, я правильно настроил тип данных (Room). Но я не уверен насчет FromJson и toJSON (правильный синтаксис?).

Кроме того, способ сохранения, который я в данный момент сохраняю, не сохраняет файл JSON в нужном мне формате:

[{"reward": "сокровище", "враг": "врага одно", "description": "это комната"}]

, тогда как описание, враг и награда должны быть в порядке.

(я также считаю, что тип данных 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")

Вот сообщения об ошибках, которые я получаю:

forStackOverflow.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 forStackOverflow.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 }

forStackOverflow.hs:47:10:
    Couldn't match expected type ‘[Room]’ with actual type ‘Maybe a0’
    Relevant bindings include
      new :: Maybe a0 (bound at forStackOverflow.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> 

1 Ответ

0 голосов
/ 18 октября 2019

Функция decode из Data.Aeson, как ясно из ее документации , возвращает не целевой тип (какой бы тип вы ни пытались декодировать), а целевой тип, заключенный в Maybe. В вашем случае это будет Maybe [Room], а не просто [Room].

Это отражает тот факт, что декодирование может завершиться неудачно (то есть неправильный формат или что-то еще), и в этом случае функция возвращает Nothing.

Это то, что компилятор говорит вам, когда говорит « Соответствующие привязки включают в себя: new :: Maybe a0 » - это говорит о том, что переменная new имеет тип Maybe a0, где a0 - еще не известный тип.

Затем он говорит, что не может передать Maybe a0 в качестве аргумента start, поскольку start ожидает аргумент типа [Room]: " Не удалосьсопоставить ожидаемый тип [Room] с фактическим типом 'Maybe a0' ... в первом аргументе 'start'"

Чтобы исправить это, вам нужно обработать возможность возврата decode Nothing, и если он возвращает 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 не является хорошим способом обработки неожиданного состояния; я использовал его только в качестве примера)

...