在haskell中构建图形结构

时间:2015-07-10 17:03:52

标签: haskell

我正在建模关系数据库的类型信息。我想建立以下图表:

  1. 顶点是表格。

  2. 对于A中的每个列,表A到表B都存在一个边,这是B的外键。

  3. 这是我用于构建图表的初始数据。

    newtype TableName = TableName T.Text
    newtype ColName = ColName T.Text
    newtype ColType = ColType T.Text
    
    type DBInfo = H.HashMap TableName TableInfo
    type TableInfo = H.HashMap ColName ColInfo
    data ColInfo = CISimple ColType
                 -- Forms the basis for building the graph
                 | CIFKey ColType TableName -- col type, referenced table
    
    getDBInfo :: IO (DBInfo)
    

    这些是我期待的图形结构的类型。

    data SafeColInfo = SCISimple ColType 
                     -- This captures an edge between two tables
                     | SCIFKey ColType SafeTableInfo
    type SafeTableInfo = H.HashMap TableName SafeColInfo
    type SafeDBInfo = ..
    

    我想写这个函数:

    convDBInfo :: DBInfo -> Either String SafeDBInfo
    

    convDBInfo应该构建上面的图表。通过在t中查找(CIFKey ctype t),可以找到有关任何外键t DBInfo的信息。如果未找到,则输入数据不一致并且是错误。

    在带引用的命令式语言中,这是相当简单的。但是,我想不出在Haskell中解决这个问题的方法。据我所知,这看起来非常适合“绑结”范例,但我似乎无法绕过它。我该如何写这个函数?

1 个答案:

答案 0 :(得分:3)

我们可以通过以下方式打结:

convDBInfo :: DBInfo -> SafeDBInfo
convDBInfo dbi = safeDbi where
  safeDbi = H.map (H.map go) dbi
  go (CIFKey colName tblName) = SCIFKey colName $ safeDbi H.! tblName
  go (CISimple colName)       = SCISimple colName

我们通过映射输入中的列条目来获得safeDbi。重要的一点是,我们在safeDbi的定义中从go查找表格,因此SCIFKey - s中的表格将来自生成的hashmap。

示例:

foo :: DBInfo
foo = H.fromList [
  ("table1", H.fromList [
       ("col1", CIFKey "a" "table2")
       ]),
  ("table2", H.fromList [
       ("col2", CIFKey "b" "table1")
       ])
  ]

bar = convDBInfo foo
SCIFKey _ tbl2 = (bar H.! "table1") H.! "col1"
SCIFKey name _ = tbl2 H.! "col2"
-- name == "b"

请注意,虽然棘手的数据结构通常不方便使用,因为它们与懒惰的无限结构无法区分,所以当我们想要打印,序列化或比较它们时,我们必须给它额外的思考。大多数情况下,显式键控图表更易于使用,性能也不会更差。