2012-06-12 60 views
5

我有一個模塊其中通過調用初始化函數創建並初始化全局環境(定義某些約束,如鄰居IP地址等)。一些後續函數在調用時應該使用這些約束。全局變量和閱讀器monad

雖然原則上我明白讀者monad的作用,但我不太清楚如何將其應用於我的問題,尤其是我的問題。

  • 它如何用來初始化由用戶定義的環境,並將其作爲數據/參數傳遞給初始化函數。我的意思是,讀者monad必須從某個地方獲得組成全球不變環境的實際值。我想,該值是從初始化函數調用,比如myinitial :: arg1 -> arg1 -> IOString哪裏隨後arg1arg2成爲全球通過讀者單子讀給後續函數訪問變量數據(?)

  • 如何使用這些環境的值作爲函數的參數例如recvFrom s arg1其中arg1是來自我的環境的全球不可變數據。或if arg2 > arg1 then ... else ...

我可以做當然是一個配置文件,但我覺得一個配置文件會帶走得多的靈活性。

[編輯]我瞭解問題,但不應該有額外的「無點狀」方式,以便全局/環境不可變可以省略,如果函數簽名已被定義正確嗎?我將如何重構我的if-then-else以應用this

回答

4

下面是一個可以清理事情的例子。首先,你需要導入的讀取器模塊:

import Control.Monad.Reader 

現在讓我們來定義一些數據結構(即我們將用它來保持一個名字和年齡)

data Config = Config { name :: String, age :: Int } 

現在定義一個函數在Reader monad中工作(類型爲Reader Config (String, Int),但我們不需要指定 - 可以推斷)。所有這些功能都是要求環境(類型Config),然後提取這些字段並對它們進行處理。

example = do 
    c <- ask 
    return ("Hello " ++ name c, 2 * age c) 

現在我們把它放到一個程序中。 do塊之後的前四行允許用戶輸入他們的名字和年齡。然後,我們建立了一個Config結構中使用用戶的輸入(我們必須使用read給變量_age,這是一個String,轉換成Int這樣我們就可以將其提供給了Config構造)以及與此環境中執行example,使用runReader功能。最後,我們使用這個計算的結果來產生一些輸出。

main = do 
    putStrLn "Enter your name:" 
    _name <- getLine 
    putStrLn "Enter your age:" 
    _age <- getLine 
    let config = Config _name (read _age) 
    let result = runReader example config 
    putStrLn $ fst result 
    putStrLn $ "Twice your age is: " ++ show (snd result) 
+0

部分工作,如問題中提到的我有一個**模塊**,它具有許多功能;其中有一個創建環境的初始化函數。來自稍後調用的模塊的函數應該使用該環境。這對讀者monad來說可能嗎? –

+0

但是這個工作應該如何?在你的/我的例子中,初始化函數會說'let config = Config blabla',後續函數需要'let result = runReader example config'; - 但是後面的函數不知道'config'。 –

+0

查看[這個要點](https://gist.github.com/2924160),其中包含一個簡單的例子。在模塊1中,我們定義了一個初始化全局環境的函數和一些依賴於全局環境的函數。模塊2只包含一個初始化環境的主函數,並使用'runReader'調用依賴它的函數(**編輯:**道歉,我刪除了您回覆的原始註釋並用此代替它。) –

5

您可以通過檢查askrunReader函數的類型和文檔來回答大部分問題。

首先,ask

ask :: Reader m r => m r 

這將返回包裹在單子底層只讀數據。酷,所以這是你將如何到達狀態,當你想與其他功能使用它,在你上面的例子:

do x <- ask 
    recvFrom s x 

(取決於recvFrom類型,當然)

其次是runReader,這就是你如何給它提供你正在談論的初始數據。它基本上只運行使用它提供的數據計算Reader

runReader :: Reader r a -> r -> a 

這意味着:運行計算(第一個參數)與r類型的只讀數據(第二個參數)。它最終會返回第一個參數的結果類型,a。在你的情況,這可能是這樣的:

result = runReader computationUsingArg1Arg2 (arg1, arg2) 

內。然後computationUsingArg1Arg2你可以通過閱讀askarg1arg2

+0

謝謝,我仍然不明白如何將'runReader'應用於我的示例項目符號我的問題之一。 –

+0

我已經擴大了答案,讓我知道是否仍有不清楚的地方。 – ScottWest

+0

我知道這是一年後,但對我來說,這並沒有回答這個問題。問題不僅在於存在compuationUsingArg1Arg2,而且計算使用了Arg1Arg2可能希望能夠調用其他也需要訪問「全局」信息的函數。否則,您可以直接傳遞參數而不需要讀者。那麼如何定義和調用所有這些其他函數呢? – David