2012-04-04 22 views
1

私はHaskellで少しコマンドラインプログラムを書いています。コマンドライン引数に基づいて正しい暗号化機能にディスパッチする必要があります。私はこれまでのことを理解しましたが、残りの引数をパラメータとして関数に渡す必要があります。私が読んだ:Haskellでコマンドライン引数を使って関数を修正するためのディスパッチ

ここまで私を得て

http://learnyouahaskell.com/input-and-output

を:

import qualified CaesarCiphers 
import qualified ExptCiphers 

dispatch::[(String, String->IO())] 
dispatch = [("EEncipher", ExptCiphers.exptEncipherString) 
      ("EDecipher", ExptCiphers.exptDecipherString) 
      ("CEncipher", CaesarCiphers.caesarEncipherString) 
      ("CDecipher", CaesarCiphers.caesarDecipherString) 
      ("CBruteForce", CaesarCiphers.bruteForceCaesar)] 

main = do 
    (command:args) <- getArgs 

の各関数は、私がそれまでは、実行時間を知ることができませんいくつかの引数を取ります。彼らはリストに束縛されるので、それらを関数に渡すにはどうすればよいですか?私はそれらを手動でつかむだけですか? Like:

​​

これは醜いようです。これを行う慣用的な方法がありますか?エラーチェックはどうですか?私の関数は、パラメータを愚かな順序で渡すようなエラーを正常に処理する機能を備えていません。

また、重要なことに、ディスパッチの各関数は異なる数の引数を取るため、このように静的に行うことはできません(上のように)。unCurry command argsは有効ではありません。

+1

で、この問題に対する興味深いソリューションを持っています。あなた自身の解決策を見つけることを妨げることはありません。 – ephemient

答えて

7

さらに、コマンドライン処理を行う関数の中に関数をラップする方法もあります。例えば必要に応じてInt S /カスタムデータ型の/ etcにその引数(の一部)を変換

dispatch::[(String, [String]->IO())] 
dispatch = [("EEncipher", takesSingleArg ExptCiphers.exptEncipherString) 
      ("EDecipher", takesSingleArg ExptCiphers.exptDecipherString) 
      ("CEncipher", takesTwoArgs CaesarCiphers.caesarEncipherString) 
      ("CDecipher", takesTwoArgs CaesarCiphers.caesarDecipherString) 
      ("CBruteForce", takesSingleArg CaesarCiphers.bruteForceCaesar)] 

-- a couple of wrapper functions: 

takesSingleArg :: (String -> IO()) -> [String] -> IO() 
takesSingleArg act [arg] = act arg 
takesSingleArg _ _  = showUsageMessage 

takesTwoArgs :: (String -> String -> IO()) -> [String] -> IO() 
takesTwoArgs act [arg1, arg2] = act arg1 arg2 
takesTwoArgs _ _   = showUsageMessage 

-- put it all together 

main = do 
    (command:args) <- getArgs 
    case lookup command dispatch of 
     Just act -> act args 
     Nothing -> showUsageMessage 

あなたはラッパー関数のバリアントを持っていることによって、これを拡張することができますが、エラーチェックを行います。

dbauppはメモのとおり、上記のgetArgsで一致するパターンは安全ではありません。より良い方法は、[CmdLib](http://hackage.haskell.org/package/cmdlib)

run :: [String] -> IO() 
run [] = showUsageMessage 
run (command : args) 
    = case lookup command dispatch of 
      Just act -> act args 
      Nothing -> showUsageMessage 

main = run =<< getArgs 
+2

'getArgs'のパターンマッチを避けるべきでしょう。引数がなければ、失敗したマッチはuncatchable例外を生成します。ディスパッチする前に 'getArgs'の出力全体をキャプチャし、' null'を使ってテストする方が良いでしょう。 – huon

+1

あなたのラッパー関数では、引数の順序が間違っているようです。署名は正しいですが、定義では文字列リストが最初に必要です。 –

+0

ありがとう@FrerichRaabe ---修正されました。 – dave4420

関連する問題