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で、 はアクションの戻り値の型です。で計算を構成するにはUserActionMonad. あまり難しく考えなくても、私の第一印象は、このモナド変換子のスタックを使用することです。

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

このWriterT [LogEntry]コンポーネントは、 aUserActionを実行すると、データベースに書き込む情報を含む一連のLogEntrys [1] が生成されることを示しています。何かのようなもの:

data LogEntry = Call FuncIdentifier FuncIdentifier

今のところ、ランダム シード、タスク ID などの保存を延期しても問題ありません。情報を に追加することで、この設計に組み込むことができますLogEntry

ReaderT FuncIdentifierコンポーネントは、 a が aUserActionに依存していると述べていFuncIdentifierます。つまり、それを呼び出している関数の識別子です。

FuncIdentifier次のような簡単なもので実装できます

type FuncIdentifier = String

または、必要に応じて、より構造のあるものを使用します。

IOコンポーネントは、sUserActionがファイル、コンソール、スポーン スレッドなど、すべてに対して任意の入出力を実行できることを示しています。アクションでこれが必要ない場合は、使用しないでください (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てデータベースに書き込みます。

コードの実行中に呼び出しをリアルタイムで記述する必要がある場合は、別のUserActionモナドが必要になります。ただし、同じインターフェイスを表示することはできます。

このアプローチでは、モナド変換子などの中間的な Haskell 概念を使用します。IRC to irc.freenode.net #haskellchannel にアクセスして、この実装スケッチの詳細を記入するためのガイダンスを求めることをお勧めします。彼らは親切な人たちで、あなたが学ぶのを喜んで助けてくれます :-)。

[1] 実際には、パフォーマンスのために使用するの[LogEntry]ではなく、使用したいと思うでしょう。しかし、変更は簡単です。Haskell に慣れるまでは を使用し、それから に切り替えることをDList LogEntryお勧めします。[LogEntry]DList

[2] 乱数の生成は純粋に行うことができますが、このスケッチにはすでに多くの脳の再配線が必要なので、それをIO効果として扱うことをお勧めします。

于 2013-01-07T18:37:19.677 に答える