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函数的惯用重写。 我第一次学习时发现它对我有帮助。

所以你想通过查看从1n/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

这很好,但在某些方面它不太理想。 首先,每次调用findFactorsfindFactors重新计算商,即n/2分区(虽然ghc -O2似乎意识到这一点并只计算一次)。 其次,在任何地方都必须处理这个反转变量有点麻烦。 第三,它仍然非常重要。

查看问题的另一种方法是将从1n/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

上一篇: haskell: error trying to call putStrLn in function

下一篇: text using voiceBase Api