How to sort a list using partial order in Haskell?

roldugin

I have a procedural EDSL which uses blocks of statements.

These statements are added to the blocks in no particular order although there may be dependencies between statements.

During compilation of the EDSL, however, I need to make sure that the statements are ordered in the order of dependence, e.g.

B := A
C := B
E := D

Since not all statements have dependencies there is no total order (E.g. E := D above is independent and can be placed anywhere). There are no cyclic dependencies so list ordering should be possible.

I have tried to hack a solution by using Data.List.sortBy and defining Ordering which would return EQ to mean that the statements have no dependencies. This worked for some examples but not in the general case, e.g. ordering the following did nothing:

C := B                           B := A
D := C    = should produce =>    C := B
B := A                           D := C

This is because the default sort insertion sort and only makes sure the inserted item is smaller or equal to the next.

I have searched the internets for a Poset implementation but have not found anything applicable:

altfloat:Data.Poset defines Ordering = LT | GT | EQ | NC (NC for Non-comparable) which is good but the provided sort assumes NaN-like non-comparable items and just throws them away.

logfloat:Data.Number.PartialOrd is similar to the above except uses Maybe Ordering and I didn't see a sorting function anywhere in the package.

Math.Combinatorics.Poset I haven't figured out how to use it or whether it's applicable.

Below is a minimal example which has both binding and non-binding statements. The order of non-biniding statements matters and they must maintain the original order (i.e. sorting needs to be stable w.r.t. statements that don't have a dependence relation).

I hope there is a simple solution to this without using a full-blown dependence graph...

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]
Petr

The problem with your approach is that your orderStmts is neither an ordering nor a partial ordering. In particular, it's not transitive and this is why the attempts at using it for sorting fail.

What you are looking for is topological sorting. You have a graph of vertices (statements) that have edges between them (their dependencies) and you want to ensure that the ordering matches the edges.

I'll focus only on the declarations, as the non-binding statements are easy (we just need to split the list into two, sort the declarations and concatenate again).

Topological sorting is already implemented in Data.Graph, which makes the task very simple:

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]

Calling flattenSCC is only for testing, as SCC has no Show instance. You'll probably want to check the SCCs for cycles (a cycle would be a language compilation error), and if there is none, extract the sorted sequence.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to sort the list order using Linq?

From Dev

How to sort the list order using Linq?

From Dev

How to sort a list of strings by using the order of the items in another list?

From Dev

Partial fold of a list in Haskell

From Dev

How to sort a list in Haskell in command line ghci

From Dev

how to sort list order in index view

From Java

How to sort/order a list by date in dart/flutter?

From Dev

How to sort a list of objects in a template in alphabetic order?

From Dev

How to sort list<string> in custom order

From Dev

How to sort a list of lists in lexicographic order?

From Dev

How to sort integer list in python descending order

From Dev

How to sort list by POJO property in descending order?

From Dev

How to sort a list of strings with a different order?

From Dev

How to sort an alphanumeric list by alphabet order

From Dev

How to custom order/sort objects in a list

From Dev

How to sort a list by length and then in reverse alphabetical order

From Dev

How to sort a list in descending order along with group by?

From Dev

How to sort a list by a certain order in Common Lisp?

From Dev

How to sort a list of strings with a different order?

From Dev

Haskell partial sum of a list error

From Dev

how to sort a list using python?

From Dev

How to sort enum using a custom order attribute?

From Dev

How sort XML using XSLT ascending order

From Dev

how to sort date in descending order using comparator

From Dev

How to sort in desc order using primitive type?

From Dev

How sort XML using XSLT ascending order

From Dev

Haskell change the order of a list

From Dev

sort a list by prefered order

From Dev

Sort list with specific order

Related Related

HotTag

Archive