# Avoiding partial functions

### From HaskellWiki

CaleGibbard (Talk | contribs) m |
(Add reference to the safe library.) |
||

Line 2: | Line 2: | ||

If you use them, you always risk to end up with an undefined. | 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. | In this article we give some hints how to avoid them, leading to code that you can be more confident about. | ||

+ | |||

+ | In addition to the below rewrites, many partial functions can be avoided by using variants from the [https://hackage.haskell.org/package/safe safe] library. | ||

For a partial function f the general pattern is: | For a partial function f the general pattern is: |

## Latest revision as of 04:03, 4 September 2017

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.

In addition to the below rewrites, many partial functions can be avoided by using variants from the safe library.

For a partial function f the general pattern is: Wherever 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.

## Contents |

## [edit] 1 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`

## [edit] 2 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

## [edit] 3 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:

## [edit] 4 (!!)

You should replace

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

by

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

## [edit] 5 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

## [edit] 6 minimum

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

You should replace it by

isLowerLimit x = all (x<=)

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