我只是在学习一些简单的haskell代码,但是我一直关注的教程都没有提到尝试运行带有do和I / O类型的任何代码时继续遇到的错误。 GHCI似乎认为其某种类型错误。这是我的代码:
main = do
putStrLn "This program can find all odd numbers between 1 and a desired number. Please enter a number."
user <- getLine
if (read user) < 1
then
do putStrLn "Improper input specified. 10 will be chosen as default."
putStrLn show oddsort 10 [] ++ "Is the list of odd numbers from 1 to 10."
else
do putStrLn show (oddsort (read user) [])
oddsort x xs
|x == 1 = 1:xs
|x `mod` 2 == 0 = oddsort (x-1) xs
|otherwise = oddsort (x - 2) (x:xs)
答案 0 :(得分:5)
您的代码中有两个错误:
缩进。始终确保do
块中属于在一起的所有行都缩进同一级
main = do
⋮putStrLn "This program..."
⋮user <- getLine
⋮if (read user) < 1
⋮ then
⋮ do⋮putStrLn "Improper..."
⋮ ⋮█putStrLn ...
⋮ else
⋮ do putStrLn ...
请注意,在第三个putStrLn
之前有一个空格。
缩进对于许多其他Haskell构造(where
,case
,class
)也很重要。 ..)。从样式上讲,我也会养成对齐else
/ then
的习惯,尽管实际上标准并不需要。即
main = do
⋮putStrLn "This program..."
⋮user <- getLine
⋮if (read user) < 1
⋮⋮then do
⋮⋮ ⋮putStrLn "Improper..."
⋮⋮ ⋮putStrLn ...
⋮⋮else do
⋮⋮ ⋮putStrLn ...
尽管putStrLn
看起来像总是这样被解析的“行首的命令”,但事实并非如此-只是一个普通的函数。因此,putStrLn show oddsort 10 [] ++ "Bla"
被解析为
(putStrLn show oddsort 10 []) ++ "Bla"
即putStrLn
应用于参数show
,oddsort
,10
和[]
。显然,它不知道该怎么做,即这是一个巨大的类型错误!你真正想要的是
putStrLn (show (oddsort 10 []) ++ "Bla")
也可以用“括号化运算符” $
编写:
putStrLn $ show (oddsort 10 []) ++ "Bla"
答案 1 :(得分:2)
我将专注于这些行
do putStrLn "Improper input specified. 10 will be chosen as default."
putStrLn show oddsort 10 [] ++ "Is the list of odd numbers from 1 to 10."
问题:
缩进错误:块条目应完全在同一列上开始
第二行解析为(putStrLn show oddsort 10 []) ++ ("Is the list of odd numbers from 1 to 10.")
,这是错误的,因为您不能++
像putStrLn show oddsort 10 []
这样的非列表。您需要括号。
putStrLn show oddsort 10 []
调用具有四个参数的函数putStrLn
:show
,oddsort
,10
和[]
。这不是您想要的,因此需要更多的括号。
可能还有更多问题,但这是最明显的问题。
一般建议:将类型签名添加到所有顶级绑定中,例如oddsort
。这将帮助GHC产生更好的类型错误消息。
此外,使用-Wall
打开警告也可以帮助检测某些问题。
答案 2 :(得分:1)
这是您代码的有效版本:
get
我对您的代码进行了一些更改,并按顺序列出了它们。
我做的第一件事是向oddsort :: Int -> [Int] -> [Int]
oddsort x xs
|x == 1 = x : xs
|x `mod` 2 == 0 = oddsort (x - 1) (x:xs)
|otherwise = oddsort (x - 2) (x:xs)
main = do
putStrLn "This program can find all odd numbers between 1 and a desired number. Please enter a number."
user <- getLine
if (read user :: Int) < 1
then putStrLn $ "Improper input specified. 10 will be chosen as default. \n" ++ ((show $ oddsort 10 []) ++ " Is the list of odd numbers from 1 to 10.")
else putStrLn $ show $ (oddsort (read user :: Int) [])
添加类型签名,因为否则类型签名将留给编译器来推断(猜测)类型,而您实际上并不想使用函数来这样做,为什么? ?仔细检查this。
然后我将oddsort
更改为if (read user) < 1
,因为您再次将其留给编译器来猜测if (read user :: Int) < 1
的返回值,并在定义后读取返回的特定类型返回类型read
的签名,它指定:: Int
的返回类型是read
。
最后一个更改是在Int
子句中,我只是删除了第二条then
语句,并将putStrLn
的结果连接到(show $ oddsort 10 [])
,因为有了"Is the list of odd numbers from 1 to 10.")
GHC将show之后的所有内容作为参数,而putStrLn只能接受字符串,并且只能接受1个参数。您可以通过键入putStrLn show oddsort 10 []
在repl上看到它。另外,我将它们串联为1个字符串,因为您实际上只需要1个,但是2个看起来更整洁,因此请保持这种方式,但要在第二个putStrLn中加上括号,这样就只有1个参数。您也可以使用:t show
运算符。