Difference between revisions of "Avoiding partial functions"
Jump to navigation
Jump to search
(→init, last: viewRTotal with narrow formatting) |
(fromJust) |
||
Line 6: | Line 6: | ||
Whereever we write "check whether x is in the domain of f before computing f x", |
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. |
we replace it by combination of check and computation of f. |
||
+ | |||
+ | == fromJust == |
||
+ | |||
+ | You should replace |
||
+ | <haskell> |
||
+ | if isJust mx |
||
+ | then g |
||
+ | else h (fromJust mx) |
||
+ | </haskell> |
||
+ | by |
||
+ | <haskell> |
||
+ | case mx of |
||
+ | Nothing -> g |
||
+ | Just x -> h x |
||
+ | </haskell> |
||
== head, tail == |
== head, tail == |
Revision as of 12:10, 5 June 2012
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 isJust mx
then g
else h (fromJust mx)
by
case mx of
Nothing -> g
Just x -> h x
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)
(!!)
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