2012-04-28 11 views
3

私は、ユーザーにimport DryRunを最初に実行させ、次にすべてが正しいと思うならimport Doとプログラムを実行できるようにしたいと考えています。
だから、実際の作業を行うモジュールがあります:いくつかのモジュールの共通インターフェイス

doThis ∷ SomeStack() 
doThis = actuallyDoThis 
... 
doThat ∷ SomeStack() 
doThat = actuallyDoThat 

と内気なユーザーのためのモジュール:

doThis ∷ SomeStack() 
doThis = liftIO $ putStrLn "DoThis" 
... 
doThat ∷ SomeStack() 
doThat = liftIO $ puStrlLn "DoThat" 

問題は、私はDoDryRun内のインタフェースは、(同じであることを確認することはできませんですコンパイラは助けができません)、この混乱は開発中に維持するのが難しいです。
この種の問題を解決する共通のイディオムはありますか?

+5

同じtypeclassの2つの実装インスタンスにオプションを設定していますか? –

+0

@GregBaconまあ、モナドスタックの2つのコピーは確かにオプションですが、コピーが含まれていない何かがあればそれを使用します。 –

+0

両方のモジュールでhaddockを実行し、結果のドキュメントを比較しますか? –

答えて

2

問題のモジュールを確認できます。

module Base where 
data MyModule = MyModule { 
    doThis_ :: SomeStack(), 
    doThat_ :: SomeStack() 
} 

あなたは(アンダースコアがすぐに明らかになるであろう理由)をエクスポートするために、各モジュールを必要とするもので:それは、ベースモジュールにデータ型を定義し、あります。

例えば、このタイプの値を定義するとあなたは、各モジュールにできます

module DryRun(moduleImpl) where 
import Base 
moduleImpl :: MyModule 
moduleImpl = MyModule doThis doThat 
-- doThis and doThat defined as above, with liftIO . putStrLn 

module Do(moduleImpl) where 
import Base 
moduleImpl :: MyModule 
moduleImpl = MyModule doThis doThat 
-- doThis and doThat defined as above, where the real work gets done 

私は確信してMyModule変更する場合は、型チェッカーがすることを確認するために、レコードの構文を使用してMyModule値を構築しません。ほとんどの場合、不平を言い始めます。クライアントモジュールで

あなたは今、あなたは同じ操作は両方のモジュールによってエクスポートされていることを知っている

module Client where 
import DryRun 
-- import Do -- uncomment as needed 

doThis = doThis_ moduleImpl 
doThat = doThat_ moduleImpl 

-- do whatever you want here 

を行うことができます。これは退屈で厄介ですが、Haskellにはファーストクラスのモジュールがないので、モジュールシステムの限界を常に克服する必要があります。良いことは、ベースモジュールとクライアントモジュールを一度書かなければならず、MyModule値で動作するコンビネータの定義を開始できることです。例えば。

doNothing = MyModule (return()) (return()) 
addTracing impl = MyModule ((liftIO $ putStrLn "DoThis") >> doThis_ impl) 
          ((liftIO $ putStrLn "DoThat") >> doThat_ impl) 

は、私が間違っていない場合は、addTracing doNothingによってDryRunモジュールの実装を置き換えることができます。

関連する問題