Personal tools

Case

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
m
(more flavors)
Line 1: Line 1:
  +
== Question ==
  +
 
Can I have a <hask>case</hask> where the alternatives contain expressions?
 
Can I have a <hask>case</hask> where the alternatives contain expressions?
   
  +
== Answer ==
   
You can make use of some [[syntactic sugar]] of Haskell, namely of [[guard]]s.
+
There are several approaches to this problem.
   
<haskell>
+
=== Using functions ===
case () of _
 
| cond1 -> ex1
 
| cond2 -> ex2
 
| cond3 -> ex3
 
| otherwise -> exDefault
 
</haskell>
 
   
Alternatively, one could simply factor out a function(/value) and use guards in the argument patterns.
+
We can do this nicely with a function implemented in Haskell:
 
Why sticking to syntactic sugar? We can do it nicely with a function implemented in Haskell:
 
 
<haskell>
 
<haskell>
 
select :: a -> [(Bool, a)] -> a
 
select :: a -> [(Bool, a)] -> a
Line 17: Line 20:
 
(cond3, ex3)]
 
(cond3, ex3)]
 
</haskell>
 
</haskell>
  +
Unfortunately this function is not in the [[Prelude]].
   
 
Alternative implementations are
 
Alternative implementations are
Line 31: Line 35:
 
The implementation of <hask>select''</hask> makes clear that <hask>select</hask> can be considered as nested <hask>if</hask>s.
 
The implementation of <hask>select''</hask> makes clear that <hask>select</hask> can be considered as nested <hask>if</hask>s.
 
The functional <hask>if'</hask> is also useful in connection with <hask>zipWith3</hask> since <hask>zipWith3 if'</hask> merges two lists according to a list of conditions.
 
The functional <hask>if'</hask> is also useful in connection with <hask>zipWith3</hask> since <hask>zipWith3 if'</hask> merges two lists according to a list of conditions.
  +
See [[if-then-else]].
   
+
Alternatively you can unroll <hask>foldr</hask> and write
If you don't like the parentheses for the pairs, you can also define
 
 
<haskell>
 
<haskell>
data SelectBranch a = (:->) {
+
if' cond1 ex1 $
condition :: Bool,
+
if' cond2 ex2 $
expression :: a
+
if' cond3 ex3 $
}
+
exDefault
 
select :: a -> [SelectBranch a] -> a
 
select def = maybe def expression . List.find condition
 
 
 
select exDefault
 
[cond1 :-> ex1,
 
cond2 :-> ex2,
 
cond3 :-> ex3]
 
 
</haskell>
 
</haskell>
   
It is also possible to define a ternary operator '?' like in C.
+
If you use <hask>if'</hask> in infix form,
Because of partial application it will work nicely together with
+
you may call it <hask>?</hask> like in C,
'$' for the else clause.
+
then because of partial application it will work nicely together with '$' for the else clause.
 
 
<haskell>
 
<haskell>
 
infixl 1 ?
 
infixl 1 ?
 
(?) :: Bool -> a -> a -> a
 
(?) :: Bool -> a -> a -> a
True ? v = const v
+
(?) = if'
False ? _ = id
 
   
 
cond1 ? ex1 $
 
cond1 ? ex1 $
 
cond2 ? ex2 $
 
cond2 ? ex2 $
cond3 ? ex3 $ exDefault
+
cond3 ? ex3 $
  +
exDefault
 
</haskell>
 
</haskell>
   
  +
  +
  +
=== Using syntactic sugar ===
  +
  +
You can make use of some [[syntactic sugar]] of Haskell, namely of [[guard]]s.
  +
  +
<haskell>
  +
case () of _
  +
| cond1 -> ex1
  +
| cond2 -> ex2
  +
| cond3 -> ex3
  +
| otherwise -> exDefault
  +
</haskell>
  +
  +
Alternatively, one could simply factor out a function(/value) and use guards in the argument patterns.
  +
  +
  +
[[Category:FAQ]]
 
[[Category:Idioms]]
 
[[Category:Idioms]]

Revision as of 13:29, 31 May 2007

Contents

1 Question

Can I have a
case
where the alternatives contain expressions?

2 Answer

There are several approaches to this problem.

2.1 Using functions

We can do this nicely with a function implemented in Haskell:

select :: a -> [(Bool, a)] -> a
select def = maybe def snd . List.find fst
 
 
select exDefault
    [(cond1, ex1),
     (cond2, ex2),
     (cond3, ex3)]

Unfortunately this function is not in the Prelude.

Alternative implementations are

select' def = fromMaybe def . lookup True
 
{- a purely functional implementation of if-then-else -}
if' :: Bool -> a -> a -> a
if' True  x _ = x
if' False _ y = y
 
select'' = foldr (uncurry if')
The implementation of
select''
makes clear that
select
can be considered as nested
if
s. The functional
if'
is also useful in connection with
zipWith3
since
zipWith3 if'
merges two lists according to a list of conditions.

See if-then-else.

Alternatively you can unroll
foldr
and write
if' cond1 ex1 $
if' cond2 ex2 $
if' cond3 ex3 $
   exDefault
If you use
if'
in infix form, you may call it
?
like in C,

then because of partial application it will work nicely together with '$' for the else clause.

infixl 1 ?
(?) :: Bool -> a -> a -> a
(?) = if'
 
cond1 ? ex1 $
cond2 ? ex2 $
cond3 ? ex3 $
   exDefault


2.2 Using syntactic sugar

You can make use of some syntactic sugar of Haskell, namely of guards.

case () of _
             | cond1     -> ex1
             | cond2     -> ex2
             | cond3     -> ex3
             | otherwise -> exDefault

Alternatively, one could simply factor out a function(/value) and use guards in the argument patterns.