7

特定の値の存続期間中、特定の計算を GHC に強制的にサンクさせる方法はありますか?

もちろん、値をレコードに配置して、計算の結果に対して遅延レコード エントリを作成し、レコードを作成して値をエントリにサンクするメーカー関数を作成することもできます。

とはいえ、必要になるたびにレコードから元の値を引き出す必要はありません。また、Haskell には、C++ や Java のようなアドホックなポリモーフィック is-a 関係はありません。

同じパラメータを持つ関数の複数の無関係な呼び出しにわたって値を記憶するためのトリックはありますか?

複数の使用法が来ることを効果的にコンパイラーに伝える、依存型の形式を使用したさまざまなトリックを漠然と想像することができました。Haskell には依存型はありませんが、暗黙のパラメーターの周りに何かありますか? ないと思いますが、聞いてみようと思いました。おそらくプラグマ?


Necklace共通の分母と分子のベクトルとして格納された有理数の結果のベクトルが必要なデータ構造のベクトルがあると想像してください。

{-# LANGUAGE ImplicitParams #-}
import qualified Data.Vector as V

data Necklace = Necklace { ... }
necklace_length n = ...

denominator :: (necklaces :: V.Vector Necklace) => Int
denominator = V.foldl' lcm 30 $ V.map necklace_length ?necklaces

numerators :: (necklaces :: V.Vector Necklace) => V.Vector Int
numerators = V.map f ?necklaces
  where f x = ... denominator ...

kittytoy :: (necklaces :: V.Vector Necklace) => Meow -> ...
kittytoy = \meow -> ... numerators ...

アプリオリにkittytoy、それぞれ異なるパラメータで数百万回呼び出すと、GHCは同じ暗黙的なパラメータで百万回meow呼び出すコードを生成すると予想されます。numeratorsnecklaces

それにもかかわらず、呼び出す必要があるのは 1 回だけであることは明らかですnumeratorsが、初回?necklacesは割り当てられるため、GHC はこの最適化に気付く可能性があります。

テンプレート haskell を使用してサンクを明示的に渡す明示的なコード リファクタリング アプローチも必要?numerators = numeratorsですnumerators :: V.Vector Int

4

2 に答える 2

7

data-memocombinatorsによって実装されているように、おそらく純粋なメモ化を探しているでしょう。基本的に、各リーフで関数のすべての可能な値を持つ (怠惰な、おそらく無限の) ツリー構造を作成し、関連する場所の値に単純にアクセスする新しい関数を作成することによって機能します。たとえば、次のBool -> aような関数のメモライザーを作成できます。

memoBool :: (Bool -> a) -> (Bool -> a)
memoBool f =
    let fTrue = f True
        fFalse = f False
    in \b -> if b then fTrue else fFalse

この場合、「木の構造」はどちらかというと盆栽で、葉は 2 つしかありません。

data-memocombinators は、 のような便利なコンビネータを使用して、これをMemo aとして定義された型にパッケージ化します(参照: 引数 type の関数を memoise し、引数 type の関数をmemoiseできる場合は、引数 type の関数を memoise できます)。forall r. (a -> r) -> (a -> r)pair :: Memo a -> Memo b -> Memo (a, b)ab(a, b)

これは純粋で非常にエレガントで、基本的にすべての Haskell 実装によって実装される共有に依存しています (これは、レコードのアイデアを機能させるのと同じことです)。残念ながら、これもあまり高速ではないため、実際に使用するには、代わりにuglymemoMapを使用することをお勧めします。これは、舞台裏でミュータブルを使用します(ただし、外部的に純粋なインターフェースを公開します)。

于 2012-04-06T21:34:53.840 に答える
0

Philip JFanswer heretypeに記載されているように、型制約の同義語が定義されているという事実から生じる別のもっともらしいアプローチがあります。

おそらく、さまざまな派生値すべてに対して暗黙的なパラメーターを作成する型制約のシノニムを作成できます。

type Necklaces = (necklaces :: V.Vector Necklace,
                  denominator :: Int,
                  numerators :: V.Vector Int)

kittytoy :: (Necklaces) => Meow -> ...

?numerators何らかの形式の Haskell 構造のテンプレートを使用するように、最初にすべての値を割り当てます。私はそれが動作するかどうかを確認するためにそれで遊んでみます。

于 2012-04-07T12:54:24.623 に答える