2015-07-10 113 views
4

我正在建模關係數據庫的類型信息。我想構建如下圖:在haskell中構建圖結構

  1. 頂點是表格。

  2. 的邊緣從表A中存在表B對A的每個列是一個外鍵B.

這是用於構建圖中的初始數據我有。

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)的信息可以通過查找tDBInfo中找到。如果找不到,則輸入數據不一致並且是錯誤的。

這在命令式語言中很引用。但是,我想不出在Haskell中解決這個問題的方法。據我瞭解,這看起來很適合'綁結'的範式,但我似乎無法把頭圍住它。我如何編寫這個函數?

+0

對不起,convDBInfo'應該做些什麼? – Ryan

+0

對不起,我不清楚。編輯添加信息。 – svr

+1

如果你知道不會有錯誤,爲什麼它需要返回'Either'? – Ryan

回答

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通過映射。重要的一點是,我們在go的定義中查找來自safeDbi的表格,因此SCIFKey-s中的表格將來自得到的散列映射。

例子:

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" 

不過,請注意棘手的數據結構通常是使用不方便,因爲他們是從懶惰無限的結構沒有區別,所以我們必須給它額外的思考,當我們想打印,序列化或比較它們。大多數情況下,顯式密鑰圖很容易使用,性能也不會太差。