私はHaskellでインタラクティブなリアルタイムのオーディオ合成を書き込もうとしていますが、時間を表すために「怠惰な数字」が切実に必要です。
私のプログラムは「信号」の概念に基づいており、これらの信号は「信号プロセッサ」によって変換されます。しかし、FaustやChucKのような他の同様のプロジェクトとは異なり、私は厳密に純粋関数で作業し、それでも時間に明示的にアクセスできるようにしたいと思います。
アイデアは、Haksellで純粋な「遅延ストリームプロセッサ」を表現することが可能であり、遅延評価により、インタラクティブでリアルタイムに機能するというものです。
たとえば、「MIDI信号」を音符を変えるイベントのストリームとして表すことができます。
type Signal = [ (Time, Notes->Notes) ]
すべて非インタラクティブモードで非常にうまく機能しますが、実際にリアルタイムで操作したい場合、大きな障害にぶつかります。ある時点で、出力信号は次の入力の時間に依存します。イベント。したがって、私の合成エンジンは実際には次のイベントまで停止します。
説明させてください。サウンドカードが出力信号のサンプルを要求すると、遅延評価者は信号プロセッサの依存関係グラフを調べ、最終的に入力(midi)信号の一部を要求します。しかし、入力信号がローカルで次のようになっているとしましょう。
input :: Signal
input = [ ..., (1, noteOn 42), (2, noteOff 42), ... ]
時間1.5で出力(オーディオ)信号を計算する必要がある場合、次のようなものが必要になります。
notesAt :: Signal -> Time -> Notes
notesAt = notesAt' noNotes where
notesAt' n ((st,sf):ss) t
| st > t = n
| otherwise = notesAt' (sf n) ss t
...そして「notesAtinput1.5」を評価すると、戻る前に「2>1.5」を計算する必要があります。ただし、イベント(2、NoteOff 42)はさらに0.5秒間発生しません。したがって、私の出力は、将来発生する入力イベントに依存しているため、停止します。
私はこの効果を「逆説的な因果関係」と呼んでいます。
私はこれをどのように処理するかをかなり前から考えていましたが、必要なのは「a>b」を怠惰に評価できる何らかの形の数値であるという結論に達しました。まあ言ってみれば:
bar :: LazyNumber
bar = 1 + bar
foo :: Bool
foo = bar > 100
...次に、「foo」をTrueと評価します。
そのためにペアノ番号を使用でき、実際に機能することに注意してください。
しかし、効率的にするために、私は自分の番号を次のように表現したいと思います。
data LazyNumber = MoreThan Double | Exactly Double
... LazyNumbersのすべての関数(例: ">")は純粋ですが、これは機能するように変更可能である必要があります...
この時点で、私はちょっと迷っています。したがって、問題は次のとおりです。インタラクティブなリアルタイムアプリケーションで時間を表すために効率的な遅延数を実装することは可能ですか?
編集
私がやっていることには、関数型リアクティブプログラミングという名前があることが指摘されています。エドワード・アムスデンによる論文「関数型リアクティブプログラミングの調査」は良い紹介です。ここに抜粋があります:
これまでのすべての信号関数の実装を含むほとんどのFRP実装は、システムが出力用にFRP式を継続的にリサンプリングする「プルベース」の実装により、イベントの非発生の継続的な再評価に屈します。Reactiveの作業(セクション3.1および4.4)は、Classic FRPのこの問題を解決することを目的としていますが、この作業を信号関数に拡張することはまだ検討されておらず、発生時間の比較の簡単な操作は、プログラマーがチェックし、間違いなく困難であることに依存しています。参照透過性を維持するためにアイデンティティを証明します。
これが問題の核心であるように思われます。私の「ダミーイベント」アプローチとDarkOtterの提案は、「イベントの非発生の継続的な再評価」カテゴリに分類されます。
ナイーブなプログラマーなので、「怠惰な数字を使って、foo/barの例を機能させましょう」と言います。/meは手を振る。その間、YampaSynthを見ていきます。
また、私がやろうとしているように、線形時間に関して数値を「怠惰」にすることは、精度に関して(実)数値を「怠惰」にすることと密接に関連しているように思われます(Exact Real Arithmeticを参照)。つまり、「参照透過性を維持する」ために満たすべき特定の法則を前提として、厳密に純粋なコンテキストからの可変オブジェクト(イベント時間の下限と実数の間隔)を使用したいと考えています。もっと手を振ってごめんなさい。