我有一个使用语句块的程序 EDSL。
尽管语句之间可能存在依赖关系,但这些语句以没有特定顺序添加到块中。
然而,在 EDSL 的编译过程中,我需要确保语句按依赖顺序排序,例如
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
这是因为默认排序插入排序并且只确保插入的项小于或等于下一项。
我在互联网上搜索了一个 Poset 实现,但没有找到任何适用的:
altfloat:Data.Poset定义Ordering = LT | GT | EQ | NC
(NC
对于不可比较的)这很好,但提供的sort
假设NaN
- 类似不可比较的项目,只是把它们扔掉。
logfloat:Data.Number.PartialOrd与上面的类似,除了用途Maybe Ordering
,我在包的任何地方都没有看到排序功能。
Math.Combinatorics.Poset我还没有弄清楚如何使用它或它是否适用。
下面是一个最小的例子,它同时具有绑定和非绑定语句。非约束语句的顺序很重要,它们必须保持原始顺序(即排序需要是稳定的 wrt 语句,没有依赖关系)。
我希望在不使用完整的依赖图的情况下有一个简单的解决方案......
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]