# Difference between revisions of "Case"

(→Using functions: reshuffle some code lines, c/e) |
(add MultiWayIf) |
||

Line 91: | 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
```