Difference between revisions of "Cases expressions"

From HaskellWiki
Jump to: navigation, search
(Initial proposal)
 
(Content transferred to "Case comprehensions")
 
Line 1: Line 1:
[[Category:Proposals]]
 
  +
#REDIRECT [[Case comprehensions]]
<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>
 
   
* [http://web.engr.oregonstate.edu/~erwig/papers/PGandTP_Haskell00.pdf Pattern guards and Transformational Patterns], Martin Erwig and Simon Peyton Jones.
 
 
[[Category:Pages to be removed]]
 
Reusing just that part of the list-comprehension syntax seems to work for multi-part function definitions:
 
<haskell>
 
clunky env var1 var2 | Just val1 <- lookup env var1,
 
Just val2 <- lookup env var2 = val1 + val2
 
| otherwise = var1 + var2
 
</haskell>
 
 
but when it's used in case expressions:
 
<haskell>
 
-- 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
 
</haskell>
 
 
it looks somewhat out-of-place, unless:
 
<haskell>
 
map f xs = [ x <- xs -> f x ]
 
</haskell>
 
 
is considered a suitable replacement for:
 
<haskell>
 
map f xs = [ f x | x <- xs ]
 
</haskell>
 
 
 
Could the GHC example benefit from some more list-comprehension syntax? Let's borrow a new reserved word:
 
<haskell>
 
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
 
</haskell>
 
 
...well, at least the ''unit-case'' workaround is gone. With a little refactoring:
 
<haskell>
 
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)
 
</haskell>
 
 
and the alternate syntax:
 
<haskell>
 
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)
 
</haskell>
 
 
this particular example is further improved, unless:
 
<haskell>
 
filter p xs = [ x <- xs, p x -> x ]
 
</haskell>
 
 
is considered a reasonable substitute for:
 
<haskell>
 
filter p xs = [ x | x <- xs, p x ]
 
</haskell>
 
 
 
Still not convinced? Here's some other examples:
 
<haskell>
 
-- 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)
 
</haskell>
 
or:
 
<haskell>
 
let
 
(test, then_, else_, likely') =
 
cases
 
(e', fbranch, tbranch, Just True) | Just False <- likely,
 
Just e' <- maybeInvertCmmExpr e
 
(e, tbranch, fbranch, likely) | otherwise
 
</haskell>
 
 
 
 
<haskell>
 
-- 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
 
</haskell>
 
or:
 
<haskell>
 
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
 
</haskell>
 
(note the reordering of matches against <code>s</code> and <code>u</code>.)
 
 
 
 
<haskell>
 
-- 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
 
</haskell>
 
or:
 
<haskell>
 
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
 
</haskell>
 
 
 
One more example:
 
<haskell>
 
concatMap f xs = [ x <- xs, y <- f x -> y ]
 
</haskell>
 
or:
 
<haskell>
 
concatMap f xs = [ y | x <- xs, y <- f x ]
 
</haskell>
 
 
[[User:Atravers|Atravers]] 01:37, 10 July 2020 (UTC)
 

Latest revision as of 02:34, 4 August 2021