ill*_*out 1 python haskell coding-style control-structure pattern-matching
我正在尝试编写一个程序,它在命令行中使用两个整数并对它们执行一些有趣的操作.我想尽可能容易和必要地编写整数的读/解,因为它应该是相对简单的代码.
我面临的问题是,在Haskell中处理错误并不是那么简单.似乎在Haskell中经常使用模式匹配.这似乎使得代码比命令式版本更难以遵循.
该程序将像这样运行(在这个例子中,它只是将两个数字加在一起):
$ ./my_prog
ERROR: Must run like `./my_prog NUM_A NUM_B`.
$ ./my_prog cat 1
ERROR: Could not parse NUM_A "cat" as integer
$ ./my_prog 10 dog
ERROR: Could not parse NUM_B "dog" as integer
$ ./my_prog 10 1
11
Run Code Online (Sandbox Code Playgroud)
这是我想要在命令式伪Python中做的事情:
function die (errorMessage):
print("ERROR: %s" % errorMessage)
sys.exit(1)
function main ():
if len(sys.argv) != 2:
die("Must run program like `%s NUM_A NUM_B`" % sys.progname)
num_a = 0
num_b = 0
try:
num_a = int(sys.argv[0])
except:
die("Could not parse NUM_A \"%s\" as integer" % sys.argv[0])
try:
num_b = int(sys.argv[1])
except:
die("Could not parse NUM_B \"%s\" as integer" % sys.argv[1])
doSomethingInteresting(num_a, num_b)
function doSomethingInteresting (num_a, num_b):
print(num_a + num_b)
Run Code Online (Sandbox Code Playgroud)
在python中,你基本上可以从上到下阅读main函数,所有的错误处理都很简单. 有没有办法在Haskell中实现这种简单,直接的错误处理而不进行多种模式匹配?
这是我提出的Haskell代码执行相同的任务,但由于多个模式匹配部分,它似乎比Python代码复杂得多.
module Main ( main
)
where
import System.Environment (getArgs, getProgName)
import System.Exit (ExitCode(..), exitWith)
import Text.Read (readMaybe)
die :: String -> IO a
die err = do putStrLn $ "ERROR: " ++ err
exitWith (ExitFailure 1)
main :: IO ()
main = do
args <- getArgs
progName <- getProgName
case args of
[strNumA, strNumB] -> do
let maybeNumA = readMaybe strNumA :: Maybe Int
maybeNumB = readMaybe strNumB :: Maybe Int
checkMaybeArgs strNumA maybeNumA strNumB maybeNumB
_ -> die ("Must run like `" ++ progName ++ " NUM_A NUM_B`.")
where
checkMaybeArgs :: String -> Maybe Int -> String -> Maybe Int -> IO ()
checkMaybeArgs badStrNumA Nothing _ _ =
die ("Could not parse NUM_A \"" ++ badStrNumA ++ "\" as integer")
checkMaybeArgs _ _ badStrNumB Nothing =
die ("Could not parse NUM_B \"" ++ badStrNumB ++ "\" as integer")
checkMaybeArgs _ (Just numA) _ (Just numB) = doSomethingInteresting numA numB
doSomethingInteresting :: Int -> Int -> IO ()
doSomethingInteresting numA numB = print $ numA + numB
Run Code Online (Sandbox Code Playgroud)
(如果我的Haskell风格还有其他问题,我将非常感谢任何更正.)
编辑:我最近发现了一篇博客文章,讨论了在Haskell中处理异常的许多不同方法.它有点相关:
http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors
这是我写这个的方式(不使用任何外部库)
import Text.Read
import Text.Printf
import System.Environment
import Control.Monad
import System.Exit
parsingFailure :: String -> String -> IO a
parsingFailure name val = printf "ERROR: Couldn't parse %s : %s as an integer\n"
name val >> exitWith (ExitFailure 1)
validateArgs :: [String] -> IO (Integer, Integer)
validateArgs [a, b] = liftM2 (,) (parse "VAL A" a) (parse "VAL B" b)
where parse name s = maybe (parsingFailure name s) return $ readMaybe s
validateArgs _ = putStrLn "Wrong number of args" >> exitWith (ExitFailure 1)
main :: IO ()
main = do
(a, b) <- getArgs >>= validateArgs
print $ a + b
Run Code Online (Sandbox Code Playgroud)
当然有趣的是validateArgs.首先我们进行单一模式匹配,但从那时起我们只使用maybe组合器来很好地抽象出模式匹配.这导致了更清晰的代码IMO.该maybe组合子取默认值 b和延续a -> b,并解开Maybe a来b.在这种情况下,我们的默认值是解析失败,我们继续注入a到IO单子.