-
Notifications
You must be signed in to change notification settings - Fork 14
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
Reimplement MapWithWithMove
in terms of MapWithPatchingMove
#14
Conversation
Be very careful using newtypes and pattern synnonyms to break as little as possible.
Looks like a haddock or, less likely, GHC bug. Ugh! |
- Do explicit export lists. This is a chore now, but makes managing Compatibility easier later. - Make `MapWithMove`'s `From` a proper newtype. This improves the compatibility and type error situation. - Work around GHC export list bug: the explicit export lists without big reexports this this for us, in fact.
This makes an instance, no new export needed.
- `mplus` -> `mappen` - better coverage
20531ce
to
32a1f2f
Compare
newtype PatchMapWithMove k v = PatchMapWithMove | ||
{ -- | Extract the internal representation of the 'PatchMapWithMove' | ||
unPatchMapWithMove :: Map k (NodeInfo k v) | ||
newtype PatchMapWithMove k (v :: Type) = PatchMapWithMove' |
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.
PolyKinds was mischievously generalizing this over things for which PatchTarget (Proxy v)
is undefined. Oh type families...
-- | ||
-- From | ||
-- | ||
|
||
-- | Describe how a key's new value should be produced | ||
data From k p | ||
= From_Insert (PatchTarget p) -- ^ Insert the given value here | ||
| From_Delete -- ^ Delete the existing value, if any, from here | ||
| From_Move !k !p -- ^ Move the value here from the given key, and apply the given patch | ||
|
||
deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (From k p) | ||
deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (From k p) | ||
deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (From k p) | ||
deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (From k p) | ||
|
||
-- | Traverse the 'From' over the key, patch, and patch target. Because of | ||
-- the type families here, this doesn't it any bi- or tri-traversal class. | ||
bitraverseFrom | ||
:: Applicative f | ||
=> (k0 -> f k1) | ||
-> (p0 -> f p1) | ||
-> (PatchTarget p0 -> f (PatchTarget p1)) | ||
-> From k0 p0 -> f (From k1 p1) | ||
bitraverseFrom fk fp fpt = \case | ||
From_Insert pt -> From_Insert <$> fpt pt | ||
From_Delete -> pure From_Delete | ||
From_Move k p -> From_Move <$> fk k <*> fp p | ||
|
||
-- | ||
-- To | ||
-- | ||
|
||
-- | Describe where a key's old value will go. If this is 'Just', that means | ||
-- the key's old value will be moved to the given other key; if it is 'Nothing', | ||
-- that means it will be deleted. | ||
type To = Maybe | ||
|
||
-- | ||
-- Fixup | ||
-- | ||
|
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 is just rearranging
-- | ||
-- NodeInfo | ||
-- | ||
|
||
-- | Holds the information about each key: where its new value should come from, | ||
-- and where its old value should go to | ||
data NodeInfo k p = NodeInfo | ||
{ _nodeInfo_from :: !(From k p) | ||
-- ^ Where do we get the new value for this key? | ||
, _nodeInfo_to :: !(To k) | ||
-- ^ If the old value is being kept (i.e. moved rather than deleted or | ||
-- replaced), where is it going? | ||
} | ||
deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (NodeInfo k p) | ||
deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (NodeInfo k p) | ||
deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (NodeInfo k p) | ||
deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (NodeInfo k p) | ||
|
||
-- | Traverse the 'NodeInfo' over the key, patch, and patch target. Because of | ||
-- the type families here, this doesn't it any bi- or tri-traversal class. | ||
bitraverseNodeInfo | ||
:: Applicative f | ||
=> (k0 -> f k1) | ||
-> (p0 -> f p1) | ||
-> (PatchTarget p0 -> f (PatchTarget p1)) | ||
-> NodeInfo k0 p0 -> f (NodeInfo k1 p1) | ||
bitraverseNodeInfo fk fp fpt (NodeInfo from to) = NodeInfo | ||
<$> bitraverseFrom fk fp fpt from | ||
<*> traverse fk to | ||
|
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 is just rearranging
-- | Holds the information about each key: where its new value should come from, | ||
-- and where its old value should go to | ||
data NodeInfo k p = NodeInfo | ||
{ _nodeInfo_from :: !(From k p) | ||
-- ^ Where do we get the new value for this key? | ||
, _nodeInfo_to :: !(To k) | ||
-- ^ If the old value is being kept (i.e. moved rather than deleted or | ||
-- replaced), where is it going? | ||
} | ||
deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (NodeInfo k p) | ||
deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (NodeInfo k p) | ||
deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (NodeInfo k p) | ||
deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (NodeInfo k p) | ||
|
||
bitraverseNodeInfo | ||
:: Applicative f | ||
=> (k0 -> f k1) | ||
-> (p0 -> f p1) | ||
-> (PatchTarget p0 -> f (PatchTarget p1)) | ||
-> NodeInfo k0 p0 -> f (NodeInfo k1 p1) | ||
bitraverseNodeInfo fk fp fpt (NodeInfo from to) = NodeInfo | ||
<$> bitraverseFrom fk fp fpt from | ||
<*> traverse fk to | ||
|
||
-- | Describe how a key's new value should be produced | ||
data From k p | ||
= From_Insert (PatchTarget p) -- ^ Insert the given value here | ||
| From_Delete -- ^ Delete the existing value, if any, from here | ||
| From_Move !k !p -- ^ Move the value here from the given key, and apply the given patch | ||
|
||
bitraverseFrom | ||
:: Applicative f | ||
=> (k0 -> f k1) | ||
-> (p0 -> f p1) | ||
-> (PatchTarget p0 -> f (PatchTarget p1)) | ||
-> From k0 p0 -> f (From k1 p1) | ||
bitraverseFrom fk fp fpt = \case | ||
From_Insert pt -> From_Insert <$> fpt pt | ||
From_Delete -> pure From_Delete | ||
From_Move k p -> From_Move <$> fk k <*> fp p | ||
|
||
deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (From k p) | ||
deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (From k p) | ||
deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (From k p) | ||
deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (From k p) | ||
|
||
-- | Describe where a key's old value will go. If this is 'Just', that means | ||
-- the key's old value will be moved to the given other key; if it is 'Nothing', | ||
-- that means it will be deleted. | ||
type To = Maybe | ||
|
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 is just rearranging, see below
- name: Build Docs | ||
run: cabal haddock |
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.
Travis was doing this, so this is a good idea if we want to be able to drop travis.
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.
Looks great!
Per the change log, care is taken so this should not be a breaking change.
I had to to write explicit export lists to get around some obscure GHC bugs with reexport data types twice with different patterns nested for
(..)
imports, but I think it's nicer anyways as it makes comparability easier to check going forward.