我的课程是根据以下输入总结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?
感谢您的帮助!
答案 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以上的学生人数
我们可以通过以下步骤解决这个问题:
让我们解决第一步:
(>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
的替代品。
总而言之,我们可以将这两个函数count
和withMinGrade
结合起来编写我们想要的函数,但我会把这一步留作家庭作业。由于这是你的第一个Haskell程序,我还将引导你走向Learn You a Haskell,这是一本非常容易阅读的书,我曾经开始使用这种有趣而强大的语言。它将向您展示许多示例,并提供有关Haskell如何工作的大量解释,以及如何在不需要再次修改变量的情况下进行常规编程!一开始很难“获得”,但是一旦你拥抱不变性,你会希望你在C / C ++ / Python / Java / .NET / Ruby / Bash / Javascript /等中拥有它。它确实使得更容易理解代码如何工作,并确保它每次都能以这种方式工作。