我正在尝试制作composition of relations。 这里的关系用列表表示。
funComp :: Ord a => [[a,a]] -> [[a,a]] -> [[a,a]]
funComp [[a,b]] [[c,d]]
| b == c = [[a,d]]
例如,给定:
[[1,1],[1,2],[2,2],[2,3],[3,3],[3,4],[4,4]]
和
[[1,4],[1,4],[2,3],[2,3],[3,2],[3,1],[4,1]]
应该返回:
[[1,4],[1,4],[1,3],[2,2],[2,1],[3,2],[3,1],[4,1]]
答案 0 :(得分:4)
我在下面提供了完整的答案,希望您会发现它有用。我同意@erisco的意见,如果你刚刚开始,这个问题可能会有点进步。您可能希望从一些仅涉及一个列表/关系而不是合并两个的问题开始。 (例如,如何通过删除 x R x 形式的所有元素来建立反自反关系?如何生成所有值 y 的集合,使得 > x R y 对于固定值 x ?你能用内置的Haskell函数和从头开始解决这些问题吗?)
无论如何,首先,你可能会发现它很有帮助,只是从易于阅读的角度来看,使用元组来表示关系元素,所以你的两个示例关系将是:
r1 = [(1,1),(1,2),(2,2),(2,3),(3,3),(3,4),(4,4)]
r2 = [(1,4),(1,4),(2,3),(2,3),(3,2),(3,1),(4,1)]
您要做的是构造是一种关系,由从r1
和r2
的任何有序元素对创建的所有复合元素组成。这是列表理解有用的东西:
result = [ combine x y | x <- r1, y <- r2 ]
此表达式从两个关系中创建每对combine x y
,x
上运行y
的结果列表。 combine
应该是什么?好吧,它需要两个元素并生成它们的组合,所以你可能首先尝试类似的东西:
combine (a,b) (c,d) | b == c = (a,d)
这将进行类型检查,但combine
只是一个部分功能 - 对于那些没有组合的对没有价值 - 所以这不会让你太过分。你需要一种编写combine
的方法,它允许你返回一个组合,如果存在一个组合,否则什么也不返回。
在Haskell中执行此操作的标准方法是使用Maybe
类型:
combine (a,b) (c,d) | b == c = Just (a,d)
| otherwise = Nothing
此类型检查并运行,但result
的值如下所示:
[Just (1,4),Just (1,4),Nothing,Nothing...]
幸运的是,Data.Maybe
中有一个名为catMaybes
的函数正是我们对这种情况所需要的 - 它会丢弃所有Nothing
并提取Just
值在删除文字Just
构造函数的同时:
> catMaybes result
[(1,4),(1,4),(1,3),...]
有一些重复项应该删除,所以让我们使用nub
中的Data.List
删除它们:
> nub (catMaybes result)
[(1,4),(1,3),(2,3),(2,2),(2,1),(3,2),(3,1),(4,1)]
看起来像你可能想要的答案,但我认为你在示例输出中错过了(2,3)
。
完整的程序,略微概括,看起来像这样:
module Relations where
import Data.List
import Data.Maybe
r1 = [(1,1),(1,2),(2,2),(2,3),(3,3),(3,4),(4,4)]
r2 = [(1,4),(1,4),(2,3),(2,3),(3,2),(3,1),(4,1)]
combine (a,b) (c,d) | b == c = Just (a,d)
| otherwise = Nothing
funcComp r1 r2
= nub $ catMaybes [ combine x y | x <- r1, y <- r2 ]
result = funcComp r1 r2
如果您还没有:
Prelude
,Data.List
和Data.Maybe
等关键模块的文档,以便熟悉其中可用的功能答案 1 :(得分:0)
“集合理解”方面的许多数学定义对列表推导具有相当直接的翻译。 (从左到右)关系构成的定义是:
R; S = {(x,z)| (x,y)∈R,(y,z)∈S}
也就是说,x与复合中的z有关,如果你可以从x到z跳过一些y到R,然后从y跳到z到s。
你几乎可以准确地翻译它 - 我们只需要将y的两个提及分开,因为你只能绑定模式中的新变量。
compose r s = [ (x,z) | (x,y) <- r, (y',z) <- s, y == y' ]
要给它一个类型签名,我会创建一个类型同义词,然后
type Relation a b = [(a,b)]
compose :: Relation a b -> Relation b c -> Relation a c
请注意,这与许多定义组合的顺序相反。我只是把关系视为成对的对象,特别清楚这个方向,并且反过来混淆。