1

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

各関数は、実行時までわからないいくつかの引数を取ります。それらがリストにバインドされるのを見て、それらを関数に渡すにはどうすればよいですか? 手動で取得するだけですか?お気に入り:

exampleFunction (args !! 1) (args !! 2) 

それはちょっと醜いようです。これを行うための慣用的な方法はありますか?エラーチェックについてはどうですか?私の関数は、渡されたパラメーターをばかげた順序で取得するなどのエラーを適切に処理する機能を備えていません。

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

4

1 に答える 1

7

1 つの方法は、さらにコマンド ライン処理を行う関数内に関数をラップすることです。例えば

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

Intラッパー関数のバリアントでエラー チェックを実行し、(一部の) 引数を必要に応じてs / カスタム データ型 / などに変換することで、これを拡張できます。

dbaupp が指摘しているように、getArgs上記のパターン マッチの方法は安全ではありません。より良い方法は

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

main = run =<< getArgs
于 2012-04-04T08:13:13.523 に答える