2011-08-26 9 views
6

私はHaskellでは、以下の機能を持っている:私は一度だけマップを生成するmemdbが好きで、代わりのmapの反復ごとになりハスケルで値をメモする方法はありますか?

map (\x -> memdb ! x) values 

memdb = -- load the contents of a database into memory as a Map 

をそして、私は次の行を持っています。

make_memdb = -- equivalent to memdb in previous example 
memdb <- make_memdb 
map (\x -> memdb ! x) values 

しかし、これは、私はそれを使用するすべての関数にmemdbに合格する必要があることを意味します:私はこのようなものを使用してそれを行うことができます。私ができる方法はありますか:

a。 memdbを呼び出すたびに再計算しないでください。

b。 make_memdbで生成された値を定数として保存して、それを使用するすべての関数に渡すのを避けることができますか?

+0

[どのようにジェネリックmemoize機能を作るのですが重複する可能性ハスケル?](http://stackoverflow.com/questions/141650/how-do-you-make-a-generic-memoize-function-in-haskell) –

+0

@Craig Stuntz:私はその質問を読んだ私の記事を投稿する前に。それらの答えは、私がどのように達成するのに役立ちますか?またはb。 ? –

+0

@Craig:タイトルにもかかわらず、この質問は、通常の意味でのメモ作成ではありません。それはその質問の重複ではありません。 – hammar

答えて

13

マップはデータベースから取得されるため、アプリケーションの実行間で異なる可能性があるため、定数にすることはできません。

しかし、これは、それを使用するすべての関数にmemdbを渡す必要があることを意味します。

はい、しかし、これは音よりも悪くないようにするツールがあります。特に、これはthe reader monadの完璧な使用例のようです。

リーダのモナドは、設定のように、プログラムの始めにロードして、いつも明示的に渡すことなくプログラムの周りにアクセスできるような値があるときによく使われます。ここでは、あなたがそれを使用する方法の簡単な例です:

main = do 
    memdb <- make_memdb -- Get the memdb from the database once and for all 
    runReaderT foo memdb 

foo = do 
    memdb <- ask -- Grab the memdb. Will not reload from the database 
    liftIO $ putStrLn "Hello, world" -- IO actions have to be lifted 
    -- [...] 

も参照してください:

+0

ありがとうございます! –

+0

この質問が読者のモナドに伝えるために作られたようなものです。いい答えだ。 –

1

より多くのパラメータを渡すことを回避する方法として、IOからmemdbを取得したいと思われる場合は、正しく入力してください。次に、(A)memdbを定義することができます。これは、DBからデータをロードするオーバーヘッドを伴わずにトップレベルの関数であることを意味するか、グローバルスコープでロードされたデータ構造を保存できるかどうかを示します。

どちらもトップレベルの可変グローバル変数を定義するためにIORefunsafePerformIOで実行できます。私はあなたがこれをすることをお勧めしません。それは不器用で、リファクタリングに迷惑をかける。それは言って、私はどのようにとにかくを紹介します:

は、あなたが機能を持っていると仮定すると:

make_memdb :: IO (Map K V) 

あなたはトップレベルの変更可能な変数を宣言することができます:あなたの関数がすること

import Data.Map as M 
import Data.IORef 

mRef :: IORef (Map K V) 
mRef = unsafePerformIO $ newIORef M.empty 
{-# NOINLINE mRef #-} 

main = do 
    m <- make_memdb 
    writeIORef mRef m 
    ... do stuff using mRef ... 

stuffUsingMRef ... = do 
    memdb <- readIORef 
    let vs = map (memdb !) values 
    return vs 

お知らせ永遠にIOに住んでいます。これは、memdbを配置したグローバル可変変数を読み取るためにIOが必要なためです。あなたがこれを気に入らず、パラメータを渡すのが嫌いなら、状態のモナドを学んでください!私は別の答えが正しい解決策であることを議論すると確信しています。

+0

州のモナドがどのように役立つかの例を教えてください。 –

+0

ハンマーの答えはリーダーモナドを使って見てください。これは私があなたに見せてもらったものです(モナドをモディファイしていないので、 'Reader 'も考えていたはずです)。 –

関連する問題