2013-01-07 117 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可能不是正确的方法,在这种情况下,我将删除该方面 - 在黑暗中的一点点。 –