反身关闭

时间:2017-04-06 02:42:09

标签: haskell math

我一直在研究一个关于反身封闭的问题:

  

关系R的自反闭合是比R更大的最小关系,它是自反的。换句话说,它是R与任何添加的对使R反身。编写一个函数(reflClosure),它接受一对对象列表(代表R)并返回一对对象列表,它们是R的自反闭包。您不必担心对在返回值中出现的顺序。< / p>

我想出了这个解决方案,但看起来很邋and,缺乏整洁。

-- QUESTION 2: Functions and relations

reflClosure :: (Eq a) => [(a,a)] -> [(a,a)]
reflClosure (x:xs) = nub ( (x:xs) ++ [ (x,x) | x <- (heads (x:xs)) ++ (tails 
(x:xs)) ])

nub :: Eq a => [a] -> [a]
nub = nubBy (==)

nubBy :: (a -> a -> Bool) -> [a] -> [a]
nubBy eq [] = []
nubBy eq (x:xs) = x : nubBy eq (filter (\y -> not (eq x y)) xs)

heads :: (Eq a) => [(a,a)] -> [a]
heads list = nub [x | (x, _) <- list]

tails :: (Eq a) => [(a,a)] -> [a]
tails list = nub [x | (_,x) <- list]

exists :: (Eq a) => (a,a) -> [(a,a)] -> Bool
exists x xs = length (filter (==x) xs) > 0


-- TEST SET FOR Q2
{-
Your functions should have the following behaviour:
reflClosure [(1,2),(3,2)] = [(1,2),(3,2),(1,1),(2,2),(3,3)]
reflClosure [(1,1),(3,5)] = [(1,1),(3,5),(3,3),(5,5)]

DO NOT WORRY ABOUT THE ORDER IN WHICH PAIRS APPEAR IN YOUR LIST
-}

有更简单的方法吗?从中学习也很有用。

2 个答案:

答案 0 :(得分:2)

撰写headstails的更好方法如下:

heads :: (Eq a) => [(a,a)] -> [a]
heads = nub . map fst

tails :: (Eq a) => [(a,a)] -> [a]
tails = nub . map snd

它没有任何意义,而且它使用了更多&#34;功能性&#34; map而不是列表理解。

然而,你需要两者意味着更好的方式:

(heads (x:xs), tails (x:xs)) = (\(a,b) -> (nub a) (nub b)) $ unzip (x:xs)

获取fstsnd等同于unzip

此外,您可以简化exists的签名:

exists :: (Eq a) => a -> [a] -> Bool
exists x xs = length (filter (==x) xs) > 0

因为没有任何东西取决于输入是对的列表。

Data.List已经定义了nubBy,所以我不确定你为什么在那里定义它。

不清楚为什么你定义reflClosure来匹配(x:xs),因为你所关心的(显然)是列表非空。也许是这样的:

reflClosure :: (Eq a) => [(a,a)] -> [(a,a)]
reflClosure [] = []
reflClosure xs = 
  let (as,bs) = unzip xs
  in nub $ xs ++ [ (x,x) | x <- (nub as) ++ (nub bs) ]

答案 1 :(得分:2)

关系与对的集合是同构的,而不是对的列表,因此对它们进行建模是有意义的。请注意,下面的所有Ord约束都在那里,因为Set的实现需要它。

使用标准库集,因为它们很快。

import Data.Set (Set)
import qualified Data.Set as Set

使代码更易于阅读的类型同义词:

-- A relation with underlying set s
type Relation s = Set (s,s)

现在我们可以编写一个函数来获取基础集的所有成员:

underlyingMembers :: Ord a => Relation a -> Set a
underlyingMembers r = (Set.map fst r) `Set.union` (Set.map snd r)

一旦我们有了这个,找到关系的反身关闭很容易:

reflexiveClosure :: Ord a => Relation a -> Relation a
reflexiveClosure r = r `Set.union` (Set.map (\x -> (x,x)) (underlyingMembers r)

如果你真的需要使用列表,(你真的不应该),你可以fromList / toList

listVersion :: Ord a => [(a,a)] -> [(a,a)]
listVersion = Set.toList . reflexiveClosure . Set.fromList

如果其中任何一项不清楚,请发表评论,我会详细解释。