# Difference between revisions of "Avoiding partial functions"

(→fromJust) |
(→init, last: links to utility-ht:viewR and switchR) |
||

Line 67: | Line 67: | ||

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

− | + | Alternatively, you may import from {{HackagePackage|id=utility-ht}}: | |

− | + | * [http://hackage.haskell.org/packages/archive/utility-ht/0.0.8/doc/html/Data-Tuple-HT.html forcePair] | |

+ | * [http://hackage.haskell.org/packages/archive/utility-ht/0.0.8/doc/html/Data-List-HT.html viewR] | ||

+ | * [http://hackage.haskell.org/packages/archive/utility-ht/0.0.8/doc/html/Data-List-HT.html switchR]. | ||

== (!!) == | == (!!) == |

## Revision as of 07:24, 26 July 2014

There are several partial functions in the Haskell standard library. If you use them, you always risk to end up with an undefined. In this article we give some hints how to avoid them, leading to code that you can be more confident about.

For a partial function f the general pattern is: Whereever we write "check whether x is in the domain of f before computing f x", we replace it by combination of check and computation of f.

## fromJust

You should replace

```
if isNothing mx
then g
else h (fromJust mx)
```

by

```
case mx of
Nothing -> g
Just x -> h x
```

which is equivalent to

```
maybe g h mx
```

## head, tail

You should replace

```
if null xs
then g
else h (head xs) (tail xs)
```

by

```
case xs of
[] -> g
y:ys -> h y ys
```

## init, last

You may replace

```
if null xs
then g
else h (init xs) (last xs)
```

by

```
case xs of
[] -> g
y:ys -> uncurry h $ viewRTotal y ys
viewRTotal :: a -> [a] -> ([a], a)
viewRTotal x xs =
forcePair $
foldr
(\x0 go y -> case go y of ~(zs,z) -> (x0:zs,z))
(\y -> ([],y))
xs x
forcePair :: (a,b) -> (a,b)
forcePair ~(a,b) = (a,b)
```

Alternatively, you may import from utility-ht:

## (!!)

You should replace

```
if k < length xs
then xs!!k
else y
```

by

```
case drop k xs of
x:_ -> x
[] -> y
```

This is also more lazy, since for computation of `length`

you have to visit every element of the list.

## irrefutable pattern match on (:)

You should replace

```
if k < length xs
then let (prefix,x:suffix) = splitAt k xs
in g prefix x suffix
else y
```

by

```
case splitAt k xs of
(prefix,x:suffix) -> g prefix x suffix
(_,[]) -> y
```

## minimum

The function `isLowerLimit`

checks if a number is a lower limit to a sequence.
You may implement it with the partial function `minimum`

.

```
isLowerLimit :: Ord a => a -> [a] -> Bool
isLowerLimit x ys = x <= minimum ys
```

It fails if `ys`

is empty or infinite.

You should replace it by

```
isLowerLimit x = all (x<=)
```

This definition terminates for infinite lists, if `x`

is not a lower limit. It aborts immediately if an element is found which is below `x`

.
Thus it is also faster for finite lists.
Even more: It also works for empty lists.