Case
From HaskellWiki
(Difference between revisions)
(one colon too much) |
(→Using functions: reshuffle some code lines, c/e) |
||
| (9 intermediate revisions not shown.) | |||
| 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 == | ||
| - | + | There are several approaches to this problem. | |
| - | + | === Using functions === | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ==== select ==== | |
| - | + | We can do this nicely with a function implemented in Haskell: | |
<haskell> | <haskell> | ||
select :: a -> [(Bool, a)] -> a | select :: a -> [(Bool, a)] -> a | ||
select def = maybe def snd . List.find fst | select def = maybe def snd . List.find fst | ||
| - | + | -- = fromMaybe def . lookup True | |
| + | -- = maybe def id . lookup True | ||
select exDefault | select exDefault | ||
| Line 25: | Line 23: | ||
(cond3, ex3)] | (cond3, ex3)] | ||
</haskell> | </haskell> | ||
| + | Unfortunately this function is not in the [[Prelude]]. | ||
| + | It is however in the [http://hackage.haskell.org/packages/archive/utility-ht/0.0.1/doc/html/Data-Bool-HT.html#v%3Aselect utility-ht] package. | ||
| + | |||
| + | ==== nested 'if' ==== | ||
Alternative implementations are | Alternative implementations are | ||
<haskell> | <haskell> | ||
| - | |||
| - | |||
{- a purely functional implementation of if-then-else -} | {- a purely functional implementation of if-then-else -} | ||
if' :: Bool -> a -> a -> a | if' :: Bool -> a -> a -> a | ||
| Line 39: | Line 39: | ||
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 | ||
| + | <haskell> | ||
| + | if' cond1 ex1 $ | ||
| + | if' cond2 ex2 $ | ||
| + | if' cond3 ex3 $ | ||
| + | exDefault | ||
| + | </haskell> | ||
| - | If you | + | ==== infix operator ==== |
| + | |||
| + | If you use <hask>if'</hask> in infix form, | ||
| + | you may call it <hask>?</hask> like in C, | ||
| + | then because of partial application it will work nicely together with '$' for the else clause. | ||
<haskell> | <haskell> | ||
| - | + | infixl 1 ? | |
| - | + | (?) :: Bool -> a -> a -> a | |
| - | + | (?) = if' | |
| - | + | ||
| - | + | cond1 ? ex1 $ | |
| - | + | cond2 ? ex2 $ | |
| + | cond3 ? ex3 $ | ||
| + | exDefault | ||
| + | </haskell> | ||
| + | === Using syntactic sugar === | ||
| - | + | ==== Guards ==== | |
| - | + | ||
| - | + | 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. | ||
| + | |||
| + | ==== List comprehensions ==== | ||
| + | |||
| + | An alternative sugarful approach is to use [[list comprehension]]s. | ||
| + | |||
| + | <haskell> | ||
| + | head $ | ||
| + | [ ex1 | cond1 ] ++ | ||
| + | [ ex2 | cond2 ] ++ | ||
| + | [ ex3 | cond3 ] ++ | ||
| + | [ exDefault ] | ||
</haskell> | </haskell> | ||
| + | [[Category:FAQ]] | ||
[[Category:Idioms]] | [[Category:Idioms]] | ||
Current revision
Contents |
1 Question
Can I have acase
2 Answer
There are several approaches to this problem.
2.1 Using functions
2.1.1 select
We can do this nicely with a function implemented in Haskell:
select :: a -> [(Bool, a)] -> a select def = maybe def snd . List.find fst -- = fromMaybe def . lookup True -- = maybe def id . lookup True select exDefault [(cond1, ex1), (cond2, ex2), (cond3, ex3)]
Unfortunately this function is not in the Prelude. It is however in the utility-ht package.
2.1.2 nested 'if'
Alternative implementations are
{- 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')
select''
select
if
if'
zipWith3
zipWith3 if'
See if-then-else.
Alternatively you can unrollfoldr
if' cond1 ex1 $ if' cond2 ex2 $ if' cond3 ex3 $ exDefault
2.1.3 infix operator
If you useif'
?
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
2.2.1 Guards
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.
2.2.2 List comprehensions
An alternative sugarful approach is to use list comprehensions.
head $ [ ex1 | cond1 ] ++ [ ex2 | cond2 ] ++ [ ex3 | cond3 ] ++ [ exDefault ]
Categories: FAQ | Idioms
