当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《haskell:尝试在函数中调用putStrLn时出错》经验,为你挑选了3个好方法。

我试图在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在通过类型检查器后测试您的功能.



1> Jonas..:

重要的是要记住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在通过类型检查器后测试您的功能.



2> Peter Burns..:

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,它可以根据需要生成每个值.



3> Paul Johnson..:

其他人已经很好地解释了你的代码,所以让我帮你解码错误信息.

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时获得的最常见错误消息,因此值得尝试阅读并理解它.查看推断类型并尝试找出引用表达式的哪个部分具有该类型.然后通过查看周围的代码,尝试找出编译器为什么期望别的东西.

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有