2015-12-08 43 views
2

我對Haskell還是比較新的,所以請原諒我,如果這是完全明顯的,我只是不能正確理解。Haskell的System.Console.GetOpt ReqArg如何將一個二元函數作爲構造函數的第一個參數?

對於Hackage the documentationSystem.Console.GetOpt ReqArg採用arity 1的函數,例如(String -> a)作爲其構造函數的第一個參數。

ReqArg (String -> a) String 

在許多例子中,我看到一個2 arity函數被傳遞給這個構造函數。從(https://wiki.haskell.org/High-level_option_handling_with_GetOpt

例子:

data Options = Options { optVerbose :: Bool 
         , optInput  :: IO String 
         , optOutput  :: String -> IO() 
         } 

startOptions :: Options 
startOptions = Options { optVerbose = False 
         , optInput  = getContents 
         , optOutput  = putStr 
         } 

options :: [ OptDescr (Options -> IO Options) ] 
options = 
    [ Option "i" ["input"] 
     (ReqArg 
      (\arg opt -> return opt { optInput = readFile arg }) 
      "FILE") 
     "Input file" 

    , Option "o" ["output"] 
     (ReqArg 
      (\arg opt -> return opt { optOutput = writeFile arg }) 
      "FILE") 
     "Output file" 

    , Option "s" ["string"] 
     (ReqArg 
      (\arg opt -> return opt { optInput = return arg }) 
      "FILE") 
     "Input string" 

    , Option "v" ["verbose"] 
     (NoArg 
      (\opt -> return opt { optVerbose = True })) 
     "Enable verbose messages" 

    , Option "V" ["version"] 
     (NoArg 
      (\_ -> do 
       hPutStrLn stderr "Version 0.01" 
       exitWith ExitSuccess)) 
     "Print version" 

    , Option "h" ["help"] 
     (NoArg 
      (\_ -> do 
       prg <- getProgName 
       hPutStrLn stderr (usageInfo prg options) 
       exitWith ExitSuccess)) 
     "Show help" 
    ] 

所以我的問題是這樣做值構造沒有真正執行類型時的函數它的參數是用來或者有別的我失蹤?

更新:

這是使我更有意義認識。我相信我忽略了一些因素。首先,正如@CommuSoft所提到的那樣,由於咖啡的緣故,所有功能在Haskell中確實是單一的。其次,我沒有仔細看不夠的選項是不是功能,而是一個變量,它的類型是:

[ OptDescr (Options -> IO Options) ] 

這類型的選項簽名聲明什麼ReqArg的類型變量的類型以及其他類型的構造函數NoArg和OptArg(後者在示例中未被使用)。

傳遞給NoArg ArgDescr構造單元數匿名函數將基本上只是:

(Options -> IO Options) 

例如,它將接收選項實例記錄

凡爲傳遞給ReqArg 2元數匿名函數構造將是:

(String -> Options -> IO Options) 

它將接受一個字符串(值有人在命令行中輸入)和插件選項tance記錄。

感謝所有幫助我認識到這一點!

回答

4

您在類型簽名中看到的->實際上也是一種類型。因此,類型變量a可以是一個函數b -> c。在你的例子中,它是Options -> IO Options

3

ReqArg不是一個函數:它是一個構造函數。現在構造函數顯然也是函數。的ReqArg簽名是:

ReqArg :: (String -> a) -> String -> ArgDescr a 

所以你構造函數返回一個ArgDescr a

現在你已經發現的第二個方面是,a在這種情況下相當於a = Options -> IO Options,這樣就意味着你ReqArg構造方法的簽名合攏爲:

ReqArg :: (String -> (Options -> IO Options)) -> String -> ArgDescr (Options -> IO Options) 

或者少一點:

ReqArg :: (String -> Options -> IO Options) -> String -> ArgDescr (Options -> IO Options) 

(括號刪除)

所以這是一個函數「arity「2(注意,嚴格來說,在函數式編程中,每個函數都有(至少在概念上)arity 1)。重點是你從第一個參數中產生一個新的函數。但Haskells語法糖一次允許「定義兩個參數」。

解釋文檔

這就是爲什麼在文檔例子,你需要使用foldr的原因:

return (foldl (flip id) defaultOptions o, n) 

注意,這並不地圖上的(Options -> IO Options),在例如,一個採用Options -> Options

問題是,在文檔中,Haskell單獨處理每個命令選項。最初,您從defaultOptions開始,並且在n之外處理選項o會產生一個新的Option,您將其用作處理下一個的輸入。在完成元素鏈之後,您將返回最終的Options數據。

對於你的程序

你做的事情有點困難,使用IO單子:這也許是更好地存儲一個布爾值,你是否有打印的版本,如果是這樣的話,在main做到這一點, 或者別的地方。儘管如此,您可以使用foldlM而不是foldl來達到同樣的效果。

相關問題