Re: Functional Programming in the Larger or Functional Oriented Software Engineering
Matthew D Swank <[email protected]> Sat, 31 Mar 2007 16:15:18 -0500
| Newsgroups | gmane.comp.lang.lightweight |
|---|---|
| Message-ID | <[email protected]> |
Robbert Haarman wrote: > On Sat, Mar 31, 2007 at 03:13:52PM -0500, Matthew D Swank wrote: >> Joe Marshall wrote: >>> On 3/29/07, Matthew Swank <[email protected]> wrote: ... > Err, did you just illustrate how not using mutation can be beneficial in > resource-constrained environments by introducing memoization and hash > tables, both of which involve mutation?!?! > > Regards, > > Bob > That's my fault; here's the full e-mail (I wasn't aware Joe hadn't sent it to the list): On 3/29/07, Matthew Swank <[email protected]> wrote: > > > What if resources aren't cheap, or I have to manage my own memory. Is > avoiding mutation still practical? It can be. There are some interesting tricks. The first is memoization. Pure functions never change their output when given the same input, so you can save the results of a computation in a table and just look up the answer the next time. Although the table itself requires memory, it can save resources in the long run because it avoids redoing any allocation performed in intermediate computations. The second trick is truly awesome. You can memoize CONS using a technique called `hash consing'. You keep a hash table of your cons cells and when the user calls CONS, you check to see if you have an existing CONS cell with the right contents and use it instead. Of course this only works if you *never* mutate hashed conses. There is a surprising additional benefit of doing this. If you think about it a bit, you'll realize that this technique causes all your CONS cells to be interned. This means that you can use EQ to compare lists in O(1) time. There is yet *another* interesting benefit. Tree structures that are built out of CONS cells turn into directed acyclic graphs with maximal sharing automatically. This results in a substantial space savings. Henry Baker has this interesting paper about applying these techniques to the Boyer benchmark: http://home.pipeline.com/~hbaker1/BoyerB.html Baker used memoization and hash-consing to reduce the memory consumption by a factor of 100. He pointed out that as a result the benchmark didn't need to spill out of the cache. There is an obvious objection here. Memoization and hash-consing are themselves implemented by mutation. My claim is that this mutation is `under the hood', that is, it is below the abstraction level of the original functional program. Furthermore, you can only make use of these techniques if the overlying program is purely functional. -- ~jrm