2012-04-28 79 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

是否讓相同類型類型的兩個實現實例成爲選項? – 2012-04-28 12:06:09

+0

@GregBacon那麼,monad棧的兩個副本肯定是一個選項,但如果有一些不涉及複製的東西,我會使用它。 – 2012-04-28 12:17:37

+0

在兩個模塊上運行haddock並比較生成的文檔? – 2012-04-28 13:34:19

回答

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沒有一流的模塊,所以你總是需要解決模塊系統的限制。好處是您只需編寫一次Base和Client模塊,並且您可以開始定義在MyModule值上運行的組合器。例如。

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

將允許您通過addTracing doNothing更換DryRun模塊實現,如果我沒有記錯。