我试图在haskell函数中调用'print out'函数.
(一个简单的调试消息).
下面是我的编译器代码和错误消息(ghc 6.10).
我不太明白为什么它会把puttr调用和空数组混为一谈.
空数组是该特定情况的返回值(打印输出消息实际上只是一个存根).
知道为什么这不起作用吗?
谢谢
我的代码:
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
Jonas.. 21
重要的是要记住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
推断你的功能,而不是使用和类似的"不纯"结构.学习利用haskells强大的类型系统并使用(例如)QuickCheck在通过类型检查器后测试您的功能.
重要的是要记住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
推断你的功能,而不是使用和类似的"不纯"结构.学习利用haskells强大的类型系统并使用(例如)QuickCheck在通过类型检查器后测试您的功能.
Jonas的帖子很好地涵盖了你的问题,所以我会给你一个惯用的重写你的findFactors函数.我第一次学习时发现它对我很有帮助.
因此,您希望n
通过查看1
最多的每个数字来查找给定数字的所有因子n/2
,检查它是否是一个因素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
调用时重新计算商数,这是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] - > [整数]".这是错误消息的"预期类型"部分.
此时,编译器得出结论,它无法匹配这两种类型,因此它报告了错误.
"无法将预期类型' Foo '与推断类型' Bar ' 匹配"可能是您在尝试编译Haskell时获得的最常见错误消息,因此值得尝试阅读并理解它.查看推断类型并尝试找出引用表达式的哪个部分具有该类型.然后通过查看周围的代码,尝试找出编译器为什么期望别的东西.