Personal tools

Worker wrapper

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(HaWiki conversion)
 
(Adding like to workerwrapper)
(One intermediate revision by one user not shown)
Line 18: Line 18:
 
</haskell>
 
</haskell>
 
note often a worker will also return some state along with a result which can be stripped away.
 
note often a worker will also return some state along with a result which can be stripped away.
  +
  +
<hask>revWorker</hask> could be considered a generally useful function. <hask>revWorker x y</hask> is equivalent to, but probably faster than, <hask>reverse y ++ x</hask>.
  +
   
 
==Other examples==
 
==Other examples==
Line 47: Line 50:
 
Moving a worker to a higher level (which may require some [[Lambda lifting]]) is known as [[Let floating]].
 
Moving a worker to a higher level (which may require some [[Lambda lifting]]) is known as [[Let floating]].
   
 
<hask>revWorker</hask> could be considered a generally useful function. <hask>revWorker x y</hask> is equivalent to, but probably faster than, <hask>reverse y ++ x</hask>.
 
   
 
==See also==
 
==See also==
 
* [[Avoiding parameter passing]]
 
* [[Avoiding parameter passing]]
  +
* [http://www.workerwrapper.com The Worker Wrapper Transformation]
   
 
[[Category:Idioms]]
 
[[Category:Idioms]]

Revision as of 04:32, 8 May 2008

It is sometimes easier or more efficient to write functions which have particular "start arguments" or that pass state. When this is the case write wrappers rather than trying to code within the original signature.

Contents

1 Accumulator examples

e.g. the function reverse

reverse :: [a] -> [a]

could be written

reverse [] = []
reverse (x:xs) =  reverse xs ++ [x]

however this will be more efficient if it were written

reverse xs = revWorker [] xs
 
revWorker s [] = s
revWorker s (x:xs) = revWorker (x:s) xs

note often a worker will also return some state along with a result which can be stripped away.

revWorker
could be considered a generally useful function.
revWorker x y
is equivalent to, but probably faster than,
reverse y ++ x
.


2 Other examples

Wrappers are often used to play the role of loop initialisation in imperative languages. For example:

fib n = fibWorker n 0 1
 
fibWorker n f1 f2
 | n == 0    = f1
 | otherwise = fibWorker (n-1) f2 (f1+f2)

3 Hiding the worker

Also, often one hides the worker(s) with a where (or let). E.g. :

fib = fibWorker 0 1
  where
  fibWorker f0 f1 n
    | n == 0  = f0
    | True    = fibWorker f1 (f0 + f1) (n-1)

Of course, one then has to de-hide the worker if one want to test it with different initial arguments.

In some cases, though, the worker can be a generally useful function on its own merits, in that case one obviously shouldn't hide it.


One common case is where you want to subject the worker function to Unit testing. In such a situation, the test suite has to be able to get to the worker function. Another is where the worker might be a candidate for further abstraction. (See Higher order function for examples.)

Moving a worker to a higher level (which may require some Lambda lifting) is known as Let floating.


4 See also