我正在开展一个小项目,我正在努力学习Haskell并制定计划以帮助计划学生的日程安排。我有以下类型:
data Course =
{ id :: Int, title :: String }
deriving (Eq, Show)
data Req = Single Course
| Any [Req]
| All [Req]
deriving Show
现在我想写一个方法:
satisfies :: [Course] -> Req -> Bool
但我无法弄清楚我应该如何使用有关Req的信息来重载函数。我该怎么办?
答案 0 :(得分:4)
首先,一些拼写错误:
data Course = Course {
id :: Int,
title :: String
} deriving (Eq, Show)
请注意添加数据构造函数名称(“课程”)以及从“派生”更改为“派生”。
data Req = Single Course
| Any [Req]
| All [Req]
deriving Show
同样在这里。
satisfies :: [Course] -> Req -> Bool
将类型从[课程]更改为[课程]。
course1 = Course 1 "One"
course2 = Course 2 "Two"
course3 = Course 3 "Three"
course4 = Course 4 "Four"
course5 = Course 5 "Five"
req1 = Single course2
req2 = Any [Single course2, Single course3, Single course5]
req3 = All [Single course1, Single course2]
req4 = Any [req2, req3]
req5 = All [req4, req1]
一些测试数据。
satisfies cs (Single c) = c `elem` cs
符合单门课程要求。另外两个在简洁方面很漂亮,因为他们所做的大部分内容已在Prelude中定义,你可以像英语一样阅读它们:
satisfies cs (Single c) = c `elem` cs
satisfies cs (Any reqs) = any (satisfies cs) reqs
satisfies cs (All reqs) = all (satisfies cs) reqs
以下是您的朋友any
和all
的类型签名:
any :: (a -> Bool) -> [a] -> Bool
all :: (a -> Bool) -> [a] -> Bool
它们都采用布尔函数并为列表的每个成员测试它。由于我们有一个需求列表和一个测试函数(它satisfies
递归地并且部分地应用于已解除的课程),我们可以直接使用它们。
我们来测试一下:
*TestSO15213421> satisfies [course1] req1
False
*TestSO15213421> satisfies [course2] req1
True
*TestSO15213421> satisfies [course1, course2] req1
True
*TestSO15213421> satisfies [course1, course2] req1
True
*TestSO15213421> satisfies [course1, course2] req3
True
*TestSO15213421> satisfies [course1, course3] req3
False
*TestSO15213421> satisfies [course1, course3] req2
True
*TestSO15213421> satisfies [course4] req2
False
*TestSO15213421> satisfies [course4] req5
False
*TestSO15213421> satisfies [course5] req2
True
*TestSO15213421> satisfies [course4] req4
False
*TestSO15213421> satisfies [course2] req4
True
*TestSO15213421> satisfies [course2, course3] req4
True
*TestSO15213421> satisfies [course5, course3] req4
True
*TestSO15213421> satisfies [course5, course3] req5
False
一切如预期。
答案 1 :(得分:3)
好的,所以我假设你想要的是接受Req
,然后根据它来决定给定的Courses
列表是否满足它。
第二,我做了一个改变,以减轻痛苦,
Req = ... Any [Courses] | All [Courses] ...
而不是[Req]
,因为实际上,有任意嵌套的要求对于这个函数来说有点不稳定和奇怪。
为此,我们将进行一些模式匹配:
satisfies :: [Courses] -> Req -> Bool
satisfies courses (Single course) = undefined
satisfies courses (Any reqs) = undefined
satisfies courses (All reqs) = undefined
好的,现在我们已经遇到了3个问题。
首先,我们如何检查列表是否包含元素?我会告诉你如何做到这一点,让我们说你找出一个函数elem
然后
satisfies courses (Single course) = course `elem` courses
其次,我们如何检查2个列表是否相交?假设函数是inter
satisfies courses (Any reqs) = courses `inter` reqs
最后我们如何检查列表是否包含另一个?称之为contains
satisfies courses (All reqs0) = courses `contains` reqs
现在这是一种处理ADT的常用方法。将它们拆开并进行一种逐案分析。