-
Notifications
You must be signed in to change notification settings - Fork 291
Human-centric let-rec, constructor and ability orderings #6039
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
Changes from all commits
ff02008
961f442
5d0aed2
d59f737
c8dc49c
b679d75
2d92831
692baca
6e878c1
6b97f7f
28f1f7c
f0321b3
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 |
|---|---|---|
|
|
@@ -2,6 +2,8 @@ module Unison.Util.List where | |
|
|
||
| import Data.List qualified as List | ||
| import Data.List.Extra qualified as List | ||
| import Data.List.NonEmpty (NonEmpty) | ||
| import Data.List.NonEmpty qualified as NEL | ||
| import Data.Map qualified as Map | ||
| import Data.Set qualified as Set | ||
| import Unison.Prelude | ||
|
|
@@ -13,23 +15,23 @@ multimap kvs = | |
| where | ||
| step m (k, v) = Map.insertWith (++) k [v] m | ||
|
|
||
| groupBy :: (Foldable f, Ord k) => (v -> k) -> f v -> Map k [v] | ||
| groupBy f vs = reverse <$> foldl' step Map.empty vs | ||
| groupBy :: (Foldable f, Ord k) => (v -> k) -> f v -> Map k (NonEmpty v) | ||
| groupBy f vs = NEL.reverse <$> foldl' step Map.empty vs | ||
| where | ||
| step m v = Map.insertWith (++) (f v) [v] m | ||
| step m v = Map.insertWith (<>) (f v) (NEL.singleton v) m | ||
|
|
||
| -- | group _consecutive_ elements by a key. | ||
| -- e.g. | ||
| -- >>> groupMap (\n -> (odd n, show n)) [1, 3, 4, 6, 7] | ||
| -- [(True,["1","3"]),(False,["4","6"]),(True,["7"])] | ||
| groupMap :: (Foldable f, Eq k) => (a -> (k, b)) -> f a -> [(k, [b])] | ||
| groupMap :: (Foldable f, Eq k) => (a -> (k, b)) -> f a -> [(k, NonEmpty b)] | ||
| groupMap f xs = | ||
| xs | ||
| & toList | ||
| & fmap f | ||
| & List.groupOn fst | ||
| -- head is okay since groupOn only returns populated lists. | ||
| <&> \grp -> (fst . head $ grp, snd <$> grp) | ||
| <&> \grp -> (fst . head $ grp, NEL.fromList (snd <$> grp)) | ||
|
Member
Author
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. NEL.fromList is partial, but this list is guaranteed to be non-empty. |
||
|
|
||
| -- returns the subset of `f a` which maps to unique `b`s. | ||
| -- prefers earlier copies, if many `a` map to some `b`. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,6 +99,7 @@ module Unison.Codebase.Branch | |
| where | ||
|
|
||
| import Control.Lens hiding (children, cons, transform, uncons) | ||
| import Data.Foldable qualified as Foldable | ||
| import Data.Map qualified as Map | ||
| import Data.Monoid (Any (..)) | ||
| import Data.Semialign qualified as Align | ||
|
|
@@ -508,7 +509,10 @@ batchUpdatesM :: | |
| batchUpdatesM (toList -> actions) curBranch = foldM execActions curBranch (groupActionsByLocation actions) | ||
| where | ||
| groupActionsByLocation :: [(Path, b)] -> [(ActionLocation, [(Path, b)])] | ||
| groupActionsByLocation = List.groupMap \(p, act) -> (pathLocation p, (p, act)) | ||
| groupActionsByLocation xs = | ||
| xs | ||
| & List.groupMap (\(p, act) -> (pathLocation p, (p, act))) | ||
| <&> second Foldable.toList | ||
|
Comment on lines
+512
to
+515
Member
Author
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. Just a tweak to work with the new NonEmpty |
||
|
|
||
| execActions :: | ||
| ( Branch0 m -> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,9 @@ module Unison.Syntax.DeclPrinter | |
| where | ||
|
|
||
| import Control.Monad.Writer (Writer, runWriter, tell) | ||
| import Data.List qualified as List | ||
| import Data.List.NonEmpty (pattern (:|)) | ||
| import Data.List.NonEmpty.Extra qualified as NEL | ||
| import Data.Map qualified as Map | ||
| import Data.Set qualified as Set | ||
| import Data.Text qualified as Text | ||
|
|
@@ -38,6 +40,7 @@ import Unison.Syntax.TypePrinter (runPretty) | |
| import Unison.Syntax.TypePrinter qualified as TypePrinter | ||
| import Unison.Syntax.Var qualified as Var (namespaced) | ||
| import Unison.Type qualified as Type | ||
| import Unison.Util.List qualified as List | ||
| import Unison.Util.Pretty (Pretty) | ||
| import Unison.Util.Pretty qualified as P | ||
| import Unison.Util.SyntaxText qualified as S | ||
|
|
@@ -86,6 +89,7 @@ prettyEffectDecl :: | |
| prettyEffectDecl ppe guid r name = prettyGADT ppe guid CT.Effect r name . toDataDecl | ||
|
|
||
| prettyGADT :: | ||
| forall v a. | ||
| (Var v) => | ||
| PrettyPrintEnvDecl -> | ||
| RenderUniqueTypeGuids -> | ||
|
|
@@ -95,11 +99,12 @@ prettyGADT :: | |
| DataDeclaration v a -> | ||
| Pretty SyntaxText | ||
| prettyGADT env guid ctorType r name dd = | ||
| header <> P.newline <> P.indentN 2 constructors | ||
| header <> P.newline <> P.indentN 2 prettyConstructors | ||
| where | ||
| constructors = P.lines (constructor <$> zip [0 ..] (DD.constructors' dd)) | ||
| constructor (n, (_, _, t)) = | ||
| prettyPattern (PPED.unsuffixifiedPPE env) ctorType name (ConstructorReference r n) | ||
| prettyConstructors = P.lines (printConstructor <$> orderConstructors unsuffixifiedPPE r dd ctorType) | ||
| unsuffixifiedPPE = PPED.unsuffixifiedPPE env | ||
| printConstructor (n, (_, _, t)) = | ||
| prettyPattern unsuffixifiedPPE ctorType name (ConstructorReference r n) | ||
| <> fmt S.TypeAscriptionColon " :" | ||
| `P.hang` TypePrinter.prettySyntax (PPED.suffixifiedPPE env) t | ||
| header = prettyEffectHeader guid name (DD.EffectDeclaration dd) <> fmt S.ControlKeyword " where" | ||
|
|
@@ -122,7 +127,33 @@ prettyPattern env ctorType namespace ref = | |
| where | ||
| conRef = Referent.Con ref ctorType | ||
|
|
||
| -- Order Constructors alphabetically by name, | ||
| -- regardless of their original order in the declaration. | ||
| -- This is both nice for readability and ensures stable output in diffs, since otherwise | ||
| -- constructors will jump around in order based on their hash. | ||
| -- They'll be re-ordered by hash when parsed. | ||
| orderConstructors :: (Var v) => PrettyPrintEnv -> TypeReference -> DataDeclaration v a -> CT.ConstructorType -> [(Word64, (a, v, Type.Type v a))] | ||
| orderConstructors ppe r dd ctype = | ||
| zip [0 ..] (DD.constructors' dd) | ||
| -- First we sort by type to ensure that identical types are adjacent. | ||
| & List.sortOn (\(_n, (_a, _v, typ)) -> typ) | ||
| -- Now we group by type, we need to leave identical types in their constructor order to avoid things like | ||
| -- swapping identical constructors, e.g. False turning into True and vice versa. | ||
| & List.groupMap (\con@(_, (_, _, typ)) -> (typ, con)) | ||
| -- Then we can sort those _groups_ by the name of the first constructor in the group. | ||
| & List.sortOn | ||
| ( \(_typ, group) -> | ||
| group | ||
| & NEL.sortOn fst | ||
| & \case | ||
| (n, (_, _, _)) :| _rest -> | ||
| PPE.termName ppe (Referent.Con (ConstructorReference r n) ctype) | ||
|
Comment on lines
+139
to
+150
Member
Author
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. Here's the tweak Paul suggested :) |
||
| ) | ||
| -- Then we flatten back out to a list of constructors. | ||
| & foldMap (toList . snd) | ||
|
|
||
| prettyDataDecl :: | ||
| forall v a. | ||
| (Var v) => | ||
| PrettyPrintEnvDecl -> | ||
| RenderUniqueTypeGuids -> | ||
|
|
@@ -132,7 +163,7 @@ prettyDataDecl :: | |
| Writer (Set AccessorName) (Pretty SyntaxText) | ||
| prettyDataDecl (PrettyPrintEnvDecl unsuffixifiedPPE suffixifiedPPE) guid r name dd = | ||
| (header <>) . P.sep (fmt S.DelimiterChar (" | " `P.orElse` "\n | ")) | ||
| <$> constructor `traverse` zip [0 ..] (DD.constructors' dd) | ||
| <$> constructor `traverse` (orderConstructors unsuffixifiedPPE r dd CT.Data) | ||
| where | ||
| constructor (n, (_, _, Type.ForallsNamed' _ t)) = constructor' n t | ||
| constructor (n, (_, _, t)) = constructor' n t | ||
|
|
||
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.
Tweaked a few helpers to return NonEmpty because 'make invalid state unrepresentable' and all that :P