为什么可以';我不能将Haskell中的查找结果与Nothing进行比较吗?

为什么可以';我不能将Haskell中的查找结果与Nothing进行比较吗?,haskell,Haskell,我有以下代码: import System.Environment import System.Directory import System.IO import Data.List dispatch :: [(String, [String] -> IO ())] dispatch = [ ("add", add) , ("view", view) , ("remove", remove) , ("bump",

我有以下代码:

import System.Environment
import System.Directory
import System.IO
import Data.List

dispatch :: [(String, [String] -> IO ())]
dispatch =  [ ("add", add)
            , ("view", view)
            , ("remove", remove)
            , ("bump", bump)
            ]

main = do
    (command:args) <- getArgs
    let result = lookup command dispatch
    if result == Nothing then
        errorExit
    else do
        let (Just action) = result
        action args

errorExit :: IO ()
errorExit = do
    putStrLn "Incorrect command"

add :: [String] -> IO ()
add [fileName, todoItem] = appendFile fileName (todoItem ++ "\n")

view :: [String] -> IO ()
view [fileName] = do
    contents <- readFile fileName
    let todoTasks = lines contents
        numberedTasks = zipWith (\n line -> show n ++ " - " ++ line) [0..] todoTasks
    putStr $ unlines numberedTasks

remove :: [String] -> IO ()
remove [fileName, numberString] = do
    handle <- openFile fileName ReadMode
    (tempName, tempHandle) <- openTempFile "." "temp"
    contents <- hGetContents handle
    let number = read numberString
        todoTasks = lines contents
        newTodoItems = delete (todoTasks !! number) todoTasks
    hPutStr tempHandle $ unlines newTodoItems
    hClose handle
    hClose tempHandle
    removeFile fileName
    renameFile tempName fileName

bump :: [String] -> IO ()
bump [fileName, numberString] = do
    handle <- openFile fileName ReadMode
    (tempName, tempHandle) <- openTempFile "." "temp"
    contents <- hGetContents handle
    let number = read numberString
        todoTasks = lines contents
        bumpedItem = todoTasks !! number
        newTodoItems = [bumpedItem] ++ delete bumpedItem todoTasks
    hPutStr tempHandle $ unlines newTodoItems
    hClose handle
    hClose tempHandle
    removeFile fileName
    renameFile tempName fileName
导入系统环境
导入系统目录
导入系统.IO
导入数据。列表
分派::[(字符串,[字符串]->IO())]
分派=[(“添加”,添加)
,(“视图”,视图)
,(“移除”,移除)
,(“凹凸”,凹凸)
]
main=do
(命令:args)IO()
添加[fileName,todoItem]=追加文件名(todoItem++“\n”)
视图::[String]->IO()
查看[文件名]=do
内容显示n++“-“++”行)[0..]到任务
putStr$unlines numberedTasks
删除::[String]->IO()
删除[fileName,numberString]=do

处理如果
a
有一个实例,那么
类型可能有一个
Eq
实例-这就是为什么(Eq([[Char]]->IO())
(一个函数不能与另一个函数相比)没有实例的原因

也许这就是你要找的。目前我无法测试,但应该是这样的:

maybe errorExit (\action -> action args) result
也就是说,如果
result
Nothing
,则返回
errorExit
,但如果
result
Just action
,则在
action

上应用lambda函数,运算符的类型为
Eq a=>a->a->Bool
。这意味着,如果对象的类型是
Eq
的实例,则只能比较对象是否相等。函数在相等性方面是不可比较的:您如何编写
(==)::(a->b)->(a->b)->Bool
?这是没有办法的。1虽然显然
Nothing==Nothing
Just x/=Nothing
,但情况是
Just x==Just y
当且仅当
x==y
;因此,除非您可以为
a
编写
(==)
,否则无法为
编写
(==)

这里最好的解决方案是使用模式匹配。一般来说,我不会在Haskell代码中使用那么多
if
语句。你可以改为写:

main = do (command:args) <- getArgs
          case lookup command dispatch of
            Just action -> action args
            Nothing     -> errorExit
main=do(命令:args)操作args
无->错误退出
出于几个原因,这是一个更好的代码。首先,它比较短,这总是很好的。第二,虽然您不能在这里使用
(==)
,但假设
dispatch
保留了列表。
case
语句保持同样的效率(恒定时间),但是比较
just x
just y
变得非常昂贵。第二,您不必使用
let(Just action)=result
重新绑定
result
;这使得代码更短,并且不会引入潜在的模式匹配失败(这很糟糕,尽管您知道它不会在这里失败)



1::事实上,在保持引用透明度的同时编写
(==)
是不可能的。在Haskell中,
f=(\x->x+x)::Integer->Integer
g=(*2)::Integer->Integer
应该被认为是相等的,因为
fx=gx
对于所有
x::Integer
;然而,用这种方法证明两个函数相等通常是不可判定的(因为它需要枚举无限多个输入)。你不能只说
\x->x+x
只等于语法上相同的函数,因为这样你就可以区分
f
g
,即使它们做的事情相同。

如果你不想重新构造你的代码,你也应该能够用
isNothing result
@JeffreyBurka替换
result==Nothing
,这在我看来是一个单独的答案。获得你应得的声誉:)哈哈,我将把它作为一个评论,因为从技术上讲,问题是“为什么
==
不起作用”,而不是“我如何才能让它起作用”<代码>也许是一种更酷的方式。请注意,
(\action->action args)
也可以写成
($args)
。也许值得补充的是,尽管你不能实现
(==)::也许a->也许a->Bool
,你可以实现
(==Nothing)::也许a->Bool
;此函数的名称为。
main = do (command:args) <- getArgs
          case lookup command dispatch of
            Just action -> action args
            Nothing     -> errorExit