Haskell - 无法演绎(Num Bool)字面上的'0'

mag*_*mig 1 haskell boolean ghci

我的课程是通过这样的输入来总结9级以上(从0到20)的学生数量:

aprov [("John",14)("Martha",8)("Elsa",12)]
Run Code Online (Sandbox Code Playgroud)

输出应为"2".但在编译时:

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

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
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能解决它.顺便说一句,我怎样才能限制"n"以使最大值为20?

感谢您的帮助!

bhe*_*ilr 7

问题是你指定

aprov [] = 0
Run Code Online (Sandbox Code Playgroud)

然后在下一行你说

aprov ((a,n):y) = if n > 9 then k == k + 1 else k == k
Run Code Online (Sandbox Code Playgroud)

返回两个表达式中的一个

k == k + 1
Run Code Online (Sandbox Code Playgroud)

要么

k == k
Run Code Online (Sandbox Code Playgroud)

哪个是布尔.所以编译器认为你的函数必须返回一个Bool,但你也有它返回0,这是一个Num a => a,而Bool不是一个Num.


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

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

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

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

  1. 找到9级以上的学生
  2. 计算这些学生的数量.

让我们解决第一步:

-- 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
Run Code Online (Sandbox Code Playgroud)

所以我们在这里说,如果我们要求哪个学生从空列表中获得最低成绩,我们会得到一个空列表.如果列表中至少有一名学生,我们会根据允许的最低成绩检查他们的成绩,如果它超过了我们将其返回以及对其他学生执行相同的操作,否则我们只检查其余的学生.如果这看起来像很多工作,那是因为它!Haskell内置了一个方便的函数来执行这个精确的操作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
Run Code Online (Sandbox Code Playgroud)

注意这与基本相同withMinGrade,但是可以推广到任何条件.使用filter,我们可以withMinGrade更简单地实现:

withMinGrade :: Int -> [Student] -> [Student]
withMinGrade minGrade students = filter checkStudent students
    where checkStudent (name, grade) = grade > minGrade
Run Code Online (Sandbox Code Playgroud)

我们也可以使用内联lambda函数来做到这一点,所以我们不必定义checkStudent:

withMinGrade minGrade students = filter (\(name, grade) -> grade > minGrade) students
Run Code Online (Sandbox Code Playgroud)

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

withMinGrade minGrade students = filter ((> minGrade) . snd) students
Run Code Online (Sandbox Code Playgroud)

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


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

-- count should work on any kind of list
count :: [a] -> Int
count [] = 0
Run Code Online (Sandbox Code Playgroud)

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

count :: [a] -> Int
count [] = 0
count (x:xs) = 1 + count xs
Run Code Online (Sandbox Code Playgroud)

很简单,我们说列表中的元素数量只比列表尾部的元素数量多1个.同样,Haskell有一个内置函数(更高效)length,我们可以使用它来代替!这是一个替代品的下降count.


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

  • @magamig耐心是一种很好的美德. (2认同)