Sorting 如何在Haskell中使用偏序对列表进行排序?
我有一个程序性的EDSL,它使用语句块 这些语句不按特定顺序添加到块中,尽管语句之间可能存在依赖关系 然而,在编译EDSL的过程中,我需要确保语句按照依赖的顺序排列,例如Sorting 如何在Haskell中使用偏序对列表进行排序?,sorting,haskell,code-generation,poset,Sorting,Haskell,Code Generation,Poset,我有一个程序性的EDSL,它使用语句块 这些语句不按特定顺序添加到块中,尽管语句之间可能存在依赖关系 然而,在编译EDSL的过程中,我需要确保语句按照依赖的顺序排列,例如 B := A C := B E := D 由于并非所有语句都具有相关性,因此没有总顺序(例如,上面的E:=D是独立的,可以放在任何位置)。不存在循环依赖关系,因此应该可以进行列表排序 我试图通过使用Data.List.sortBy和定义Ordering来破解一个解决方案,这将返回EQ,表示语句没有依赖关系。这适用于某些示例,
B := A
C := B
E := D
由于并非所有语句都具有相关性,因此没有总顺序(例如,上面的E:=D
是独立的,可以放在任何位置)。不存在循环依赖关系,因此应该可以进行列表排序
我试图通过使用Data.List.sortBy
和定义Ordering
来破解一个解决方案,这将返回EQ
,表示语句没有依赖关系。这适用于某些示例,但不适用于一般情况,例如,订购以下产品没有任何作用:
C := B B := A
D := C = should produce => C := B
B := A D := C
这是因为默认的排序插入排序只确保插入的项目小于或等于下一个项目
我在互联网上搜索了偏序集实现,但没有找到任何适用的:
定义Ordering=LT | GT | EQ | NC
(NC
用于不可比项),这很好,但提供的sort
假定NaN
与不可比项类似,并将其丢弃
除了使用可能排序
和我在包中的任何地方都没有看到排序功能之外,与上面的类似
我还没有弄明白如何使用它或者它是否适用
下面是一个包含绑定和非绑定语句的最小示例。非二进制语句的顺序很重要,它们必须保持原始顺序(即排序需要是稳定的w.r.t.没有依赖关系的语句)
我希望有一个简单的解决方案,而不使用完整的依赖关系图
module Stmts where
import Data.List ( sortBy )
data Var = A | B | C | D | E | F | G | H deriving (Eq, Show)
data Stmt = Var := Var
| Inc Var
deriving (Show)
-- LHS variable
binds :: Stmt -> Maybe Var
binds (v := _) = Just v
binds _ = Nothing
-- RHS variables
references :: Stmt -> [Var]
references (_ := v) = [v]
references (Inc v) = [v]
order :: [Stmt] -> [Stmt]
order = sortBy orderStmts
orderStmts :: Stmt -> Stmt -> Ordering
orderStmts s1 s2 = ord mbv1 mbv2
where
ord Nothing Nothing = EQ -- No dep since they don't bind vars
ord (Just v1) Nothing = LT -- Binding statements have precedence
ord Nothing (Just v2) = GT -- ^^^
ord (Just v1) (Just v2) -- Both statements are binding:
| v1 `elem` refs2 = LT -- * s2 depends on s1
| v2 `elem` refs1 = GT -- * s1 depends on s2
| otherwise = EQ -- * neither
-- *Maybe* they bind variables
mbv1 = binds s1
mbv2 = binds s2
-- Variables they reference
refs1 = references s1
refs2 = references s2
-- The following should return [B := A, C := B, D := C, Inc F, Inc G]
test = order [Inc F, Inc G, C := B, D := C, B := A]
我认为对你的陈述进行分类的唯一方法是从根源走向儿童
import Data.List
data Var = A | B | C | D | E | F | G | H deriving (Eq, Show)
data Stmt = Var := Var deriving (Show)
parent :: Stmt -> Var
parent (_ := p) = p
child :: Stmt -> Var
child (c := _) = c
steps :: [Stmt] -> [[Stmt]]
steps st = step roots st
where step _ [] = []
step r s = let (a, b) = partition (flip elem r . parent) s
(v, u) = partition (flip elem (map child b) . child ) a
in if null u then error "Cycle!"
else u : step (r ++ (nub $ map child u)) (v ++ b)
roots = let cs = map child st
rs = nub $ filter (not . flip elem cs) (map parent st)
in if null rs then error "No roots!"
else rs
main = mapM_ print $ steps [F := H, G := H, C := B, D := C, B := A]
有输出
[F := H,G := H,B := A]
[C := B]
[D := C]
当“排序”超过组(而不是语句)时
(由于通过分区
,映射
,++
,…)是不变的,因此此代码具有稳定性。)
(新增)
如果您真的想要一些稳定性属性(对语句进行排序),您必须添加一些其他限制(定义“稳定性”)
让两个“排序”直接算法(简单地将语句重新排序到前面或后面)
对于相同的输入,orderToFront
输出与orderToBack
输出不同,但两者都有效
-- orderToFront
F := H
B := A
C := B
D := C
G := F
-- orderToBack
B := A
F := H
G := F
C := B
D := C
(只有等式关系,你的算法不能低于O(n^2),但如果你定义了稳定性限制,它可以减少)你的方法的问题是你的
ordersmts
既不是一个序,也不是一个偏序。特别是,它不是,这就是为什么尝试使用它进行排序失败的原因
你要找的是。您有一个顶点图(语句),它们之间有边(它们的依赖项),并且您希望确保排序与边匹配
我将只关注声明,因为非绑定语句很容易(我们只需要将列表分成两部分,对声明进行排序并再次连接)
拓扑排序已在中实现,这使得任务非常简单:
module Stmts where
import Data.Graph
data Var = A | B | C | D | E | F | G | H deriving (Eq, Ord, Show)
data Decl = Var := Var
deriving (Show, Eq)
data Stmt = Decl
| Inc Var
deriving (Show, Eq)
sortDecls :: [Decl] -> [SCC Decl]
sortDecls = stronglyConnComp . map triple
where
triple n@(x := y) = (n, x, [y])
-- The following should return [B := A, C := B, D := C]
test = map flattenSCC . sortDecls $ [C := B, D := C, B := A]
调用
SCC
仅用于测试,因为SCC
没有Show
实例。您可能需要检查s中是否有循环(循环可能是语言编译错误),如果没有,则提取排序序列。非常清楚:您正在寻找一种稳定的排序,对于不可比较的元素,排序顺序保持不变?我搜索了一段时间后发现。我还发现网络上的评论怀疑“稳定拓扑排序”(如果存在的话就是这样)是否是一个定义良好的东西。当然,任何地方都不包含“稳定”一词。我自己的问题是:是否真的可以始终保持不可比较项的顺序?嗯,我想如果语句只需要在与其他语句没有依赖关系的情况下保持稳定,那么就没有问题了。对于一般稳定拓扑排序的较强问题,我发现了一个反例:节点a B C D E F与a>C,B>D,E步骤那样的分组顺序)。但是(我认为)关于“顺序保留”的问题并不清楚。@josejuan问题说需要保留非约束性语句的顺序,问题中的ordersmts
的实现意味着它们应该只遵循约束性语句。因此,因为对于非绑定语句,不涉及排序,所以我建议将它们从依赖项排序中排除,只是在对绑定语句排序后按原始顺序追加它们。如果需要的话,我也可以发布一个更新的代码块来澄清。(请注意,您的解决方案很棒)“我建议排除”是的,但存在很多解决方案。我看到你的解决方案一个更一般的问题(但我的头脑模糊了…:D)我可能曾经困惑过
module Stmts where
import Data.Graph
data Var = A | B | C | D | E | F | G | H deriving (Eq, Ord, Show)
data Decl = Var := Var
deriving (Show, Eq)
data Stmt = Decl
| Inc Var
deriving (Show, Eq)
sortDecls :: [Decl] -> [SCC Decl]
sortDecls = stronglyConnComp . map triple
where
triple n@(x := y) = (n, x, [y])
-- The following should return [B := A, C := B, D := C]
test = map flattenSCC . sortDecls $ [C := B, D := C, B := A]