Difference between revisions of "Case comprehensions"

From HaskellWiki
Jump to navigation Jump to search
(Content transferred from "Cases expressions")
 
m (More minor formatting changes)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
 
[[Category:Proposals]]
 
[[Category:Proposals]]
  +
<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
<blockquote>''One could argue that the notation <code><-</code> is misleading, suggesting the idea of <span style="color:gray">drawn from</span> as in a list comprehension. But it is very nice to reuse precisely the list comprehension syntax.''</blockquote>
+
One could argue that the notation <code><-</code> 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.
   
* [http://web.engr.oregonstate.edu/~erwig/papers/PGandTP_Haskell00.pdf Pattern guards and Transformational Patterns], Martin Erwig and Simon Peyton Jones.
+
<tt>[http://web.engr.oregonstate.edu/~erwig/papers/PGandTP_Haskell00.pdf Pattern guards and Transformational Patterns], Martin Erwig and Simon Peyton Jones.</tt>
  +
</div>
   
 
Reusing just that part of the list-comprehension syntax seems to work for multi-part function definitions:
 
Reusing just that part of the list-comprehension syntax seems to work for multi-part function definitions:
Line 89: Line 91:
   
 
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 102:
 
_ -> (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 111:
 
(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 128:
 
_ -> 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 140:
 
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 156:
 
-> Nothing
 
-> Nothing
 
</haskell>
 
</haskell>
or:
+
:or:
<haskell>
+
:<haskell>
 
mb_scrut dc =
 
mb_scrut dc =
 
cases
 
cases
Line 154: Line 164:
 
Nothing | otherwise
 
Nothing | otherwise
 
</haskell>
 
</haskell>
  +
|}
   
  +
{|
 
  +
|
One more example:
+
* One more example:
<haskell>
 
 
:<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)

Latest revision as of 02:12, 5 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.

Pattern guards and Transformational Patterns, Martin Erwig and Simon Peyton Jones.

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)