![](/img/trans.png)
[英]code wrong haskell Couldn't match expected type `[(Key, Value)]'
[英]Couldn't match expected type - Haskell Code
我正在尝试学习Haskell,但是我尝试编写的一小段示例代码遇到了相当大的“无法匹配预期类型”错误。 任何人都可以给我一些指导,告诉我我做错了什么/我应该怎么做?
这些是错误,但我不确定我应该如何编写代码。
toDoSchedulerSimple.hs:6:14:
Couldn't match expected type `[t0]' with actual type `IO String'
In the return type of a call of `readFile'
In a stmt of a 'do' block: f <- readFile inFile
In the expression:
do { f <- readFile inFile;
lines f }
toDoSchedulerSimple.hs:27:9:
Couldn't match expected type `[a0]' with actual type `IO ()'
In the return type of a call of `putStr'
In a stmt of a 'do' block: putStr "Enter task name: "
In the expression:
do { putStr "Enter task name: ";
task <- getLine;
return inFileArray : task }
toDoSchedulerSimple.hs:34:9:
Couldn't match expected type `IO ()' with actual type `[a0]'
In a stmt of a 'do' block:
putStrLn "Your task is: " ++ (inFileArray !! i)
In the expression:
do { i <- randomRIO (0, (length inFileArray - 1));
putStrLn "Your task is: " ++ (inFileArray !! i) }
In an equation for `getTask':
getTask inFileArray
= do { i <- randomRIO (0, (length inFileArray - 1));
putStrLn "Your task is: " ++ (inFileArray !! i) }
toDoSchedulerSimple.hs:41:9:
Couldn't match expected type `[a0]' with actual type `IO ()'
In the return type of a call of `putStr'
In a stmt of a 'do' block:
putStr "Enter the task you would like to end: "
In the expression:
do { putStr "Enter the task you would like to end: ";
task <- getLine;
filter (endTaskCheck task) inFileArray }
toDoSchedulerSimple.hs:60:53:
Couldn't match expected type `IO ()'
with actual type `[String] -> IO ()'
In a stmt of a 'do' block: schedulerSimpleMain
In the expression:
do { (getTask inFileArray);
schedulerSimpleMain }
In a case alternative:
"get-task"
-> do { (getTask inFileArray);
schedulerSimpleMain }
这是代码本身。 我认为这是相当简单的,但我的想法是通过调用其他函数来运行循环,获取输入并基于它执行操作。
import System.Random (randomRIO)
import Data.List (lines)
initializeFile :: [char] -> [String]
initializeFile inFile =
do f <- readFile inFile
let parsedFile = lines f
return parsedFile
displayHelp :: IO()
displayHelp =
do putStrLn "Welcome to To Do Scheduler Simple, written in Haskell."
putStrLn "Here are some commands you might find useful:"
putStrLn " 'help' : Display this menu."
putStrLn " 'quit' : Exit the program."
putStrLn " 'new-task' : Create a new task."
putStrLn " 'get-task' : Randomly select a task."
putStrLn " 'end-task' : Mark a task as finished."
putStrLn " 'view-tasks' : View all of your tasks."
quit :: IO()
quit =
do putStrLn "We're very sad to see you go...:("
putStrLn "Come back soon!"
createTask :: [String] -> [String]
createTask inFileArray =
do putStr "Enter task name: "
task <- getLine
return inFileArray:task
getTask :: [String] -> IO()
getTask inFileArray =
do i <- randomRIO (0, (length inFileArray - 1))
putStrLn "Your task is: " ++ (inFileArray !! i)
endTaskCheck :: String -> String -> Bool
endTaskCheck str1 str2 = str1 /= str2
endTask :: [String] -> [String]
endTask inFileArray =
do putStr "Enter the task you would like to end: "
task <- getLine
return filter (endTaskCheck task) inFileArray
viewTasks :: [String] -> IO()
viewTasks inFileArray =
case inFileArray of
[] -> do putStrLn "\nEnd of tasks."
_ -> do putStrLn (head inFileArray)
viewTasks (tail inFileArray)
schedulerSimpleMain :: [String] -> IO()
schedulerSimpleMain inFileArray =
do putStr "SchedulerSimple> "
input <- getLine
case input of
"help" -> displayHelp
"quit" -> quit
"new-task" -> schedulerSimpleMain (createTask inFileArray)
"get-task" -> do (getTask inFileArray); schedulerSimpleMain
"end-task" -> schedulerSimpleMain (endTask inFileArray)
"view-tasks" -> do (viewTasks inFileArray); schedulerSimpleMain
_ -> do putStrLn "Invalid input."; schedulerSimpleMain
main :: IO()
main =
do putStr "What is the name of the schedule? "
sName <- getLine
schedulerSimpleMain (initializeFile sName)
谢谢,如果这不是提出这样一个问题的正确位置,请道歉。
您的代码存在几个问题,需要不同级别的工作才能修复。 按照我发现它们的顺序,你有......
很多类型签名都不正确。 如果函数完全执行任何I / O,则需要将其返回类型包装在IO
。 例如,而不是
createTask :: [String] -> [String]
你需要拥有
createTask :: [String] -> IO [String]
这反映了createTask
执行I / O这一事实(它向用户询问任务的名称)。
幸运的是,修复此问题很简单 - 只需删除所有类型的签名即可! 这听起来很疯狂,但它可能非常有用。 GHC具有强大的类型推断机制,这意味着通常可以在不明确指定类型的情况下推断类型。 在你的程序中, 所有类型都很简单,可以推断出来,所以你可以删除所有类型的签名,在GHCi中加载模块并输入例如:t createTask
,然后解释器会告诉你推断的类型(然后你可以添加它)来源)。
在Haskell中,函数应用程序具有最严格的绑定。 特别是,当你写作
putStrLn "Your task is: " ++ (inFileArray !! i)
这被Haskell解析为
(putStrLn "Your task is: ") ++ (inFileArray !! i)
不进行类型检查,因为左侧是IO ()
类型,右侧是String
类型。 这也很容易修复。 你只需要写出你想要的东西,也就是
putStrLn ("Your task is: " ++ (inFileArray !! i))
要么
putStrLn $ "Your task is: " ++ (inFileArray !! i)
其中operator $
表示“具有最低可能优先级的函数应用程序”,通常用于避免使用括号。
添加括号后,您的代码就行了
return (inFileArray:task)
其中inFileArray
的类型为[String]
, task
的类型为String
。 大概你打算在inFileArray
的末尾添加task
。
:
运算符用于将单个项添加到列表的前面 (O(1)操作)。 您不能使用它将项添加到列表的末尾(O(n)操作)。 Haskell中的所有列表都是链表,因此在列表前面添加项目与将其添加到最后是完全不同的。 你也想要
return (task:inFileArray)
这将把任务添加到列表的前面,或者
return (inFileArray ++ [task])
它从task
创建一个新的单元素列表,并使用列表连接运算符++
将其添加到列表的末尾。
>>=
这是您的代码中最根本的误解,需要最多的工作来解释。 让我们看看以下(经过高度编辑的)代码片段:
schedulerSimpleMain :: [String] -> IO () -- 1
schedulerSimpleMain inFileArray = -- 2
do input <- getLine -- 3
case input of -- 4
"new-task" -> schedulerSimpleMain (createTask inFileArray) -- 5
_ -> do putStrLn "Invalid input."; schedulerSimpleMain -- 6
我们已经知道createTask
的类型是[String] -> IO [String]
。 因此第5行不进行类型检查。 函数schedulerSimpleMain
需要一个[String]
但是你传递一个IO [String]
。
您需要做的是从createTask inFileArray
的结果中打开IO
层,并将生成的[String]
传递给schedulerSimpleMain
(它将其重新包装在IO
层中)。 这正是operator >>=
(发音为bind )的作用。 你可以把这一行写成
createTask inFileArray >>= schedulerSimpleMain
你可以将>>=
运算符视为“管道转发”结果(有点像Unix管道运算符),但也可以在路上进行所有必要的展开/重新处理。
它可以是一个有点棘手正确使用绑定操作,当你刚刚起步的,这是我们提供的原因之一do
摆在首位符号。 您可以将此代码段写为
do newInFileArray <- createTask inFileArray
schedulerSimpleMain newInFileArray
这对于我上面编写的代码来说只是语法糖,但是如果你对bind运算符感到不舒服的话,它会更具可读性。
在第6行中,您有一个不同但相关的问题。 测序操作员;
本质上意味着“在左边做计算,忽略结果,然后在右边做计算”。 它要求左计算具有类型IO a
,而右计算具有类型IO b
(对于任何a
和b
)。
不幸的是,你正确的计算有[String] -> IO [String]
,所以这一行也不是类型检查。 要更正它,您只需确保将相应的参数提供给schedulerSimpleMain
:
do putStrLn "Invalid input."; schedulerSimpleMain inFileArray
现在哪个样子。 你的代码中都有这种错误。 我不会在这里详细介绍所有修复方法。 我想你应该先尝试自己解决。 如果你在一天左右的时间内仍遇到问题,我可以将更正的代码放在hpaste上供你学习。
我建议你用较小的位来打破你的程序并逐个测试它们。 我已经修复了你的几个功能:你可以为其他功能做同样的事情。
import System.Random (randomRIO)
import Data.List (lines)
-- ERROR
-- f.hs:6:14:
-- Couldn't match expected type `[t0]' with actual type `IO String'
-- In the return type of a call of `readFile'
-- In a stmt of a 'do' block: f <- readFile inFile
-- In the expression:
-- do { f <- readFile inFile;
-- let parsedFile = lines f;
-- return parsedFile }
-- WHY?
-- initializeFile reads a file, therefore it must live inside the IO monad
initializeFile :: String -> IO [String]
initializeFile inFile = do
f <- readFile inFile
let parsedFile = lines f
return parsedFile
quit :: IO()
quit = do
putStrLn "We're very sad to see you go...:("
putStrLn "Come back soon!"
-- ERROR
-- f.hs:76:44:
-- Couldn't match expected type `IO ()'
-- with actual type `[String] -> IO ()'
-- In a stmt of a 'do' block: schedulerSimpleMain
-- In the expression:
-- do { putStrLn "Invalid input.";
-- schedulerSimpleMain }
-- In a case alternative:
-- _ -> do { putStrLn "Invalid input.";
-- schedulerSimpleMain }
-- WHY?
-- in the "_" case, schedulerSimpleMain is called without parameters, but
-- it needs a [String] one.
schedulerSimpleMain :: [String] -> IO()
schedulerSimpleMain inFileArray = do
putStr "SchedulerSimple> "
input <- getLine
case input of
"quit" -> quit
_ -> do putStrLn "Invalid input."; schedulerSimpleMain inFileArray
main :: IO()
main = do
putStr "What is the name of the schedule? "
sName <- getLine
-- Extract the lines from the IO monad
ls <- initializeFile sName
-- Feed them to the scheduler
schedulerSimpleMain ls
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.