しかし、このバイクを見ると、少なくとも2つの欠点があることに気付きました。すべての機能が組み込まれているため、Haskell / Erlangのサーバーのようにエンドレスコンピューティングは不可能です。
server state = server renew(state, iosystem)
server EXIT = EXIT
そのため、ベンチを折りたたみ、スタックされた仮想マシンを作成する必要がありました。 さらに、それは単なる車ではなく、Fort車です。2番目の枠を修正できます-Fortは呼び出しスタックにアクセスできます:)。サーバー関数を再帰的に再呼び出しする代わりに、パラメーターを変更するだけです。
ただし、そのような最適化を行うことができなかった次の形式の関数がまだありました。
g(xs) = f(xs) . g(k(xs))
g(EOSEQ) = INIT
ここで: f(xs)は部分的に指定された関数で、「次の状態」型を「結果」型に変換する関数を返します。短くて理解できない場合は、
f :: ('state -> ('param -> 'result))
k(xs)は、計算されたデータの次の状態を返す関数です。たとえば、
(head | tail -> tail)
または
(x -> 1 + x)
EOSEQ-シーケンス終了文字
INIT-結果の最初の近似
「。」 -合成演算子; 私の場合-
(.) :: (('a -> 'b) -> ('b -> 'c) -> ('a -> 'c))
(いまいましい、私は言葉でそれを書きたくない...ヘニー)
そのような関数の例を考えてみましょう。
fac N -> N * fac (N-1)
fac 0 -> 1
ここで
xs = N, f(N) = (N *), k(x) = x - 1, EOSEQ = 0, INIT = 1
実行の順序(一般的に最初):
g(xs) = f(xs) . f(k(xs)) . f(k^2(xs)) . ... . f(k^N(xs)) . INIT
例:
fac N = N * (N-1) * ((N-1) - 1) * ... * (N - (N - 2)) * 1
このような関数は、コンパイラーが繰り返すことができるように変換および作成されている必要があります。 したがって、関数gをgとg1のペアで置き換える方法を開発しました。
g(xs) = f(xs) . g(k(xs))
g(EOSEQ) = INIT
=>
g(xs) = g1(xs, INIT)
g1(xs, ACC) = g1(k(xs), f(xs) (ACC))
g1(EOSEQ, ACC) = ACC
ここで、ACCは結果を保存するバッテリーです。
そのような関数の計算手順:
g1 = INIT . f(xs) . f(k(xs)) . ... . f(k^N(xs))
最初に目を引くのは、INITが式の先頭に移動した
例で変換を検討してください。
summ(head|tail) = head + summ(tail)
summ([]) = 0
=>
summ(xs) = summ1(xs, 0)
summ1(head|tail, accum) = summ1(tail, head + accum)
summ1([], accum) = accum
それはうまくいくようです-リストを要約し、最後に到達して完了します。
この例はより薄くなりました。
isSort (x|y|tail) = if x >= y then isSort(y|tail) else false
isSort (x|[]) = true
ここで:
f(x|y|tail) = (value -> if x >= y then value else false)
=>
isSort(list) = isSort1(list, true)
isSort1(x|y|tail, flag) = isSort1(y|tail, if x >= y then flag else false)
isSort1(x|[], flag) = flag
-- :
-- isSort1(_, false) = false
問題は、最初の要素に到達すると、元の関数が停止し、結果の関数が踏みにじるということです。彼女は、スタックの最上部の「フラグ」の値を気にしませんでした。
追加のパラメーター、つまり計算可能アキュムレーターを導入するというアイデアがありました。 しかし、その後、最初にもう1つの例を確認します。
attach(pstart、pfin、head | tail)= [pstart | 頭| pfin] | 接続(pstart、pfin、tail)
attach(pstart、pfin、[])= []
attach( "Dorough、"、 "!"、["World"] | ["Wall"] | ["green devil"])= ["Dow、Peace!"] | [「ドロウ、壁!」] | [「ダロー、緑の悪魔!」]。
=>
attach(pstart、pfin、head | tail)= attach1(pstart、pfin、head | tail、[])
attach1(pstart、pfin、head | tail、[])= attach1(pstart、pfin、tail、[pstart | head | pfin] | ACC)
attach(pstart、pfin、[]、ACC)= ACC
attach( "Hello、"、 "!"、["World"] | ["Wall"] | ["green devil"])= ["Dowr、green devil!"] ["Dorow、Wall!"] ["ドーロー、平和!」]。
ご覧のとおり、これは元の関数が返し
これが私のマナの終わりなので、要約します。
オプション1:正式なメタ処理変換を複雑にします。
オプション2:バッテリーの再帰関数をすぐに記述します。
正直に言うと、私は2番目の選択肢です。脳を発達させるからです-(アクションの明確な説明がない場合)アルゴリズムの実装方法を考える必要があります。
コメントや提案を聞いてうれしいですが、今のところは青いボトルから飲みます。