Skip to content

Commit c0a9fe4

Browse files
Add a function to return the list of edges in a graph (#17)
* Add a function to return the list of edges in a graph * Also adds an Edge type * Updated the CHANGELOG * CHANGELOG formatting * Remove dependency on purescript-tailrec * Remove unused toMap import in test/Main.purs * Correctly export Edge constructor * Replace custom tail-recursive function with foldlWithIndex Thanks @JordanMartinez * Implement Edge suggestion from @JordanMartinez * Switch Edge type from a Tuple of newtypes to a record
1 parent 90873fc commit c0a9fe4

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Notable changes to this project are documented in this file. The format is based
77
Breaking changes:
88

99
New features:
10+
- Added an `edges` function that returns a list of all edges in the graph (#17 by @MaybeJustJames)
11+
- Added `toMap` to unwrap `Graph` (#18)
1012

1113
Bugfixes:
1214

@@ -19,7 +21,6 @@ Breaking changes:
1921

2022
New features:
2123
- Added `Foldable` and `Traversable` instances for `Graph` (#16 by @MaybeJustJames)
22-
- Added `toMap` to unwrap `Graph` (#18)
2324

2425
Bugfixes:
2526

src/Data/Graph.purs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,25 @@
22

33
module Data.Graph
44
( Graph
5+
, Edge
56
, unfoldGraph
67
, fromMap
78
, toMap
89
, vertices
10+
, edges
911
, lookup
1012
, outEdges
1113
, topologicalSort
1214
) where
1315

1416
import Prelude
17+
1518
import Data.Bifunctor (lmap)
1619
import Data.CatList (CatList)
1720
import Data.CatList as CL
1821
import Data.Foldable (class Foldable, foldl, foldr, foldMap)
19-
import Data.List (List(..))
22+
import Data.FoldableWithIndex (foldlWithIndex)
23+
import Data.List (List(..), (:))
2024
import Data.List as L
2125
import Data.Map (Map)
2226
import Data.Map as M
@@ -42,6 +46,9 @@ instance traversableGraph :: Traversable (Graph k) where
4246
traverse f (Graph m) = Graph <$> (traverse (\(v /\ ks) -> (_ /\ ks) <$> (f v)) m)
4347
sequence = traverse identity
4448

49+
-- | An Edge between 2 nodes in a Graph
50+
type Edge k = { start :: k, end :: k }
51+
4552
-- | Unfold a `Graph` from a collection of keys and functions which label keys
4653
-- | and specify out-edges.
4754
unfoldGraph
@@ -54,9 +61,9 @@ unfoldGraph
5461
-> (k -> v)
5562
-> (k -> out k)
5663
-> Graph k v
57-
unfoldGraph ks label edges =
64+
unfoldGraph ks label theEdges =
5865
Graph (M.fromFoldable (map (\k ->
59-
Tuple k (Tuple (label k) (L.fromFoldable (edges k)))) ks))
66+
Tuple k (Tuple (label k) (L.fromFoldable (theEdges k)))) ks))
6067

6168
-- | Create a `Graph` from a `Map` which maps vertices to their labels and
6269
-- | outgoing edges.
@@ -72,6 +79,17 @@ toMap (Graph g) = g
7279
vertices :: forall k v. Graph k v -> List v
7380
vertices (Graph g) = map fst (M.values g)
7481

82+
-- | List all edges in a graph
83+
edges :: forall k v. Graph k v -> List (Edge k)
84+
edges (Graph g) = foldlWithIndex edges' Nil g
85+
where
86+
edges' :: k -> List (Edge k) -> Tuple v (List k) -> List (Edge k)
87+
edges' src acc (_ /\ dests) =
88+
foldl (mkEdge src) acc dests
89+
90+
mkEdge :: k -> List (Edge k) -> k -> List (Edge k)
91+
mkEdge src acc dest = { start: src, end: dest } : acc
92+
7593
-- | Lookup a vertex by its key.
7694
lookup :: forall k v. Ord k => k -> Graph k v -> Maybe v
7795
lookup k (Graph g) = map fst (M.lookup k g)

test/Main.purs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,54 @@ module Test.Main where
22

33
import Prelude
44

5-
import Effect (Effect, foreachE)
6-
import Effect.Console (logShow)
75
import Data.Foldable (foldr)
6+
import Data.Graph (Graph, Edge, edges, fromMap, unfoldGraph, topologicalSort)
7+
import Data.List (filter, length, toUnfoldable, range, (:), List(Nil))
8+
import Data.Map (Map)
9+
import Data.Map as M
810
import Data.Maybe (Maybe(Just))
911
import Data.Traversable (traverse)
10-
import Data.Graph (Graph, unfoldGraph, topologicalSort)
11-
import Data.List (filter, toUnfoldable, range, (:), List(Nil))
12+
import Data.Tuple (Tuple)
13+
import Data.Tuple.Nested ((/\))
14+
import Effect (Effect, foreachE)
15+
import Effect.Console (logShow)
16+
17+
-- An example graph:
18+
-- 0
19+
-- / \
20+
-- 1 2
21+
-- \/
22+
-- 3
23+
24+
example1 :: Graph Int Int
25+
example1 =
26+
fromMap example1'
27+
where
28+
example1' :: Map Int (Tuple Int (List Int))
29+
example1' =
30+
M.fromFoldable
31+
[ (0 /\ (0 /\ (1 : 2 : Nil)))
32+
, (1 /\ (1 /\ (3 : Nil)))
33+
, (2 /\ (2 /\ (3 : Nil)))
34+
, (3 /\ (3 /\ Nil))
35+
]
36+
37+
showEdge :: forall k. Show k => Edge k -> String
38+
showEdge { start, end } =
39+
"(" <> show start <> " --> " <> show end <> ")"
1240

1341
main :: Effect Unit
1442
main = do
15-
let double x | x * 2 < 100000 = [x * 2]
16-
| otherwise = []
17-
graph :: Graph Int Int
18-
graph = unfoldGraph (range 1 100000) identity double
43+
let
44+
double x
45+
| x * 2 < 100000 = [ x * 2 ]
46+
| otherwise = []
47+
48+
graph :: Graph Int Int
49+
graph = unfoldGraph (range 1 100000) identity double
1950
foreachE (toUnfoldable (topologicalSort graph)) logShow
2051
logShow
2152
$ filter (_ /= 0) <<< foldr (:) Nil
22-
<$> traverse (\n -> if n `mod` 2 == 0 then Just 0 else Just n) graph
23-
53+
<$> traverse (\n -> if n `mod` 2 == 0 then Just 0 else Just n) graph
54+
logShow (length (edges graph))
55+
logShow $ map showEdge $ edges example1

0 commit comments

Comments
 (0)