为什么可以';我不能将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