我有以下代码:
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
尝试编译它会出现以下错误:
$ ghc --make todo
[1 of 1] Compiling Main ( todo.hs, todo.o )
todo.hs:16:15:
No instance for (Eq ([[Char]] -> IO ()))
arising from a use of `=='
Possible fix:
add an instance declaration for (Eq ([[Char]] -> IO ()))
In the expression: result == Nothing
In a stmt of a 'do' block:
if result == Nothing then
errorExit
else
do { let (Just action) = ...;
action args }
In the expression:
do { (command : args) <- getArgs;
let result = lookup command dispatch;
if result == Nothing then
errorExit
else
do { let ...;
.... } }
我不明白为什么会这样,因为 lookup
返回 Maybe a
,我肯定可以将其与 Nothing
进行比较。
最佳答案
(==)
的类型运算符是 Eq a => a -> a -> Bool
。这意味着,只有当对象属于 Eq
实例的类型时,您才能比较对象是否相等。 。并且函数在平等方面是不可比较的:你会怎么写 (==) :: (a -> b) -> (a -> b) -> Bool
?没有办法做到这一点。1 虽然很明显 Nothing == Nothing
和Just x /= Nothing
,情况就是Just x == Just y
当且仅当x == y
;因此,无法写 (==)
对于 Maybe a
除非你可以写(==)
对于 a
.
这里最好的解决方案是使用模式匹配。一般来说,我发现自己没有使用那么多 if
我的 Haskell 代码中的语句。您可以改为编写:
main = do (command:args) <- getArgs
case lookup command dispatch of
Just action -> action args
Nothing -> errorExit
出于几个原因,这是更好的代码。首先,它更短,这总是好的。其次,虽然您根本不能使用 (==)
在这里,假设dispatch
相反,持有 list 。 case
语句仍然有效(恒定时间),但比较 Just x
和Just y
变得非常昂贵。其次,您不必重新绑定(bind)result
与 let (Just action) = result
;这使得代码更短,并且不会引入潜在的模式匹配失败(这很糟糕,尽管您知道它不会在这里失败)。
1::事实上,不可能写(==)
同时保持引用透明度。在 haskell ,f = (\x -> x + x) :: Integer -> Integer
和g = (* 2) :: Integer -> Integer
应该被认为是相等的,因为 f x = g x
对于所有人x :: Integer
;然而,以这种方式证明两个函数相等通常是不可判定的(因为它需要枚举无限数量的输入)。你不能只是说\x -> x + x
只等于语法相同的函数,因为这样你就可以区分 f
和g
即使他们做同样的事情。
关于haskell - 为什么我不能将查找结果与 Haskell 中的 Nothing 进行比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11745799/