2013-01-07 39 views
1

我正在創建一個需要存儲用戶在數據庫中運行的所有功能和參數的系統。沒有記錄被刪除,但我需要能夠重新創建確定性再生的最小函數序列和參數集。撤消數據庫中的記錄

用戶交互非常少,它們不是編程 - 在C++中處理輸入交互是通過FFI作爲數據傳遞到列表和回調來處理當前的數據緩衝區。該函數會觸發一系列關於如何連接數據庫中的數據集處理圖形及其輸入的函數的一系列決策。該圖是非循環的。此圖形最初運行並且值爲用戶可視化。圖表的後面部分將重新組合以生成新圖。

Haskell這些圖的內部構造是從數據庫中的數據分析和組合中的簡單隨機選擇創建的。我希望能夠存儲隨機生成器的種子,它應用的模塊和參數ID。

我認爲這可能是最好的框架作爲存儲EDSL的功能在數據庫中,其中只有高級別的交互存儲,但是完全確定性。

我對存儲值不感興趣,而是操作的功能圖。

每個表格指的是不同的功能。每條記錄都有一個日期和一個任務ID,以便將特定操作的所有功能歸爲一組。這些參數引用表ID和記錄ID。如果一個組合的函數在內部做某事,比如產生一個隨機數,那麼該數字的種子應該被自動存儲。

我正在使用沒有GHCI和持久性SQlite的GHC階段1。

我對Haskell還是一個新手,希望找出哪些方法和軟件包適合以功能方式解決這個問題。

+0

你是什麼意思的「功能圖」? GHC Haskell在運行時系統中將函數表示爲圖形(運行時是所謂的圖形縮減機器),但內部不能被用戶訪問。將函數存儲在數據庫中會非常複雜 - 通常這是「持久」語言的領域,例如Napier 88或Tycoon-2。在Napier 88的持久性商店(Persistent Haskell)上實施了Haskell,但這是一個早已完成的研究項目。 –

+0

對不起,有點不清楚。我仍然與Haskell搖擺不定。我會用我認爲可能是我需要的策略來重述這個問題。我現在打字。 –

+0

用戶與什麼樣的API進行交互? – Henrik

回答

3

如果你想對源代碼級的功能,如做到這一點:

myFoo x y = x + y 

你非常不走運了,除非你想要去的編譯器黑客左右。但是,您可以定義您自己的支持此功能的概念,並帶有一些適當的註釋。我們稱這個概念爲UserAction a,其中a是該操作的返回類型。爲了組成UserAction中的計算,它應該是Monad。沒有想到過非常辛苦,我的第一感覺就是使用這個堆棧單子變壓器:

type UserAction = WriterT [LogEntry] (ReaderT FuncIdentifier IO) 

WriterT [LogEntry]組件說,一個UserAction,運行時產生的LogEntry S [1]的序列,其中含有你想要寫入數據庫的信息;是這樣的:

data LogEntry = Call FuncIdentifier FuncIdentifier 

沒關係推遲存儲隨機種子,任務標識符等現在 - 這可以通過將信息添加到LogEntry被納入這個設計。

ReaderT FuncIdentifier組件說,UserAction取決於FuncIdentifier;即調用它的函數的標識符。

FuncIdentifier可以通過爲

type FuncIdentifier = String 

簡單的東西來實現,或者你使用的東西與更多的結構,如果你喜歡。

IO組件說,UserAction s可以做任意的輸入和輸出到文件,控制檯,產卵線程,整個很多。如果您的操作不需要此操作,請不要使用它(使用Identity代替)。但是既然你提到了產生隨機數,我想你並沒有純粹的計算[2]。

那麼你會標註你想要這樣的功能來記錄日誌,每個動作:

userAction :: FuncIdentifier -> UserAction a -> UserAction a 

這會像這樣使用:

randRange :: (Integer, Integer) -> UserAction Integer 
randRange (low,hi) = userAction "randRange" $ do 
    -- implementation 

userAction將記錄呼叫,並設置記錄他們的呼叫;例如是這樣的:

userAction func action = do 
    caller <- ask 
    -- record the current call 
    tell [Call caller func] 
    -- Call the body of this action, passing the current identifier as its caller. 
    local (const func) action 

從頂層,運行所需的行動和完成任務後,收集了所有的LogEntry S和它們寫入數據庫。

如果您需要在代碼執行時實時寫入呼叫,則需要不同的UserAction monad;但你仍然可以呈現相同的界面。

該方法使用了一些中間Haskell概念,如monad變換器。我建議去IRC irc.freenode.net#haskell頻道詢問關於填寫本實施草圖細節的指導。他們是一羣善良的人,會很樂意幫助你學習:-)。

[1]在實踐中,您不會想要使用[LogEntry]而是使用DList LogEntry來獲得性能。但改變很簡單,我建議你用[LogEntry],直到你對Haskell更舒適,然後切換到DList

[2]隨機數字的生成可以純粹完成,但它需要進一步的大腦重新連接,這個草圖已經有很多,所以我建議只是把它當作一個IO效果來達到目的。

+1

你的問題不斷變化!這種方法不太適合確定性再生 - 主要是因爲'UserAction'類型中的'IO'。我認爲我們需要更多地瞭解你的這個框架的用途,以幫助確定性更新 - 如果你不使用'IO',Haskell是純粹的和確定性的,所以你可能不需要做任何事情,只需記錄輸入到計算。 – luqui

+0

我已經更新了這個問題。 EDSL可能不是正確的方法,在這種情況下,我將刪除該方面 - 在黑暗中的一點點。 –