-
Notifications
You must be signed in to change notification settings - Fork 181
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
Added HasCallStack to partial functions #493
base: master
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -411,6 +411,9 @@ import qualified Control.Category as Category | |
import Data.Coerce | ||
#endif | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
import GHC.Stack (HasCallStack) | ||
#endif | ||
|
||
{-------------------------------------------------------------------- | ||
Operators | ||
|
@@ -423,7 +426,11 @@ infixl 9 !,!?,\\ -- | |
-- > fromList [(5,'a'), (3,'b')] ! 1 Error: element not in the map | ||
-- > fromList [(5,'a'), (3,'b')] ! 5 == 'a' | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
(!) :: (HasCallStack, Ord k) => Map k a -> k -> a | ||
#else | ||
(!) :: Ord k => Map k a -> k -> a | ||
#endif | ||
(!) m k = find k m | ||
#if __GLASGOW_HASKELL__ | ||
{-# INLINE (!) #-} | ||
|
@@ -1433,7 +1440,11 @@ alterFYoneda = go | |
-- > findIndex 6 (fromList [(5,"a"), (3,"b")]) Error: element is not in the map | ||
|
||
-- See Note: Type of local 'go' function | ||
#if __GLASGOW_HASKELL__ >= 800 | ||
findIndex :: (HasCallStack, Ord k) => k -> Map k a -> Int | ||
#else | ||
findIndex :: Ord k => k -> Map k a -> Int | ||
#endif | ||
findIndex = go 0 | ||
where | ||
go :: Ord k => Int -> k -> Map k a -> Int | ||
|
@@ -1477,7 +1488,11 @@ lookupIndex = go 0 | |
-- > elemAt 1 (fromList [(5,"a"), (3,"b")]) == (5, "a") | ||
-- > elemAt 2 (fromList [(5,"a"), (3,"b")]) Error: index out of range | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
elemAt :: HasCallStack => Int -> Map k a -> (k,a) | ||
#else | ||
elemAt :: Int -> Map k a -> (k,a) | ||
#endif | ||
elemAt !_ Tip = error "Map.elemAt: index out of range" | ||
elemAt i (Bin _ kx x l r) | ||
= case compare i sizeL of | ||
|
@@ -1566,7 +1581,11 @@ splitAt i0 m0 | |
-- > updateAt (\_ _ -> Nothing) 2 (fromList [(5,"a"), (3,"b")]) Error: index out of range | ||
-- > updateAt (\_ _ -> Nothing) (-1) (fromList [(5,"a"), (3,"b")]) Error: index out of range | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
updateAt :: HasCallStack => (k -> a -> Maybe a) -> Int -> Map k a -> Map k a | ||
#else | ||
updateAt :: (k -> a -> Maybe a) -> Int -> Map k a -> Map k a | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better to just make this function total by making an update at a bad index do nothing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is definitely a more interesting question than just where to add |
||
updateAt f !i t = | ||
case t of | ||
Tip -> error "Map.updateAt: index out of range" | ||
|
@@ -1588,7 +1607,11 @@ updateAt f !i t = | |
-- > deleteAt 2 (fromList [(5,"a"), (3,"b")]) Error: index out of range | ||
-- > deleteAt (-1) (fromList [(5,"a"), (3,"b")]) Error: index out of range | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
deleteAt :: HasCallStack => Int -> Map k a -> Map k a | ||
#else | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question here. |
||
deleteAt :: Int -> Map k a -> Map k a | ||
#endif | ||
deleteAt !i t = | ||
case t of | ||
Tip -> error "Map.deleteAt: index out of range" | ||
|
@@ -1624,7 +1647,11 @@ lookupMin (Bin _ k x l _) = Just $! lookupMinSure k x l | |
-- > findMin (fromList [(5,"a"), (3,"b")]) == (3,"b") | ||
-- > findMin empty Error: empty map has no minimal element | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
findMin :: HasCallStack => Map k a -> (k,a) | ||
#else | ||
findMin :: Map k a -> (k,a) | ||
#endif | ||
findMin t | ||
| Just r <- lookupMin t = r | ||
| otherwise = error "Map.findMin: empty map has no minimal element" | ||
|
@@ -1649,7 +1676,11 @@ lookupMax :: Map k a -> Maybe (k, a) | |
lookupMax Tip = Nothing | ||
lookupMax (Bin _ k x _ r) = Just $! lookupMaxSure k x r | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
findMax :: HasCallStack => Map k a -> (k,a) | ||
#else | ||
findMax :: Map k a -> (k,a) | ||
#endif | ||
findMax t | ||
| Just r <- lookupMax t = r | ||
| otherwise = error "Map.findMax: empty map has no maximal element" | ||
|
@@ -3866,7 +3897,11 @@ maxViewSure = go | |
-- > deleteFindMin (fromList [(5,"a"), (3,"b"), (10,"c")]) == ((3,"b"), fromList[(5,"a"), (10,"c")]) | ||
-- > deleteFindMin Error: can not return the minimal element of an empty map | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
deleteFindMin :: HasCallStack => Map k a -> ((k,a),Map k a) | ||
#else | ||
deleteFindMin :: Map k a -> ((k,a),Map k a) | ||
#endif | ||
deleteFindMin t = case minViewWithKey t of | ||
Nothing -> (error "Map.deleteFindMin: can not return the minimal element of an empty map", Tip) | ||
Just res -> res | ||
|
@@ -3876,7 +3911,11 @@ deleteFindMin t = case minViewWithKey t of | |
-- > deleteFindMax (fromList [(5,"a"), (3,"b"), (10,"c")]) == ((10,"c"), fromList [(3,"b"), (5,"a")]) | ||
-- > deleteFindMax empty Error: can not return the maximal element of an empty map | ||
|
||
#if __GLASGOW_HASKELL__ >= 800 | ||
deleteFindMax :: HasCallStack => Map k a -> ((k,a),Map k a) | ||
#else | ||
deleteFindMax :: Map k a -> ((k,a),Map k a) | ||
#endif | ||
deleteFindMax t = case maxViewWithKey t of | ||
Nothing -> (error "Map.deleteFindMax: can not return the maximal element of an empty map", Tip) | ||
Just res -> res | ||
|
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 the call stack grow through the recursion here or elsewhere? If so, that's a big problem. You can check the Core to be sure. We know there are no
Nil
s except at the root, but GHC does not! If the stacks build, you'll need to restructure the functions to fix that. Watch out for performance. If the times for the current benchmarks exercising these functions are too short to trust, consider adding more benchmarks.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, yes it does. I didn't realize it would do that. The fix is to use an internal
go
function. I'll update the PR with that in a moment.On a related note, I realized that my
HasCallStack
forMap.!
was wrong becauseMap.!
callsfind
which actually throws the error. Is there a reason it usesfind
rather thanlookup
? My inclination is to removefind
altogether (it's only used by!
and looks identical other than theMaybe
wrapper) and replace withlookup
---then!
can callerror
itself, which should then makeHasCallStack
work the way we want.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.
Oh, I just noticed the
[Note: Local 'go' functions and capturing]
-- I'll read that and try to make sure I'm not doing anything stupid.