3

我正在做一个小项目,我正在尝试学习 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 的信息来重载函数。我应该如何进行?

4

2 回答 2

4

首先,一些错别字:

data Course = Course { 
   id :: Int, 
   title :: String 
   } deriving (Eq, Show)

请注意添加了数据构造函数名称(“Course”)以及从“derives”更改为“deriving”。

data Req = Single Course
    | Any [Req]
    | All [Req]
    deriving Show

同样在这里。

satisfies :: [Course] -> Req -> Bool

将类型从 [Courses] 更改为 [Course]。

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

以下是您朋友的类型签名anyall

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

一切如预期。

于 2013-03-05T14:22:37.483 回答
3

好的,所以我假设您想要的是接受 a Req,然后根据它决定给定的列表是否Courses满足它。

其次,我会进行 1 次更改以减少痛苦,

Req = ... Any [Courses] | All [Courses] ...

而不是[Req]s 因为真的,有任意嵌套的需求对于这个函数来说有点奇怪和奇怪。

为此,我们将进行一些模式匹配:

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

其次,我们如何检查两个列表是否完全相交?假设函数是inter

satisfies courses (Any reqs)      = courses `inter` reqs

最后,我们如何检查一个列表是否包含另一个?叫它contains

satisfies courses (All reqs0)      = courses `contains` reqs

现在这是处理 ADT 的一种非常常见的方法。将它们分开并逐案分析。

于 2013-03-05T00:22:48.060 回答