哈斯克尔 - 无法演绎(Num Bool)字面上的'0'

时间:2014-07-09 19:28:26

标签: haskell boolean ghci

我的课程是根据以下输入总结9年级(从0到20)的学生人数:

aprov [("John",14)("Martha",8)("Elsa",12)]

输出应为“2”。但在编译时:

k = 0
aprov [] = 0
aprov ((a,n):y)  = if n > 9 then k == k + 1 else k == k

GHCi给了我这个错误:

Could not deduce (Num Bool) arising from the literal `0'
from the context (Num a, Ord a)
  bound by the inferred type of
     aprov :: (Num a, Ord a) => [(t, a)] -> Bool
  at prog.hs:(29,1)-(30,55)
Possible fix: add an instance declaration for (Num Bool)
In the expression: 0
In an equation for `aprov': aprov [] = 0

我该怎么做才能解决它。顺便说一句,我如何限制“n”以使最大值为20?

感谢您的帮助!

1 个答案:

答案 0 :(得分:7)

问题是你指定了

aprov [] = 0

然后在下一行你说

aprov ((a,n):y) = if n > 9 then k == k + 1 else k == k

返回两个表达式之一

k == k + 1

或者

k == k

哪些是布尔。所以编译器认为你的函数来返回一个Bool,但你也可以让它返回0,这是一个Num a => a,{{1} }不是Bool


你说你想要计算成绩通过特定考试的学生,在这种情况下Num。好吧,在Haskell中,所有值都是不可变的,你不能从它们的初始值改变它们。这很难,我们习惯于能够修改变量,但在Haskell 中没有变量

相反,我们可以使用函数来执行我们通常使用变量的操作。因此,让我们列出问题陈述以及我们可以采取的步骤:

  

计算年级9以上的学生人数

我们可以通过以下步骤解决这个问题:

  1. 找到成绩高于9的学生
  2. 计算这些学生的人数。
  3. 让我们解决第一步:

    (>9)

    所以我们在这里说,如果我们要求哪个学生从空列表中获得最低成绩,我们会得到一个空列表。如果列表中至少有一名学生,我们会根据允许的最低成绩检查他们的成绩,如果它超过了我们将其返回以及对其他学生执行相同的操作,否则我们只检查其余的学生。如果这看起来像很多工作,那是因为它! Haskell内置了一个方便的函数,用于执行名为-- A simple type alias to make our type signatures more readable -- This just says that "Student" and "(String, Int)" are interchangeable type Student = (String, Int) withMinGrade :: Int -> [Student] -> [Student] withMinGrade minGrade [] = [] withMinGrade minGrade ((name, grade):rest) = if grade > minGrade then (name, grade) : withMinGrade minGrade rest else withMinGrade minGrade rest 的精确操作。它看起来像

    filter

    注意这与filter :: (a -> Bool) -> [a] -> [a] filter condition [] = [] filter condition (x:xs) = if condition x -- Apply the function "condition" to "x" returning a Bool then x : filter condition xs else filter condition xs 基本相同,但是可以推广到任何条件。使用withMinGrade,我们可以更简单地实现filter

    withMinGrade

    我们也可以使用内联lambda函数执行此操作,因此我们不必定义withMinGrade :: Int -> [Student] -> [Student] withMinGrade minGrade students = filter checkStudent students where checkStudent (name, grade) = grade > minGrade

    checkStudent

    甚至还有一些有趣的功能组合:

    withMinGrade minGrade students = filter (\(name, grade) -> grade > minGrade) students
    

    我会让你玩这个定义来弄清楚它是如何工作的


    现在解决问题2.这个使用类似的递归方式,但我们返回一个数字而不是列表:

    withMinGrade minGrade students = filter ((> minGrade) . snd) students
    

    所以这种情况很容易,空列表中有0个元素。具有至少一个元素的列表怎么样?嗯,直观地说,我们希望它返回比列表其余部分长度大1的计数,或者使用代码

    -- count should work on any kind of list
    count :: [a] -> Int
    count [] = 0
    

    非常简单,我们说列表中的元素数量只比列表尾部的元素数量多1个。同样,Haskell有一个内置函数(更高效),称为count :: [a] -> Int count [] = 0 count (x:xs) = 1 + count xs ,我们可以使用它!这是length的替代品。


    总而言之,我们可以将这两个函数countwithMinGrade结合起来编写我们想要的函数,但我会把这一步留作家庭作业。由于这是你的第一个Haskell程序,我还将引导你走向Learn You a Haskell,这是一本非常容易阅读的书,我曾经开始使用这种有趣而强大的语言。它将向您展示许多示例,并提供有关Haskell如何工作的大量解释,以及如何在不需要再次修改变量的情况下进行常规编程!一开始很难“获得”,但是一旦你拥抱不变性,你会希望你在C / C ++ / Python / Java / .NET / Ruby / Bash / Javascript /等中拥有它。它确实使得更容易理解代码如何工作,并确保它每次都能以这种方式工作。