# Difference between revisions of "Case"

(add MultiWayIf) |
|||

(5 intermediate revisions by 2 users not shown) | |||

Line 8: | Line 8: | ||

=== Using functions === |
=== Using functions === |
||

+ | |||

+ | ==== select ==== |
||

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

Line 13: | Line 15: | ||

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 |
||

− | |||

⚫ | |||

+ | -- = maybe def id . lookup True |
||

select exDefault |
select exDefault |
||

Line 21: | Line 24: | ||

</haskell> |
</haskell> |
||

Unfortunately this function is not in the [[Prelude]]. |
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 44: | Line 48: | ||

exDefault |
exDefault |
||

</haskell> |
</haskell> |
||

+ | |||

+ | ==== infix operator ==== |
||

If you use <hask>if'</hask> in infix form, |
If you use <hask>if'</hask> in infix form, |
||

Line 59: | Line 65: | ||

</haskell> |
</haskell> |
||

⚫ | |||

− | |||

+ | ==== Guards ==== |
||

⚫ | |||

You can make use of some [[syntactic sugar]] of Haskell, namely of [[guard]]s. |
You can make use of some [[syntactic sugar]] of Haskell, namely of [[guard]]s. |
||

Line 75: | Line 81: | ||

Alternatively, one could simply factor out a function(/value) and use guards in the argument patterns. |
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. |
An alternative sugarful approach is to use [[list comprehension]]s. |
||

Line 85: | Line 91: | ||

[ ex3 | cond3 ] ++ |
[ ex3 | cond3 ] ++ |
||

[ exDefault ] |
[ exDefault ] |
||

+ | </haskell> |
||

+ | |||

+ | === MultiWayIf === |
||

+ | |||

+ | The MultiWayIf extension lets you write code similar to a <hask>case () of _</hask> form, using only the word <hask>if</hask>. To enable it, add <hask>{-# LANGUAGE MultiWayIf #-}</hask> to the top of a <tt>.hs</tt> file, run ghci with <tt>ghci -XMultiWayIf</tt>, or add <tt>MultiWayIf</tt> to the <tt>default-extensions</tt> in your <tt>.cabal</tt> file. |
||

+ | |||

+ | <haskell> |
||

+ | if | guard1 -> expr1 |
||

+ | | ... |
||

+ | | guardN -> exprN |
||

</haskell> |
</haskell> |
||

## Latest revision as of 11:36, 11 June 2020

## Contents

## Question

Can I have a `case`

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:

```
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.

#### 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')
```

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
```

#### infix operator

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
```

### Using syntactic sugar

#### 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.

#### List comprehensions

An alternative sugarful approach is to use list comprehensions.

```
head $
[ ex1 | cond1 ] ++
[ ex2 | cond2 ] ++
[ ex3 | cond3 ] ++
[ exDefault ]
```

### MultiWayIf

The MultiWayIf extension lets you write code similar to a `case () of _`

form, using only the word `if`

. To enable it, add `{-# LANGUAGE MultiWayIf #-}`

to the top of a `.hs` file, run ghci with `ghci -XMultiWayIf`, or add `MultiWayIf` to the `default-extensions` in your `.cabal` file.

```
if | guard1 -> expr1
| ...
| guardN -> exprN
```