haskell:尝试在函数中调用putStrLn时出错
我试图在haskell函数中放置一个'print out'函数调用。
(一个简单的调试消息)。
下面是我的编译器代码和错误消息(ghc 6.10)。
我不太明白为什么它会提升putstr调用和空数组。
空数组是特定情况下的返回值(打印输出消息现在实际上只是一个存根)。
任何想法,为什么这是行不通的?
谢谢
我的代码:
isAFactor :: Integer -> Integer -> Bool isAFactor x y = x `mod` y == 0 findFactors :: Integer -> Integer -> [Integer] findFactors counter num = let quotient = div num 2 in if(counter > quotient) then do putStrLn ("factorList is : " ++ show quotient) (*** Line 10***) [] else if(isAFactor num counter) then [counter] ++ [quotient] ++ findFactors (counter + 1) num else findFactors (counter + 1) num
来自ghc的错误
test.hs:10:4: Couldn't match expected type `[a] -> [Integer]' against inferred type `IO ()' In the expression: putStrLn ("factorList is : " ++ show quotient) [] In the expression: do putStrLn ("factorList is : " ++ show quotient) [] In the expression: if (counter > quotient) then do putStrLn ("factorList is : " ++ show quotient) [] else if (isAFactor num counter) then [counter] ++ [quotient] ++ findFactors (counter + 1) num else findFactors (counter + 1) num
记住Haskell是一种纯粹的函数式语言是很重要的。 这意味着功能不允许有任何副作用,包括将调试消息打印到屏幕上。
然而,打破这种纯度是可能的,它可以用于调试。 看看模块Debug.Trace。 在那里你会找到一个函数trace :: String -> a -> a
。 你可以像这样在你的代码中使用它:
import Debug.Trace
isAFactor :: Integer -> Integer -> Bool
isAFactor x y = x `mod` y == 0
findFactors :: Integer -> Integer -> [Integer]
findFactors counter num =
let quotient = div num 2
in
if(counter > quotient)
then trace ("factorList is: " ++ show quotient) []
else if(isAFactor num counter)
then [counter] ++ [quotient] ++ findFactors (counter + 1) num
else
findFactors (counter + 1) num
正如评论建议的那样:
Haskell也是一种懒惰的语言。 在实际需要结果之前,不会评估表达式。 使用跟踪功能在懒惰设置中会有点混乱,因为跟踪消息打印到屏幕时(如果打印出来的话)并不总是很容易理解。
由于haskell是一种非常不同的语言,因此尝试和以不同方式开发程序也许是最好的选择。 尝试推理你的功能,而不是使用trace
和类似的“unpure”结构。 学习利用haskells强大的类型系统,并使用(例如)QuickCheck在通过类型检查器后测试函数。
乔纳斯的帖子很好地涵盖了你的问题,所以我会给你一个findFactors函数的惯用重写。 我第一次学习时发现它对我有帮助。
所以你想通过查看从1
到n/2
每个数字来查找给定数字n
的所有因子,检查它是否是n
的因子并建立一个列表。
您的版本(只需最少的修改即可使其运行):
findFactors :: Integer -> Integer -> [Integer]
findFactors counter num =
let quotient = div num 2
in
if(counter > quotient)
then []
else if(isAFactor num counter)
then [counter] ++ findFactors (counter + 1) num
else
findFactors (counter + 1) num
一些格式更改使其更具可读性:
findFactors :: Integer -> Integer -> [Integer]
findFactors counter num
| counter > div num 2 = []
| otherwise = if num `isAFactor` counter
then counter:findFactors (counter+1) num
else findFactors (counter + 1) num
这很好,但在某些方面它不太理想。 首先,每次调用findFactors
时findFactors
重新计算商,即n/2
分区(虽然ghc -O2
似乎意识到这一点并只计算一次)。 其次,在任何地方都必须处理这个反转变量有点麻烦。 第三,它仍然非常重要。
查看问题的另一种方法是将从1
到n/2
的整数列表进行过滤,只对那些因子为n
过滤器进行过滤。 这直接转化为Haskell:
findFactors :: Integer -> [Integer]
findFactors num = filter (isAFactor num) [1..(num `div` 2)]
发现它具有与上述版本相同的性能特征可能会令人惊讶。 Haskell不需要一次为整个列表分配最多n/2
内存,它可以根据需要生成每个值。
其他人在解释你的代码方面做得很好,所以让我帮你解码错误信息。
Couldn't match expected type `[a] -> [Integer]'
against inferred type `IO ()'
In the expression:
putStrLn ("factorList is : " ++ show quotient) []
我错过了所有其他的“在表达”部分; 他们只是表现出越来越多的封闭环境。
Haskell中的所有东西都是一个表达式,所以所有东西都有一个类型。 这包括诸如“putStrLn”之类的东西。 如果你在GHCi中输入“:t putStrLn”,你会看到它的回复:
putStrLn :: String -> IO ()
这意味着putStrLn是一个函数,它接受一个字符串并返回一个“IO动作”,在这种情况下是将消息放在屏幕上的动作。 在你的代码中,你给了“putStrLn”一个字符串,所以编译器推断表达式“putStrLn(stuff)”的类型为“IO()”。 这是编译器错误消息的“推断类型”部分。
与此同时,编译器也从另一个方向进行类型推断,除了其他方面外,它注意到这个“putStrLn(stuff)”表达式似乎应用于一个空的列表,其类型为“[a]” (即一些东西,我们不知道是什么)。 此外,整个表达式的结果应该是“[Integer]”类型。 因此,表达式“putStrLn(stuff)”应该是一个将“[]”变成整数列表的函数,其类型写为“[a] - > [Integer]”。 这是错误消息的“预期类型”部分。
在这一点上,编译器得出结论,它不能匹配这两种类型,所以它报告了错误。
“无法匹配预期类型”Foo“与推测类型”Bar“”可能是尝试编译Haskell时最常见的错误消息,因此它值得尝试读取并理解它。 查看推断的类型,并试图找出引用的表达式的哪一部分具有该类型。 然后通过查看周围的代码,试图找出编译器为什么期望别的东西。
链接地址: http://www.djcxy.com/p/5667.html