Lawrence Bottorff <borgauf@...> writes:
> > I posted the following question at stackoverflow and got 3 pluses and a star (favorite question) -- although only one response. I'd really like to clear these issues up in my mind. Here goes: > ---- > > > I've read some of the discussions here, as well as followed links to other explanations, but I'm still not able to understand the mathematical connection between "changing state" and "not changing state" as it pertains to our functional programming versus non-FP debate. I understand the basic argument goes back to the pure math definition of a function, whereby a function maps a domain member to only one range member. This is subsequently compared to when a computer code function is given certain input, it will always produce the same output, i.e., not vary from use to use, i.e.i.e., the function's state, bzw. its domain to range mapping behavior, will not change. ------------------------------ Lawrence, Take a different perspective entirely. Forget the mathematical and theoretical stuff for the moment. Think about sources for bugs in imperative, procedural or OO programming, when left up to a programmer to manage: 1. pointers 2. memory management 3. assigning and reassigning values to variables/memory locations 4. breaking an interface (whether it’s OO or not) Let’s just stop at those 4. People might mention others… Also think about some other things that we do repeatedly in coding solutions to many problems: 5. iterate over a list or collection to do something to each element of that collection 6. interrupt computation at time t, restart from the same point at time t+x. 7. use “potentially infinite” and possibly recursive data set Pure functional languages do not allow (re)assignment. You can assign a variable/identifier once, then it is immutable. If you need a new value, it is a different identifier (different memory location under the covers). It removes a number of shared-memory bugs caused by updating a location incorrectly, whether your application is single-threaded or multi-threaded or distributed. Similarly a programmer can create new things, like lists, but is not *required* to explicitly manage when a list gets destroyed/deallocated. Typically, the system will do it. Functional languages allow a clean way of passing functions (and closures) as parameters and returning functions as values from another function. This enables higher- order functions such as map, filter, fold and list comprehensions to work in predictable, sane ways. Again so the programmer doesn’t have to explicitly manage, or even think about, operating on a collection as explicit iteration. Functions with closures allow you to cleanly stop execution of a function, “memorize it” (to use some jargon) and restart it later, with the expectation that it will generate the same result as though it had simply run from beginning to end. And then there is lazy versus strict evaluation. When dealing with potentially infinite data, the programmer’s code does not have to change versus dealing with a collection that only has 10 items. Typically the programmer includes a lazy version of the same code, or change a library import, or something like that—which is much less likely to introduce bugs in code than having to change a lot of function/method names. Lazy versus strict evaluation of code/data is a behavioral, semantic issue, usually not a syntactic one. George ____________________ Racket Users list: http://lists.racket-lang.org/users