Mac*_*cki 2 haskell types typeerror
在过去的几天里,我一直在努力学习Haskell.虽然我正在慢慢变好,但我发现很难用Haskell的IO来推理,可能是因为我缺乏知识.我一直在尝试编写一个简单的待办事项列表程序.这是我得到的:
tadd todo = do
td <- getLine
td:todo
tdel todo = do
trem <- getLine
let rid = read trem :: Int
[todo !! x | x <- [0..(length todo-1)], not $ x == rid]
tls todo = do
mapM putStrLn [ (show x) ++ (todo !! x) | x <- [0..(length todo -1)] ]
todo
mtodo "add" todo = tadd todo
mtodo "del" todo = tdel todo
mtodo "ls" todo = tls todo
bege = do
com <- getLine
mtodo com []
main = bege
Run Code Online (Sandbox Code Playgroud)
我除了mtodo mtodo :: [IO String] -> [IO String] -> [IO String]
和tadd,tdel,tls是:: [IO String] -> [IO String].
相反,我只是得到这个可怕的错误消息
[1 of 1] Compiling Main ( todo.hs, todo.o )
todo.hs:3:9:
Couldn't match type `[]' with `IO'
Expected type: IO String
Actual type: [String]
In a stmt of a 'do' block: td : todo
In the expression:
do { td <- getLine;
td : todo }
In an equation for `tadd':
tadd todo
= do { td <- getLine;
td : todo }
todo.hs:8:9:
Couldn't match expected type `IO' with actual type `[]'
In a stmt of a 'do' block:
[todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid]
In the expression:
do { trem <- getLine;
let rid = ...;
[todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid] }
In an equation for `tdel':
tdel todo
= do { trem <- getLine;
let rid = ...;
[todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid] }
todo.hs:12:9:
Couldn't match type `[]' with `IO'
Expected type: IO [Char]
Actual type: [[Char]]
In a stmt of a 'do' block: todo
In the expression:
do { mapM
putStrLn [(show x) ++ (todo !! x) | x <- [0 .. (length todo - 1)]];
todo }
In an equation for `tls':
tls todo
= do { mapM
putStrLn [(show x) ++ (todo !! x) | x <- [0 .. (length todo - 1)]];
todo }
Run Code Online (Sandbox Code Playgroud)
任何想法我的类型有什么问题?(另外 - 有什么我应该改变的吗?).谢谢
C. *_*ann 10
看看这段代码:
tadd todo = do
td <- getLine
td:todo
Run Code Online (Sandbox Code Playgroud)
问题是你自己有td:todo一条线; 你正在使用getLine,所以整个块应该使用IO,但你的最后一行是一个列表.这就是"无法匹配"的错误 - 代码似乎说IO并且[]应该是同一个东西,但当然它们不是.
要将值提升到monadic上下文以将其用作do块的结果值,请使用以下函数return:
tadd todo = do
td <- getLine
return $ td:todo
Run Code Online (Sandbox Code Playgroud)
这将给出tadd类型[String] -> IO [String].这不是你期望的那种类型,但是从你写的那些我不认为你想要使用它[IO String].
这同样适用于在列表理解tdel和最终todo的tls.
此外,您的预期类型是关闭的:
mtodo :: [IO String] -> [IO String] -> [IO String]
mtodo "add" todo = tadd todo
mtodo "del" todo = tdel todo
mtodo "ls" todo = tls todo
Run Code Online (Sandbox Code Playgroud)
第一个论点显然是String在这里,所以基于上面你可能想要的mtodo :: String -> [String] -> IO [String]
这可能也不是你想要的:
bege = do
com <- getLine
mtodo com []
Run Code Online (Sandbox Code Playgroud)
其他几点说明:
基于其余的代码,您似乎想要一个交互式程序,但这只会运行一次.你可能想要的是这样的:
bege todo = do
com <- getLine
todo' <- mtodo com todo
bege todo'
main = bege []
Run Code Online (Sandbox Code Playgroud)
你的列表理解[todo !! x | x <- [0..(length todo-1)], not $ x == rid]是非常低效的,根本不是惯用语.根据经验,如果你还在学习Haskell,你可能永远不会使用,(!!)除非你之后丢弃列表.Haskell列表是线性序列,因此索引需要遍历到那一点的所有内容.对于你正在做的事情来说,并不是最好的数据结构,但你至少应该找到一些不需要多次遍历列表的方法.
作为避免的一个例子(!!),你可以重写mapM putStrLn [ (show x) ++ (todo !! x) | x <- [0..(length todo -1)] ]为mapM_ putStrLn $ zipWith (\n t -> show n ++ t) [0..] todo,这避免了所有令人困惑和多余的东西,如索引和担心列表的长度,以及遍历列表只有一次,而不是先遍历它来计算长度,然后部分遍历每个项目以打印它.
这更多的是品味问题,而不是写这个:
mtodo "add" todo = tadd todo
mtodo "del" todo = tdel todo
mtodo "ls" todo = tls todo
Run Code Online (Sandbox Code Playgroud)
您可以将其缩写为:
mtodo "add" = tadd
mtodo "del" = tdel
mtodo "ls" = tls
Run Code Online (Sandbox Code Playgroud)
...这意味着完全相同的事情,并且可以通过减少过多的噪音并且明显地表明所有它正在做的是根据给定的字符串选择其他几个函数中的一个来说更清楚.
此外,这个let rid = read trem :: Int位是不必要的 - 只需使用函数readLn代替getLine,这完全符合您的要求.此外,类型注释可能不必要(并且分散注意力),因为应该根据您对结果的处理来推断类型.
| 归档时间: |
|
| 查看次数: |
823 次 |
| 最近记录: |