Difference between revisions of "Case comprehensions"

From HaskellWiki
Jump to: navigation, search
(Content transferred from "Cases expressions")
 
m (List of examples reformatted)
Line 89: Line 89:
   
 
Still not convinced? Here's some other examples:
 
Still not convinced? Here's some other examples:
<haskell>
 
  +
  +
{|
  +
|
  +
* <haskell>
 
-- ghc-8.6.5/compiler/codeGen/StgCmmMonad.hs, lines 819-827
 
-- ghc-8.6.5/compiler/codeGen/StgCmmMonad.hs, lines 819-827
 
let
 
let
Line 97: Line 100:
 
_ -> (e, tbranch, fbranch, likely)
 
_ -> (e, tbranch, fbranch, likely)
 
</haskell>
 
</haskell>
or:
+
:or:
<haskell>
+
:<haskell>
 
let
 
let
 
(test, then_, else_, likely') =
 
(test, then_, else_, likely') =
Line 106: Line 109:
 
(e, tbranch, fbranch, likely) | otherwise
 
(e, tbranch, fbranch, likely) | otherwise
 
</haskell>
 
</haskell>
  +
|}
   
   
   
<haskell>
 
  +
{|
  +
|
  +
* <haskell>
 
-- ghc-8.6.5/compiler/basicTypes/Demand.hs, lines 927-934
 
-- ghc-8.6.5/compiler/basicTypes/Demand.hs, lines 927-934
 
splitProdDmd_maybe (JD { sd = s, ud = u })
 
splitProdDmd_maybe (JD { sd = s, ud = u })
Line 120: Line 126:
 
_ -> Nothing
 
_ -> Nothing
 
</haskell>
 
</haskell>
or:
+
:or:
<haskell>
+
:<haskell>
 
splitProdDmd_maybe (JD { sd = s, ud = u })
 
splitProdDmd_maybe (JD { sd = s, ud = u })
 
= cases
 
= cases
Line 132: Line 138:
 
Nothing | otherwise
 
Nothing | otherwise
 
</haskell>
 
</haskell>
(note the reordering of matches against <code>s</code> and <code>u</code>.)
+
:(note the reordering of matches against <code>s</code> and <code>u</code>.)
  +
|}
   
   
 
  +
{|
<haskell>
 
  +
|
  +
* <haskell>
 
-- ghc-8.6.5/compiler/specialise/SpecConstr.hs, lines 2209-2215
 
-- ghc-8.6.5/compiler/specialise/SpecConstr.hs, lines 2209-2215
 
mb_scrut dc = case arg_occ of
 
mb_scrut dc = case arg_occ of
Line 146: Line 153:
 
-> Nothing
 
-> Nothing
 
</haskell>
 
</haskell>
or:
+
:or:
<haskell>
+
:<haskell>
 
mb_scrut dc =
 
mb_scrut dc =
 
cases
 
cases
Line 154: Line 161:
 
Nothing | otherwise
 
Nothing | otherwise
 
</haskell>
 
</haskell>
  +
|}
   
 
  +
{|
One more example:
 
  +
|
<haskell>
 
 
* One more example:
 
:<haskell>
 
concatMap f xs = [ x <- xs, y <- f x -> y ]
 
concatMap f xs = [ x <- xs, y <- f x -> y ]
 
</haskell>
 
</haskell>
or:
+
:or:
<haskell>
+
:<haskell>
 
concatMap f xs = [ y | x <- xs, y <- f x ]
 
concatMap f xs = [ y | x <- xs, y <- f x ]
 
</haskell>
 
</haskell>
  +
|}
   
 
[[User:Atravers|Atravers]] 01:37, 10 July 2020 (UTC)
 
[[User:Atravers|Atravers]] 01:37, 10 July 2020 (UTC)

Revision as of 02:51, 4 August 2021

One could argue that the notation <- is misleading, suggesting the idea of drawn from as in a list comprehension. But it is very nice to reuse precisely the list comprehension syntax.

Reusing just that part of the list-comprehension syntax seems to work for multi-part function definitions:

clunky env var1 var2 | Just val1 <- lookup env var1,
                       Just val2 <- lookup env var2  = val1 + val2
                     | otherwise = var1 + var2

but when it's used in case expressions:

 -- ghc-8.6.5/compiler/ghci/RtClosureInspect.hs, lines 1099-1107
check2 (_, rtti_ty) (_, old_ty)
  | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
  = case () of
      _ | Just (_,olds) <- tcSplitTyConApp_maybe old_ty
        -> and$ zipWith check2 (map quantifyType rttis) (map quantifyType olds)
      _ | Just _ <- splitAppTy_maybe old_ty
        -> isMonomorphicOnNonPhantomArgs rtti_ty
      _ -> True
  | otherwise = True

it looks somewhat out-of-place, unless:

map f xs = [ x <- xs -> f x ]

is considered a suitable replacement for:

map f xs = [ f x | x <- xs ]


Could the GHC example benefit from some more list-comprehension syntax? Let's borrow a new reserved word:

check2 (_, rtti_ty) (_, old_ty)
  | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
  = cases
      and $ zipWith check2 (map quantifyType rttis) (map quantifyType olds) |
          Just (_,olds) <- tcSplitTyConApp_maybe old_ty
      isMonomorphicOnNonPhantomArgs rtti_ty |
          Just _ <- splitAppTy_maybe old_ty
      True | otherwise
  | otherwise = True

...well, at least the unit-case workaround is gone. With a little refactoring:

check2 (_, rtti_ty) (_, old_ty)
  | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
  = case () of
      _ | Just (_,olds) <- tcSplitTyConApp_maybe old_ty
        -> and $ zipWith qcheck2 rttis olds
      _ | Just _ <- splitAppTy_maybe old_ty
        -> isMonomorphicOnNonPhantomArgs rtti_ty
      _ -> True
  | otherwise = True

qcheck2 rtti old = check2 (quantifyType rtti) (quantifyType old)

and the alternate syntax:

check2 (_, rtti_ty) (_, old_ty)
  | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty
  = cases
      and $ zipWith qcheck2 rttis olds | Just (_,olds) <- tcSplitTyConApp_maybe old_ty
      isMonomorphicOnNonPhantomArgs rtti_ty | Just _ <- splitAppTy_maybe old_ty
      True | otherwise
  | otherwise = True

qcheck2 rtti old = check2 (quantifyType rtti) (quantifyType old)

this particular example is further improved, unless:

filter p xs = [ x <- xs, p x -> x ]

is considered a reasonable substitute for:

filter p xs = [ x | x <- xs, p x ]


Still not convinced? Here's some other examples:

  •  -- ghc-8.6.5/compiler/codeGen/StgCmmMonad.hs, lines 819-827
    let
       (test, then_, else_, likely') = case likely of
         Just False | Just e' <- maybeInvertCmmExpr e
           -> (e', fbranch, tbranch, Just True)
         _ -> (e, tbranch, fbranch, likely)
    
or:
let
   (test, then_, else_, likely') =
     cases
       (e', fbranch, tbranch, Just True) | Just False <- likely,
                                           Just e' <- maybeInvertCmmExpr e
       (e, tbranch, fbranch, likely)     | otherwise


  •  -- ghc-8.6.5/compiler/basicTypes/Demand.hs, lines 927-934
    splitProdDmd_maybe (JD { sd = s, ud = u })
     = case (s,u) of
         (Str _ (SProd sx), Use _ u) | Just ux <- splitUseProdDmd (length sx) u
                                     -> Just (mkJointDmds sx ux)
         (Str _ s, Use _ (UProd ux)) | Just sx <- splitStrProdDmd (length ux) s
                                     -> Just (mkJointDmds sx ux)
         (Lazy,    Use _ (UProd ux)) -> Just (mkJointDmds (replicate (length ux) Lazy) ux)
         _ -> Nothing
    
or:
splitProdDmd_maybe (JD { sd = s, ud = u })
 = cases
     Just (mkJointDmds sx ux) | Str _ (SProd sx) <- s, Use _ u <- u,
                                Just ux <- splitUseProdDmd (length sx) u
     Just (mkJointDmds sx ux) | Use _ (UProd ux) <- u, Str _ s <- s,
                                Just sx <- splitStrProdDmd (length ux) s
     Just (mkJointDmds (replicate (length ux) Lazy) ux) |
                                Use _ (UProd ux) <- u, Lazy <- s
     Nothing                  | otherwise
(note the reordering of matches against s and u.)


  •  -- ghc-8.6.5/compiler/specialise/SpecConstr.hs, lines 2209-2215
       mb_scrut dc = case arg_occ of
                       ScrutOcc bs | Just occs <- lookupUFM bs dc
                                   -> Just (occs)
                       _other      | sc_force env || sc_keen env
                                   -> Just (repeat UnkOcc)
                                   | otherwise
                                   -> Nothing
    
or:
   mb_scrut dc =
     cases
       Just (occs) | ScrutOcc bs <- arg_occ, Just occs <- lookupUFM bs dc
       Just (repeat UnkOcc) | sc_force env || sc_keen env
       Nothing | otherwise
  • One more example:
concatMap f xs = [ x <- xs, y <- f x -> y ]
or:
concatMap f xs = [ y | x <- xs, y <- f x ]

Atravers 01:37, 10 July 2020 (UTC)