-
Notifications
You must be signed in to change notification settings - Fork 10
Add a function to return the list of edges in a graph #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
I think this shouldn't add a dependency on |
|
@JordanMartinez that was significantly easier than I expected. I also exposed the |
| unfoldGraph ks label theEdges = | ||
| Graph (M.fromFoldable (map (\k -> | ||
| Tuple k (Tuple (label k) (L.fromFoldable (edges k)))) ks)) | ||
| Tuple k (Tuple (label k) (L.fromFoldable (theEdges k)))) ks)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you revert these two changes since they're not relevant to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 changes are to avoid shadowing the edges name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Makes sense. Ok.
| -- | List all edges in a graph | ||
| edges :: forall k v. Graph k v -> List (Edge k) | ||
| edges (Graph g) = go initialState | ||
| where | ||
| go :: EdgesState k v -> List (Edge k) | ||
| go { unvisited: Nil, result: res } = res | ||
| go { unvisited: (src /\ (_ /\ dests)) : ns, result: res } = | ||
| go | ||
| { unvisited: ns | ||
| , result: map (Edge <<< (src /\ _)) dests <> res | ||
| } | ||
|
|
||
| initialState :: EdgesState k v | ||
| initialState = | ||
| { unvisited: M.toUnfoldableUnordered g | ||
| , result: Nil | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this is slow for a few reasons.
First, you're using List and you have at least two traversals over dests:
map (Edge <<< (src /\ _)) dests: 1 traversal to create a new version of the list(map _ dests) <> res: 1 traversal appending the result ofmap _ deststores. See https://github.com/JordanMartinez/purescript-jordans-reference/blob/latestRelease/21-Hello-World/05-Application-Structure/src/03-Free/01-What-Is-The-Free-Monad/04-The-Remorseless-Free-Monad.md#the-direction-matters for context.
A faster solution would to fold over dests and cons the src and destination onto res in one fold:
result: foldl (\acc dest -> Edge (src /\ dest) : acc) res destsSecond, for initialState, why convert the Map to a List in the first place via M.toUnfoldableUnordered? That traverses the map once and then you traverse the map a second time in go via the unvisited field. Since Graph is just a newtype around Map and Map has an instance for FoldableWithIndex, couldn't this same key-value information be obtained with foldlWithIndex using a single traversal rather than two as it currently does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow! I did not notice that at all. Thank you for taking the time to explain this all to me so clearly :)
As you mentioned I've replaced the custom function with foldlWithIndex (which traverses the Map once) and a foldl for each list of edge endpoints. So I cannot see any redundant traversals now.
src/Data/Graph.purs
Outdated
| sequence = traverse identity | ||
|
|
||
| -- | An edge within a `Graph` referencing endpoint keys | ||
| newtype Edge k = Edge (Tuple k k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than defining an edge, it may be more helpful to define a newtype indicating which value inside the Tuple is the source and which is the destination. For example:
-newtype Edge k = Edge (Tuple k k)
+Tuple (Source k) (Destination k)I'm not sure what the best API would be here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented this. I don't think it's any less ergonomic and, as you say, prevents mixing up source and destination. What do you think? Is this what you meant?
JordanMartinez
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM besides the changelog issue.
|
|
||
| New features: | ||
| - Added `Foldable` and `Traversable` instances for `Graph` (#16 by @MaybeJustJames) | ||
| - Added `toMap` to unwrap `Graph` (#18) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you put this back into the correct spot in the changelog?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this because it hasn't been released. Would you prefer a separate PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my bad. No, let's just fix it here.
|
Can this be merged? |
|
@garyb Can this get an approval? |
|
Another option here might be to use If we don't want to go that route, then I'd suggest including |
I've just pushed this. It still has the advantage of not mixing up source and destination without needing |
|
🏓 @garyb |
garyb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thanks for making the change!
Adds an
edgesfunction and a correspondingEdgetype.Reasoning for the change:
I had implemented this badly in my own project.
edgesfunctionality is also necessary to implement anEqinstance forGraphif that should be considered (RE #1).Checklist: