関数としての関数
10638 ワード
機能的反応プログラミングは、時間tにおける以前の値に基づいて時間tにおける電流値を計算する必要がある.しかし、その前の値が機能であるならば、どうですか?それはどのように見えるかを見るために時間をアンロールしましょう.私たちの機能は
私たちが以前のタイムスタンプから値を格納することができたならば、私たちが常にそれらを再計算する必要がないように、それはよりよいでしょう.しかし、どのように我々はこれを行うことができますか?つの解決策は、関数の初期評価を強制するクロージャを使用することです.
私が最近プピュラーで使用した1つの戦略は、機能から記録への自然な転換を使用している抽象的な回帰すことです.
FizzBang
to Number
.data FizzBang = Fizz | Bang
initialValue v = case v of
Fizz -> 1.0
Bang -> 0.0
valueAt1 v = initialValue v + case v of
Fizz -> 3.0
Bang -> 1.0
valueAt2 v = valueAt1 v + 1.0
valueAt3 v = valueAt2 v + case v of
Fizz -> 0.0
Bang -> 3.0
currentValue v = valueAt3 v + 6.3
時間が経過すると、関数呼び出しスタックはかなり深くなります.currentValue
は4つの関数を呼び出す必要があります.valueAt3
, valueAt2
, valueAt1
and initialValue
現在の値を取得するには私たちが以前のタイムスタンプから値を格納することができたならば、私たちが常にそれらを再計算する必要がないように、それはよりよいでしょう.しかし、どのように我々はこれを行うことができますか?つの解決策は、関数の初期評価を強制するクロージャを使用することです.
data FizzBang = Fizz | Bang
memoize :: (FizzBang -> Number) -> (FizzBang -> Number) -> FizzBang -> Number
memoize f g = let
fizz = f Fizz
bang = f Bang
in
\v -> case v of
Fizz -> fizz + g Fizz
Bang -> bang + g Bang
initialValue v = case v of
Fizz -> 1.0
Bang -> 0.0
valueAt1 = memoize initialValue (case _ of
Fizz -> 3.0
Bang -> 1.0)
valueAt2 = memoize valueAt1 (const 1.0)
valueAt3 = memoize valueAt2 (case _ of
Fizz -> 0.0
Bang -> 3.0)
currentValue = memoize valueAt3 (const 6.3)
これは関数呼び出し問題を解決しますが、それは非常に拡張できません.我々は機能を覚えるたびに、我々はそれらのすべてを作成する必要がありますlet
ステートメントと追加のクロージャ.私が最近プピュラーで使用した1つの戦略は、機能から記録への自然な転換を使用している抽象的な回帰すことです.
data FizzBang = Fizz | Bang
newtype FizzBang' a
= FizzBang'
{ fizz :: a
, bang :: a
}
class Memoizable f g | f -> g, g -> f where
memoize :: Function f ~> g
functionize :: g ~> Function f
instance memoizableFizzBang :: Memoizable FizzBang FizzBang' where
memoize f =
FizzBang'
{ fizz: f Fizz
, bang: f Bang
}
functionize (FizzBang' { fizz }) Fizz = fizz
functionize (FizzBang' { bang }) Bang = bang
eval = functionize <<< memoize
initialValue v = case v of
Fizz -> 1.0
Bang -> 0.0
initialValue' = eval initialValue
valueAt1 v = initialValue' v + (case v of
Fizz -> 3.0
Bang -> 1.0)
valueAt1' = eval valueAt1
valueAt2 v = valueAt1' v + 1.0
valueAt2' = eval valueAt2
valueAt3 v = valueAt2' v + (case v of
Fizz -> 0.0
Bang -> 3.0)
valueAt3' = eval valueAt3
currentValue v = valueAt3' v + 6.3
これは、型クラスの使用を通して拡張可能なままである間、何かを本来の機能的な構文に近づけることの利点を持ちます.他の人も同様に役に立つと思います!Reference
この問題について(関数としての関数), 我々は、より多くの情報をここで見つけました https://dev.to/mikesol/functions-as-data-as-functions-a-quick-memoization-hack-lacテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol