-
Notifications
You must be signed in to change notification settings - Fork 25
Ordered maps #298
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
base: master
Are you sure you want to change the base?
Ordered maps #298
Conversation
First implementation of Ordered Map and Ordered Set
Small changes to address my mistakes in naming.
First implementation of queues based on implementation of Hood Melville queues from "Purely Functional Data Structures" Chris Okasaki.
Little correction of definitions.
Final touches before merge
… other things to understand what is going on in RedBlackTree
fb83300 to
6acd9b2
Compare
6acd9b2 to
4285976
Compare
4285976 to
be71b7a
Compare
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 have worked through this PR. Everything is much better then it used to be and hopefully soon everything will be ready. I have some minor issues. My comments apply to entire codebase, I simply didn't want to flood this discussion with repeated comments.
Interface is well polished. I suggest to do some name changes: member to mem and domain to keyList. Other than that, it is all fine.
Documentation requires overhaul. All sentences must start with capital letters and end with periods. Also docstrings need update. We don't support @brief label.
|
|
||
| pub data Either X Y = Left of X | Right of Y | ||
|
|
||
| pub data Ord = Lt | Eq | Gt |
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.
Please, add show method for this datatype.
| pub data Map Key = Map of { | ||
| T | ||
|
|
||
| {## @brief Creates empty map |
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.
We don't support @brief label. Simply write this statement and add a period at the end.
| , empty : {Val} -> T Val | ||
|
|
||
| {## @brief Method to testing whether given map is empty or not | ||
| # @return True if it's empty false otherwise |
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.
Don't add those # symbols in the middle of docstrings.
|
|
||
| # Basic tests | ||
| let _ = | ||
| assert (IntMap.empty {Val=Bool} >.isEmpty); |
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.
Tests could be modernized to use the new testing framework.
| , method foldr = mapFoldr | ||
| , method toList = toListT | ||
| , method toValueList = toValueListT | ||
| , method domain = domainT |
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.
This naming is inconsistent. We either stick to domain/codomain or values/keys. I prefer latter honestly
| , method insertChange = insertChangeT | ||
| , method remove = removeT | ||
| , method removeChange = removeChangeT | ||
| , method member = memberT |
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.
Lists already uses mem, so I think it should be used here as well
| each internal node has either two or three children, and all leaves are at the | ||
| same depth. Interestingly, the latter invariant is enforced by types, using | ||
| nested datatypes approach. To do so, we define the following two types. | ||
| # Due to frequent request for understanding this file please |
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.
This bit needs to be rewritten. Don't announce any "popular demand", simply mention that the algorithm based on some resarch papers and enumerate them. It will be much more natural
| | Black => | ||
| match child with | ||
| | Node {value} => | ||
| # Must be RED with Leaf children, by black-height invariant. |
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.
Some assertion to test this invariant would be nice
| | Right colorLeftMin leftLeftMin valueLeftMin :: zipperr => | ||
| deleteNearLeaf colorLeftMin leftLeftMin | ||
| (List.append zipperr (Left color valueLeftMin right :: zipper)) | ||
| | _ => Leaf #Fail "postcondition" |
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.
Does it really fail or is just misplaced comment?
| | Left colorRightMin valueRightMin rightRightMin :: zipperr => | ||
| deleteNearLeaf colorRightMin rightRightMin | ||
| (List.append zipperr (Right color left valueRightMin :: zipper)) | ||
| | _ => Leaf #Fail "postcondition" |
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.
ditto
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.
Pull request overview
This PR implements ordered maps using a red-black tree data structure, replacing the previous 2-3 tree implementation. The changes introduce a complete rewrite of the Map module with new API methods and update the comparison interface from separate equal and lt methods to a unified compare method returning an Ord type.
Key changes:
- Complete reimplementation of Map using red-black trees instead of 2-3 trees
- Introduction of
Ordtype (Lt, Eq, Gt) for comparisons - API updates including renamed methods (
add→insert,mem→member,fold→foldl) and new operations (union,update,mapVal, etc.)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/Map.fram | Complete rewrite implementing red-black tree-based ordered maps with new API |
| lib/Base/Types.fram | Added Ord data type for three-way comparisons |
| lib/Base/Int.fram | Added compare method to Int type |
| lib/Base/String.fram | Added compare method to String type |
| lib/Testing.fram | Updated to use new Map API (add → insert, removed {key} syntax) |
| test/stdlib/stdlib0008_Map.fram | Updated test suite with new API methods and added comprehensive test cases |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # let compareI (x : Int) (y : Int) = if x < y then Lt else if x > y then Gt else Eq | ||
| # let compareS (x : String) (y : String) = if x < y then Lt else if x > y then Gt else Eq | ||
|
|
Copilot
AI
Dec 18, 2025
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.
Commented-out code should be removed. If these comparison functions are intended as examples or documentation, they should be uncommented or moved to proper documentation.
| # let compareI (x : Int) (y : Int) = if x < y then Lt else if x > y then Gt else Eq | |
| # let compareS (x : String) (y : String) = if x < y then Lt else if x > y then Gt else Eq |
| let (Map { module IntMap }) = Map.make {Key = Int} | ||
| let (Map { module StrMap }) = Map.make {Key = String} |
Copilot
AI
Dec 18, 2025
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.
Inconsistent spacing in record syntax. Consider using consistent spacing: either {Key = Int} for both or {Key=Int} for both to match the style used elsewhere in the file.
| # Organizes all registered tests into a tree structure | ||
| let Map {module SMap} = Map.make {Key=String} | ||
|
|
||
| let Map {module SMap} = Map.make {String} |
Copilot
AI
Dec 18, 2025
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.
The Map.make call uses positional syntax {String} instead of the named parameter syntax {Key = String} used elsewhere. This is inconsistent with the API design shown in other files and may be confusing.
| let Map {module SMap} = Map.make {String} | |
| let Map {module SMap} = Map.make {Key = String} |
| match ar with | ||
| | AR_Ok repr => Tree repr | ||
| | AR_Split l k v r => Succ (Tree (Node2 l k v r)) | ||
| # serachMin finds smallest element in a tree and builds zipper |
Copilot
AI
Dec 18, 2025
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.
Corrected spelling of 'serach' to 'search'.
| match rr with | ||
| | RR_Ok node => Succ (Tree node) | ||
| | RR_Underflow repr => Tree repr | ||
| # serachMax finds largest element in a tree and builds zipper |
Copilot
AI
Dec 18, 2025
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.
Corrected spelling of 'serach' to 'search'.
|
|
||
| # The father is red and no nephew is red. | ||
| # Then father becomes black and brother becomes red | ||
| # removing therfore the inequality of blackness. |
Copilot
AI
Dec 18, 2025
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.
Corrected spelling of 'therfore' to 'therefore'.
|
|
||
| # The father is red and no nephew is red. | ||
| # Then father becomes black and brother becomes red | ||
| # removing therfore the inequality of blackness. |
Copilot
AI
Dec 18, 2025
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.
Corrected spelling of 'therfore' to 'therefore'.
| | Right colorLeftMin leftLeftMin valueLeftMin :: zipperr => | ||
| deleteNearLeaf colorLeftMin leftLeftMin | ||
| (List.append zipperr (Left color valueLeftMin right :: zipper)) | ||
| | _ => Leaf #Fail "postcondition" |
Copilot
AI
Dec 18, 2025
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.
The error handling here is unclear. The comment suggests a postcondition failure, but returning Leaf silently hides this error condition. Consider using a proper error mechanism or at minimum improving the error message to explain what postcondition failed.
| | Left colorRightMin valueRightMin rightRightMin :: zipperr => | ||
| deleteNearLeaf colorRightMin rightRightMin | ||
| (List.append zipperr (Right color left valueRightMin :: zipper)) | ||
| | _ => Leaf #Fail "postcondition" |
Copilot
AI
Dec 18, 2025
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.
The error handling here is unclear. The comment suggests a postcondition failure, but returning Leaf silently hides this error condition. Consider using a proper error mechanism or at minimum improving the error message to explain what postcondition failed.
This is full implementation of Ordered Maps, and it is also a continuation of Pull Request #136 and #288 .