我正在使用aeson
库来为我的自定义Graph
类型生成和解析 json 文件。以下是类型定义。
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)
实际上,我正在使用欧拉图和半欧拉图,它们的所有顶点在二维空间中都有位置。简而言之,Graph 使用 Data.Graph,但这与我的问题无关。每个图表都有自己的 ID,以便在许多其他图表中快速识别它。
这是 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-file 解析回来时遇到了问题。主要问题是这样一个事实,我们不知道有多少顶点有特定的 Graph,所以它不能被硬编码。这是我第一次尝试编写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
并获取顶点,而程序仍然会解析每个 next i
。但这不是一个好的选择,因为 minimumvertex id
并不总是如此1
,有时 nextvertex id
与 current 的差异更大1
。甚至可以解析这些数据吗?无论如何,即使是这个问题的最简单情况(当vertex ids
从开始1
并使用 递增时(+1)
)我也坚持了下来。
好吧。这就是我如何获得最大和最小顶点ID:
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)
所有签名都不是通用的,但这只是示例。
明天我将再次尝试解决这个简单的问题案例。无论如何,主要问题仍然需要一个答案:)