Я использую библиотеку aeson
для создания и анализа json-файлов для моего пользовательского типа Graph
. Вот определения типов.
type Id = Int
type Edge = (Id, Id)
type Scenario = [Id]
data Point = Point Int Int
data Vertex = Vertex {-# UNPACK #-}!Id {-# UNPACK #-}!Point deriving (Show)
data Graph = Graph Id [Vertex] Scenario deriving (Show)
На самом деле я работаю с эйлеровыми и полуэйлеровыми графами, все вершины которых имеют позиции в 2D-пространстве. В двух словах Graph использует Data.Graph, но это не связано с моей проблемой. Каждый график имеет свой идентификатор, чтобы быстро идентифицировать его среди множества других.
Вот пример json-файла, содержащего информацию о моем графике:
{
"id": 1,
"vertices": {
"3": {
"y": 12,
"x": 0
},
"2": {
"y": 16,
"x": 24
},
"1": {
"y": 12,
"x": 10
}
},
"scenario": [
1,
2,
3,
1
]
}
Итак, вот моя реализация функции toJSON
:
import qualified Data.Text as T
instance ToJSON Graph where
toJSON (Graph id v s) = object [ "vertices" .= object (map vertexToPair v)
, "scenario" .= s
, "id" .= id
]
where
vertexToPair :: Vertex -> (T.Text, Value)
vertexToPair (Vertex id (Point x y)) =
(T.pack $ show id) .= object [ "x" .= x, "y" .= y]
Но на самом деле у меня проблема с разбором json-файла. Основная проблема заключается в том, что мы не знаем, сколько вершин имеет тот или иной граф, поэтому его нельзя жестко закодировать. Вот моя первая попытка написать функцию parseJSON
:
instance FromJSON Graph where
parseJSON (Object v) = do
i <- parseJSON =<< v .: "id"
vs <- parseJSON =<< v .: "vertices"
sc <- parseJSON =<< v .: "scenario"
maybeReturn ((buildGraph i sc) <$> (parseVertices vs 1))
where
parseVertices :: Value -> Int -> Maybe [Vertex]
-- parseVertices (Object o) i = ???
parseVertices _ _ = Just []
buildGraph :: Int -> Scenario -> [Vertex] -> Graph
buildGraph i sc vertices = Graph i vertices sc
maybeReturn Nothing = mzero
maybeReturn (Just x) = return x
parseJSON _ = mzero
На самом деле я думал, что могу начать считать с 1
и получать вершины, пока программа будет разбирать каждые следующие i
. Но это не лучший выбор, потому что минимальное vertex id
не всегда равно 1
, а иногда следующее vertex id
отличается от текущего более чем на 1
. Можно ли вообще разобрать такие данные? Во всяком случае, я остановился даже на самом простом случае этой проблемы (когда vertex ids
начинается с 1
и увеличивается с помощью (+1)
).
Хорошо. Вот как я могу получить максимальный и минимальный идентификатор вершины:
import qualified Data.Text.Read as TR
import qualified Data.Foldable as Foldable
minID :: [Either T.Text Int] -> Int
minID = Foldable.maximum
maxID :: [Either T.Text Int] -> Int
maxID = Foldable.minimum
ids :: Object -> [Either T.Text Int]
ids o = map ((fmap fst) . TR.decimal) (M.keys o)
Все подписи не являются обобщенными, но это только пример.
Я попробую завтра еще раз решить этот простой случай проблемы. В любом случае, главный вопрос все еще требует ответа :)
FromJSON
для вершин, которые считывают индексы? - person duplode   schedule 28.03.2014