好吧,这是我现在的代码:
import System.IO
import System.Environment
import System.Directory
main = do
unfiltered <- getArgs ; home <- getHomeDirectory ; let db = home ++ "/.grindstone"
case unfiltered of
(x:xs) -> return ()
_ -> error "No command given. See --help for more info."
command:args <- getArgs
createDirectoryIfMissing True db
let check = case args of
[] -> error "No arguments given. See --help for more info."
_ -> do let (params@(param:_),rest) = span (\(c:_) -> c=='-') args
if length params > 1 then error ("No arguments given for " ++ param)
else do
let (pArgs,_) = span (\(c:_) -> c/='-') rest
return (param, pArgs) :: Either (IO ()) (String, [String])
let add = print "sup"
let cmds = [("add", add)]
let action = lookup command cmds
case action of
Nothing -> error "Unknown command."
(Just action) -> action
主要问题是检查。我尝试实现Either类型,因为我希望它出错,或返回一些东西供另一个函数使用,但是,它当前错误地用:
grindstone.hs:21:23:
No instance for (Monad (Either (IO ())))
arising from a use of `return' at grindstone.hs:21:23-43
Possible fix:
add an instance declaration for (Monad (Either (IO ())))
In the expression:
return (param, pArgs) :: Either (IO ()) (String, [String])
In the expression:
do { let (pArgs, _) = span (\ (c : _) -> ...) rest;
return (param, pArgs) :: Either (IO ()) (String, [String]) }
In the expression:
if length params > 1 then
error ("No arguments given for " ++ param)
else
do { let (pArgs, _) = ...;
return (param, pArgs) :: Either (IO ()) (String, [String]) }
我刚刚开始使用haskell而且还没有对monad进行太多处理,所以我想在这里问一下。有人有什么想法吗?
答案 0 :(得分:3)
导致编译问题的错误是,当表达式不是Either (IO ()) (String, [String])
值时,您直接将表达式转换为类型Either
。 (编译器没有输出非常有用的错误消息。)
要创建Either值[1],我们使用数据构造函数Left
和Right
。约定(来自库页面)是错误是Left值,而正确的值是Right值。
我快速重写你的arg检查功能
checkArgs :: [String] -> Either String (String, [String])
checkArgs args =
case args of
[] -> Left "No arguments given. See --help for more info."
_ -> let (params@(param:_),rest) = span (\(c:_) -> c=='-') args in
if length params > 1 then
Left ("No arguments given for " ++ param)
else
let (pArgs,_) = span (\(c:_) -> c/='-') rest in
Right (param, pArgs)
请注意,arg检查功能不与任何外部IO ()
库函数交互,因此具有纯函数类型。一般来说,如果你的代码没有monadic元素(IO ()
),那么用纯函数风格编写代码会更清楚。 (当我在Haskell开始时,这绝对是我推荐的东西,而不是试图立即绕过monads / monad变换器/等。)
当你对monad更加熟悉时,你可能想要查看Control.Monad.Error
[2],它可以包含与Either
类似的功能作为monad,并封装一些细节,如{{ 1}}总是计算错误。
[1] http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Either.html
[2] http://hackage.haskell.org/packages/archive/mtl/1.1.0.2/doc/html/Control-Monad-Error.html
答案 1 :(得分:1)
Either (IO ()) (String, [String])
是包含IO操作或类型的类型
(String, [String])
,因此此类型的值可以是Left IO ()
或
Right (String, [String])
。 Left
值通常表示错误
在哈斯克尔发生。此错误可以用您想要的任何类型表示,
例如,错误代码(Int
)或String
说明发生了什么。
如果您使用IO ()
作为表示错误的类型,您将无法使用
提取有关错误的任何信息。您稍后将能够执行IO操作。
您要查找的类型不是Either (IO ()) (String, [String])
,
是Either String (String, [String])
。有了这种类型就可以获得有关的信息
错误(String
)。现在,您不需要Either
类型的任何IO操作,所以你
可以删除所有do
表达式:
let check = case args of
[] -> Left "No arguments given. See --help for more info."
_ -> let (params@(param:_),rest) = span (\(c:_) -> c=='-') args
in if length params > 1
then Left ("No arguments given for " ++ param)
else let (pArgs,_) = span (\(c:_) -> c/='-') rest
in Right (param, pArgs)