Removing the default grouping clause from the SQL-like comprehension notation ;
authorGeorge Giorgidze <giorgidze@gmail.com>
Wed, 2 Nov 2011 22:43:36 +0000 (23:43 +0100)
committerSimon Peyton Jones <simonpj@microsoft.com>
Thu, 17 Nov 2011 08:38:31 +0000 (08:38 +0000)
compiler/hsSyn/HsExpr.lhs
compiler/hsSyn/HsUtils.lhs
compiler/parser/Parser.y.pp
compiler/prelude/PrelNames.lhs
compiler/rename/RnExpr.lhs
compiler/typecheck/TcMatches.lhs
docs/users_guide/glasgow_exts.xml

index 7b814e1..af2de9f 100644 (file)
@@ -943,12 +943,8 @@ data StmtLR idL idR
   deriving (Data, Typeable)
 
 data TransForm  -- The 'f' below is the 'using' function, 'e' is the by function
-  = ThenForm    -- then f          or    then f by e        (depending on trS_by)
-  | GroupFormU  -- group using f   or    group using f by e (depending on trS_by)
-  | GroupFormB   -- group by e  
-      -- In the GroupByFormB, trS_using is filled in with
-      --    'groupWith' (list comprehensions) or 
-      --    'groupM' (monad comprehensions)
+  = ThenForm     -- then f               or    then f by e             (depending on trS_by)
+  | GroupForm     -- then group using f   or    then group by e using f (depending on trS_by)
   deriving (Data, Typeable)
 \end{code}
 
@@ -1078,12 +1074,7 @@ expressions:
    =>
   guard exp >> [ body | stmts ]
 
-Grouping/parallel statements require the 'Control.Monad.Group.groupM' and
-'Control.Monad.Zip.mzip' functions:
-
-  [ body | stmts, then group by e, rest]
-   =>
-  groupM [ body | stmts ] >>= \bndrs -> [ body | rest ]
+Parallel statements require the 'Control.Monad.Zip.mzip' function:
 
   [ body | stmts1 | stmts2 | .. ]
    =>
@@ -1126,9 +1117,7 @@ pprTransStmt :: OutputableBndr id => Maybe (LHsExpr id)
                                  -> SDoc
 pprTransStmt by using ThenForm
   = sep [ ptext (sLit "then"), nest 2 (ppr using), nest 2 (pprBy by)]
-pprTransStmt by _ GroupFormB
-  = sep [ ptext (sLit "then group"), nest 2 (pprBy by) ]
-pprTransStmt by using GroupFormU
+pprTransStmt by using GroupForm
   = sep [ ptext (sLit "then group"), nest 2 (pprBy by), nest 2 (ptext (sLit "using") <+> ppr using)]
 
 pprBy :: OutputableBndr id => Maybe (LHsExpr id) -> SDoc
index 207c2bc..358f8bb 100644 (file)
@@ -51,7 +51,7 @@ module HsUtils(
 
   -- Stmts
   mkTransformStmt, mkTransformByStmt, mkExprStmt, mkBindStmt, mkLastStmt,
-  emptyTransStmt, mkGroupUsingStmt, mkGroupByStmt, mkGroupByUsingStmt, 
+  emptyTransStmt, mkGroupUsingStmt, mkGroupByUsingStmt, 
   emptyRecStmt, mkRecStmt, 
 
   -- Template Haskell
@@ -243,10 +243,9 @@ mkHsIf c a b = HsIf (Just noSyntaxExpr) c a b
 mkNPat lit neg     = NPat lit neg noSyntaxExpr
 mkNPlusKPat id lit = NPlusKPat id lit noSyntaxExpr noSyntaxExpr
 
-mkTransformStmt   :: [LStmt idL] -> LHsExpr idR                -> StmtLR idL idR
-mkTransformByStmt :: [LStmt idL] -> LHsExpr idR -> LHsExpr idR -> StmtLR idL idR
+mkTransformStmt    :: [LStmt idL] -> LHsExpr idR                -> StmtLR idL idR
+mkTransformByStmt  :: [LStmt idL] -> LHsExpr idR -> LHsExpr idR -> StmtLR idL idR
 mkGroupUsingStmt   :: [LStmt idL]                -> LHsExpr idR -> StmtLR idL idR
-mkGroupByStmt      :: [LStmt idL] -> LHsExpr idR                -> StmtLR idL idR
 mkGroupByUsingStmt :: [LStmt idL] -> LHsExpr idR -> LHsExpr idR -> StmtLR idL idR
 
 emptyTransStmt :: StmtLR idL idR
@@ -254,12 +253,10 @@ emptyTransStmt = TransStmt { trS_form = undefined, trS_stmts = [], trS_bndrs = [
                            , trS_by = Nothing, trS_using = noLoc noSyntaxExpr
                            , trS_ret = noSyntaxExpr, trS_bind = noSyntaxExpr
                            , trS_fmap = noSyntaxExpr }
-mkTransformStmt   ss u    = emptyTransStmt { trS_form = ThenForm, trS_stmts = ss, trS_using = u }
-mkTransformByStmt ss u b  = emptyTransStmt { trS_form = ThenForm, trS_stmts = ss, trS_using = u, trS_by = Just b }
-mkGroupByStmt      ss b   = emptyTransStmt { trS_form = GroupFormB, trS_stmts = ss, trS_by = Just b }
-mkGroupUsingStmt   ss u   = emptyTransStmt { trS_form = GroupFormU, trS_stmts = ss, trS_using = u }
-mkGroupByUsingStmt ss b u = emptyTransStmt { trS_form = GroupFormU, trS_stmts = ss
-                                           , trS_by = Just b, trS_using = u }
+mkTransformStmt    ss u   = emptyTransStmt { trS_form = ThenForm,  trS_stmts = ss, trS_using = u }
+mkTransformByStmt  ss u b = emptyTransStmt { trS_form = ThenForm,  trS_stmts = ss, trS_using = u, trS_by = Just b }
+mkGroupUsingStmt   ss u   = emptyTransStmt { trS_form = GroupForm, trS_stmts = ss, trS_using = u }
+mkGroupByUsingStmt ss b u = emptyTransStmt { trS_form = GroupForm, trS_stmts = ss, trS_using = u, trS_by = Just b }
 
 mkLastStmt expr            = LastStmt expr noSyntaxExpr
 mkExprStmt expr            = ExprStmt expr noSyntaxExpr noSyntaxExpr placeHolderType
index b7b024a..0701b9f 100644 (file)
@@ -1584,22 +1584,16 @@ squals :: { Located [LStmt RdrName] }   -- In reverse order, because the last
 
 transformqual :: { Located ([LStmt RdrName] -> Stmt RdrName) }
                         -- Function is applied to a list of stmts *in order*
-    : 'then' exp                { LL $ \leftStmts -> (mkTransformStmt leftStmts $2) }
-    -- >>>
-    | 'then' exp 'by' exp       { LL $ \leftStmts -> (mkTransformByStmt leftStmts $2 $4) }
-    | 'then' 'group' 'by' exp   { LL $ \leftStmts -> (mkGroupByStmt leftStmts $4) }
-    -- <<<
-    -- These two productions deliberately have a shift-reduce conflict. I have made 'group' into a special_id,
-    -- which means you can enable TransformListComp while still using Data.List.group. However, this makes the two
-    -- productions ambiguous. I've set things up so that Happy chooses to resolve the conflict in that case by
-    -- choosing the "group by" variant, which is what we want.
-    --
-    -- This is rather dubious: the user might be confused as to how to parse this statement. However, it is a good
-    -- practical choice. NB: Data.List.group :: [a] -> [[a]], so using the first production would not even type check
-    -- if /that/ is the group function we conflict with.
-    | 'then' 'group' 'using' exp           { LL $ \leftStmts -> (mkGroupUsingStmt leftStmts $4) }
+    : 'then' exp                           { LL $ \leftStmts -> (mkTransformStmt    leftStmts $2)    }
+    | 'then' exp 'by' exp                  { LL $ \leftStmts -> (mkTransformByStmt  leftStmts $2 $4) }
+    | 'then' 'group' 'using' exp           { LL $ \leftStmts -> (mkGroupUsingStmt   leftStmts $4)    }
     | 'then' 'group' 'by' exp 'using' exp  { LL $ \leftStmts -> (mkGroupByUsingStmt leftStmts $4 $6) }
 
+-- Note that 'group' is a special_id, which means that you can enable
+-- TransformListComp while still using Data.List.group. However, this
+-- introduces a shift/reduce conflict. Happy chooses to resolve the conflict
+-- in by choosing the "group by" variant, which is what we want.
+
 -----------------------------------------------------------------------------
 -- Parallel array expressions
 
index cd6a621..319227b 100644 (file)
@@ -292,7 +292,6 @@ basicKnownKeyNames
         -- Monad comprehensions
         , guardMName
         , liftMName
-        , groupMName
         , mzipName
     ]
 
@@ -328,7 +327,7 @@ gHC_PRIM, gHC_TYPES, gHC_GENERICS,
     gHC_CONC, gHC_IO, gHC_IO_Exception,
     gHC_ST, gHC_ARR, gHC_STABLE, gHC_PTR, gHC_ERR, gHC_REAL,
     gHC_FLOAT, gHC_TOP_HANDLER, sYSTEM_IO, dYNAMIC, tYPEABLE, tYPEABLE_INTERNAL, gENERICS,
-    dOTNET, rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_GROUP, mONAD_ZIP,
+    dOTNET, rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_ZIP,
     aRROW, cONTROL_APPLICATIVE, gHC_DESUGAR, rANDOM, gHC_EXTS,
     cONTROL_EXCEPTION_BASE :: Module
 
@@ -375,7 +374,6 @@ gHC_INT         = mkBaseModule (fsLit "GHC.Int")
 gHC_WORD        = mkBaseModule (fsLit "GHC.Word")
 mONAD           = mkBaseModule (fsLit "Control.Monad")
 mONAD_FIX       = mkBaseModule (fsLit "Control.Monad.Fix")
-mONAD_GROUP     = mkBaseModule (fsLit "Control.Monad.Group")
 mONAD_ZIP       = mkBaseModule (fsLit "Control.Monad.Zip")
 aRROW           = mkBaseModule (fsLit "Control.Arrow")
 cONTROL_APPLICATIVE = mkBaseModule (fsLit "Control.Applicative")
@@ -1007,10 +1005,9 @@ choiceAName        = varQual aRROW (fsLit "|||")          choiceAIdKey
 loopAName          = varQual aRROW (fsLit "loop")  loopAIdKey
 
 -- Monad comprehensions
-guardMName, liftMName, groupMName, mzipName :: Name
+guardMName, liftMName, mzipName :: Name
 guardMName         = varQual mONAD (fsLit "guard") guardMIdKey
 liftMName          = varQual mONAD (fsLit "liftM") liftMIdKey
-groupMName         = varQual mONAD_GROUP (fsLit "mgroupWith") groupMIdKey
 mzipName           = varQual mONAD_ZIP (fsLit "mzip") mzipIdKey
 
 
@@ -1578,11 +1575,10 @@ toIntegerClassOpKey  = mkPreludeMiscIdUnique 192
 toRationalClassOpKey = mkPreludeMiscIdUnique 193
 
 -- Monad comprehensions
-guardMIdKey, liftMIdKey, groupMIdKey, mzipIdKey :: Unique
+guardMIdKey, liftMIdKey, mzipIdKey :: Unique
 guardMIdKey     = mkPreludeMiscIdUnique 194
 liftMIdKey      = mkPreludeMiscIdUnique 195
-groupMIdKey     = mkPreludeMiscIdUnique 196
-mzipIdKey       = mkPreludeMiscIdUnique 197
+mzipIdKey       = mkPreludeMiscIdUnique 196
 
 
 ---------------- Template Haskell -------------------
index d73f7c6..0487733 100644 (file)
@@ -779,13 +779,10 @@ rnStmt ctxt (L loc (ParStmt segs _ _ _)) thing_inside
 rnStmt ctxt (L loc (TransStmt { trS_stmts = stmts, trS_by = by, trS_form = form
                               , trS_using = using })) thing_inside
   = do { -- Rename the 'using' expression in the context before the transform is begun
-         (using', fvs1) <- case form of
-                             GroupFormB -> do { (e,fvs) <- lookupStmtName ctxt groupMName
-                                              ; return (noLoc e, fvs) }
-                            _          -> rnLExpr using
+         (using', fvs1) <- rnLExpr using
 
          -- Rename the stmts and the 'by' expression
-        -- Keep track of the variables mentioned in the 'by' expression
+         -- Keep track of the variables mentioned in the 'by' expression
        ; ((stmts', (by', used_bndrs, thing)), fvs2) 
              <- rnStmts (TransStmtCtxt ctxt) stmts $ \ bndrs ->
                 do { (by',   fvs_by) <- mapMaybeFvRn rnLExpr by
index cb16fb3..4aa19ae 100644 (file)
@@ -540,8 +540,6 @@ tcMcStmt _ (ExprStmt rhs then_op guard_op _) res_ty thing_inside
 
 -- Grouping statements
 --
---   [ body | stmts, then group by e ]
---     ->  e :: t
 --   [ body | stmts, then group by e using f ]
 --     ->  e :: t
 --         f :: forall a. (a -> t) -> m a -> m (m a)
index 8026c85..c6d4888 100644 (file)
@@ -1087,7 +1087,7 @@ employees = [ ("Simon", "MS", 80)
 
 output = [ (the dept, sum salary)
 | (name, dept, salary) &lt;- employees
-, then group by dept
+, then group by dept using groupWith
 , then sortWith by (sum salary)
 , then take 5 ]
 </programlisting>
@@ -1099,8 +1099,8 @@ In this example, the list <literal>output</literal> would take on
 </programlisting>
 </para>
 <para>There are three new keywords: <literal>group</literal>, <literal>by</literal>, and <literal>using</literal>.
-(The function <literal>sortWith</literal> is not a keyword; it is an ordinary
-function that is exported by <literal>GHC.Exts</literal>.)</para>
+(The functions <literal>sortWith</literal> and <literal>groupWith</literal> are not keywords; they are ordinary
+functions that are exported by <literal>GHC.Exts</literal>.)</para>
 
 <para>There are five new forms of comprehension qualifier,
 all introduced by the (existing) keyword <literal>then</literal>:
@@ -1179,21 +1179,6 @@ output = [ (the x, y)
     <listitem>
 
 <programlisting>
-then group by e
-</programlisting>
-
-    <para>This form of grouping is essentially the same as the one described above. However,
-    since no function to use for the grouping has been supplied it will fall back on the
-    <literal>groupWith</literal> function defined in
-    <ulink url="&libraryBaseLocation;/GHC-Exts.html"><literal>GHC.Exts</literal></ulink>. This
-    is the form of the group statement that we made use of in the opening example.</para>
-
-    </listitem>
-
-
-    <listitem>
-
-<programlisting>
 then group using f
 </programlisting>
 
@@ -1305,34 +1290,10 @@ do (x,y) &lt;- take 2 (do x &lt;- [1..10]
             </para>
 
 <programlisting>
-[ x | x &lt;- [1,1,2,2,3], then group by x ]
 [ x | x &lt;- [1,1,2,2,3], then group by x using GHC.Exts.groupWith ]
 [ x | x &lt;- [1,1,2,2,3], then group using myGroup ]
 </programlisting>
 
-            <para>
-                The basic <literal>then group by e</literal> statement is
-                translated using the <literal>mgroupWith</literal> function, which
-                requires a <literal>MonadGroup</literal> instance, defined in
-                <ulink url="&libraryBaseLocation;/Control-Monad-Group.html"><literal>Control.Monad.Group</literal></ulink>:
-            </para>
-
-<programlisting>
-do x &lt;- mgroupWith (do x &lt;- [1,1,2,2,3]
-                       return x)
-   return x
-</programlisting>
-
-            <para>
-                Note that the type of <literal>x</literal> is changed by the
-                grouping statement.
-            </para>
-
-            <para>
-                The grouping function can also be defined with the
-                <literal>using</literal> keyword.
-            </para>
-
         </listitem>
         <listitem>
             <para>
@@ -1390,7 +1351,7 @@ Lists of qualifiers: Q,R,S
 
 -- Basic forms
 D[ e | ]               = return e
-D[ e | p &lt;- e, Q ]     = e &gt;&gt;= \p -&gt; D[ e | Q ]
+D[ e | p &lt;- e, Q ]  = e &gt;&gt;= \p -&gt; D[ e | Q ]
 D[ e | e, Q ]          = guard e &gt;&gt; \p -&gt; D[ e | Q ]
 D[ e | let d, Q ]      = let d in D[ e | Q ]
 
@@ -1406,8 +1367,6 @@ D[ e | Q then group using f, R ]      = f D[ Qv | Q ] &gt;&gt;= \ys -&gt;
                                         case (fmap selQv1 ys, ..., fmap selQvn ys) of
                                             Qv -&gt; D[ e | R ]
 
-D[ e | Q then group by b, R ]         = D[ e | Q then group by b using mgroupWith, R ]
-
 D[ e | Q then group by b using f, R ] = f (\Qv -&gt; b) D[ Qv | Q ] &gt;&gt;= \ys -&gt;
                                         case (fmap selQv1 ys, ..., fmap selQvn ys) of
                                            Qv -&gt; D[ e | R ]
@@ -1422,7 +1381,6 @@ return       GHC.Base               t1 -&gt; m t2
 (&gt;&gt;)         GHC.Base               m1 t1 -&gt; m2 t2         -&gt; m3 t3
 guard        Control.Monad          t1 -&gt; m t2
 fmap         GHC.Base               forall a b. (a-&gt;b) -&gt; n a -&gt; n b
-mgroupWith   Control.Monad.Group    forall a. (a -&gt; t) -&gt; m1 a -&gt; m2 (n a)
 mzip         Control.Monad.Zip      forall a b. m a -&gt; m b -&gt; m (a,b)
 </programlisting>
 The comprehension should typecheck when its desugaring would typecheck.