Debugging 尝试在函数中调用putStrLn时出错

Debugging 尝试在函数中调用putStrLn时出错,debugging,haskell,Debugging,Haskell,我试图在Haskell函数中放置一个“print out”函数调用 (一条简单的调试消息) 下面是我的代码和来自编译器(GHC 6.10)的错误消息 我不太明白为什么它把putStr调用和空数组混为一谈 空数组是特定情况下的返回值(打印输出消息目前实际上只是一个存根) 你知道为什么这不起作用吗 我的代码: isAFactor :: Integer -> Integer -> Bool isAFactor x y = x `mod` y == 0 findFactors :: Integer

我试图在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 isAFactor::Integer->Integer->Bool isAFactor x y=x`mod`y==0 findFactors::Integer->Integer->[Integer] findFactors计数器数量= 让商=div num 2 在里面 if(计数器>商) 那就做吧 putStrLn(“factorList是:”++显示商)(***第10行***) [] else if(isAFactor num计数器) 然后是[计数器]++[商]++findFactors(计数器+1)num 其他的 findFactors(计数器+1)数量 来自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 测试。hs:10:4: 无法匹配预期的类型“[a]->[Integer]” 针对推断类型'IO()' 在表达式中: putStrLn(“factorList是:”++显示商)[] 在表达式中: do putStrLn(“factorList是:+++显示商)[] 在表达式中: 如果(计数器>商),则 do putStrLn(“factorList是:+++显示商)[] 其他的 如果(isAFactor num计数器),则 [计数器]++[商]++findFactors(计数器+1)num 其他的 findFactors(计数器+1)数量
记住Haskell是一种函数式语言,这一点很重要。这意味着函数不允许有任何副作用,包括将调试消息打印到屏幕上

然而,打破这种纯度是可能的,它在调试中是有用的。看看这个模块。在那里你可以找到一个函数
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
正如评论所建议的那样:

哈斯克尔也是一种语言。在实际需要结果之前,不会对表达式求值。在惰性设置中使用trace函数可能会有点混乱,因为在将跟踪消息打印到屏幕上时(如果打印的话)并不总是容易理解的

由于haskell是一种非常不同的语言,因此最好尝试以同样不同的方式开发程序。尝试对函数进行推理,而不是使用
trace
和类似的“非纯”结构。学习利用Haskell强大的类型系统,并在通过类型检查器后使用(例如)测试您的函数。

更新了说明

问题是Haskell中的IO是一元的,以do开头的块是将一元表达式(有时称为语句)与一元运算符组合在一起的语法糖。在本例中,所讨论的monad是IO monad,这可以从对putStrLn的调用中推断出来。
do
块第二行的
[]
实际上不是整个do块的值,而是putStrLn的最后一个参数;并不是说它接受第二个参数,而是编译器甚至没有弄清楚这一点,因为它会在前面终止,并出现您引用的类型错误。要使该行成为命令,您必须将另一个一元函数放在它前面(例如,
return[]
)。不过,我并不是说这会帮助你解决问题

类型错误源于IO一元表达式始终具有类型
IO
;在您的情况下,
do
块也有此类型,这显然与签名中指定的类型
[Integer]
不兼容


一般来说,因为Haskell是一种带有单声道IO的纯函数式语言,一旦进入IO单声道,就没有出路了,这是不连贯的。i、 例如,如果一个函数有一个包含IO操作的
do
块,那么它的签名必然包含
IO
类型,调用该函数的所有其他函数的签名也必然包含
IO
类型,等等。(其他monad确实提供了“退出”函数,但IO monad没有。)

Jonas的帖子很好地回答了你的问题,因此,我将为您提供findFactors函数的惯用重写。当我第一次学习时,我发现它对我很有帮助

因此,通过查看从
1
n/2
的每个数字,检查它是否是
n
的因子,并建立一个包含这些因子的列表,您可以找到给定数字的所有因子
n

您的版本(只需进行少量修改即可使用):

对格式进行了一些更改,使其更具可读性:

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) []
我错过了所有其他“表达中”的部分;他们只是显示出越来越多的e
Couldn't match expected type `[a] -> [Integer]'
       against inferred type `IO ()'
In the expression:
    putStrLn ("factorList is  : " ++ show quotient) []
putStrLn :: String -> IO ()