1

我正在创建一个需要存储用户在数据库中运行的所有函数和参数的系统。没有记录被删除,但我需要能够重新创建最小的函数序列和参数集以进行确定性重新生成。

用户交互非常少,他们不是编程 - 输入交互在 C++ 中处理,通过 FFI 作为数据传递到列表中并回调以处理当前数据缓冲区。该函数触发一系列关于如何连接数据库中数据集的处理图以及它们被输入到的函数的决策。该图是非循环的。该图最初是运行的,并且值是为用户可视化的。图的后面部分将被重新组合以生成新的图。

这些图的 Haskell 内部结构是通过分析数据库中的数据和组合之间的简单随机选择创建的。我希望能够只存储随机生成器的种子、它适用的模块和参数 id。

我认为这可能最好将 EDSL 的功能存储在数据库中,其中仅存储高级交互,但具有完全确定性。

我对存储值不感兴趣,而是对动作的函数图感兴趣。

每个表指的是不同的功能。每条记录都有一个日期和一个任务 ID,以将特定操作的所有功能组合在一起。参数引用表 ID 和记录 ID。如果组合函数在内部执行诸如生成随机数之类的操作,则应自动存储该数字的种子。

我正在使用没有 GHCI 和 Persistent SQlite 的 GHC 阶段 1。

我还是 Haskell 的新手,我正在寻找适合以功能方式解决此问题的方法和软件包。

4

1 回答 1

3

如果您想对源级函数执行此操作,例如:

myFoo x y = x + y

除非您想在编译器中四处乱窜,否则您几乎不走运。但是,您可以使用一些合适的注释定义自己的支持此功能的函数概念。让我们将此概念称为 a UserAction a,其中a是操作的返回类型。为了在 中组合计算UserAction,它应该是Monad. 不用想太多,我的第一印象是使用这堆 monad 转换器:

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

WriterT [LogEntry]组件表示 aUserAction运行时会生成一个 s [1] 序列LogEntry,其中包含您要写入数据库的信息;就像是:

data LogEntry = Call FuncIdentifier FuncIdentifier

现在可以推迟存储随机种子、任务标识符等——可以通过将信息添加到LogEntry.

ReaderT FuncIdentifier组件说 aUserAction取决于 a FuncIdentifier; 即,调用它的函数的标识符。

FuncIdentifier可以通过简单的东西来实现

type FuncIdentifier = String

或者,如果您愿意,可以使用具有更多结构的东西。

IO组件表示UserActions 可以对文件、控制台、生成线程等进行任意输入和输出。如果您的操作不需要它,请不要使用它(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

从顶层运行所需的操作,完成后,收集所有LogEntrys 并将它们写入数据库。

如果您需要在代码执行时实时编写调用,则需要一个不同的UserActionmonad;但您仍然可以呈现相同的界面。

这种方法使用了一些中间的 Haskell 概念,例如 monad 转换器。我建议在 IRC 上irc.freenode.net #haskell寻求有关填写此实施草图细节的指导。他们是一群善良的人,很乐意帮助您学习:-)。

[1] 在实践中,您不想使用[LogEntry]而是DList LogEntry为了性能。但是更改很容易,我建议您继续使用,[LogEntry]直到您对 Haskell 更加熟悉,然后切换到DList.

[2] 随机数生成可以纯粹完成,但它需要进一步的大脑重新布线,这个草图已经有很多了,所以我建议把它当作一个IO效果来开始。

于 2013-01-07T18:37:19.677 回答