3 ms·
Good points, although I agree that a lot of them boil down to similar statements. I have settled on a style of doing "functional-like" programming in Python an
by chubot 10y ago
Good points, although I agree that a lot of them boil down to similar statements.
I have settled on a style of doing "functional-like" programming in Python and C++. It's more about the high level architecture than low level coding details.
It means being very paranoid and rigorous about state -- but still having great tools to express it! For example: Using ZERO mutable globals, and passing state in as a parameter to functions. Using immutable/persistent data structures. These techniques are done very naturally and effectively in Python and C++. You just have to be disciplined.
To me there's no real advantage to expressing something like "split a string by a delimiter" in a purely functional style. Either way, you have a trivial referentially transparent function you can reuse without causing complexity in your program. You might as well do the obvious imperative thing.
However there IS a benefit to threading state explicitly throughout the application, and encapsulating it in OBJECTS (yes objects).
For me, the thing that sealed the deal against functional languages for "real work" was trying to write a production quality sh parser.
I went down a long path of trying to do this first in OCaml and then in Lisp. The VERY first thing that hits you over the head -- lexing -- is heavily and inherently stateful. ocamllex and ocamlyacc to me are evidence of this paucity and poverty of purely functional solutions. They're just transliterating solutions from C. Well I might as well use C then.
Actually, I decided to use C++, which was like my 5th choice as language. Aside from headers and compile times, it's a good choice. I use "functions and data" (a la Rich Hickey).
Except my functions and data are both CLASSES. Data objects are basically structs, except they can do things like print themselves and answer simple queries based on their values, which helps readability (e.g. 1 liners, like word.AsFuncName() ).
Function objects are simply classes with configuration passed to constructors. That usually have a single method, but multiple methods are also often useful. Calling this method is basically equivalent to calling a curried function. But this is supremely useful for both compilers and servers, because often you have config/params that is constant once you reach main(), and then you have params that vary per request or per file processed. Many functions depend on both, and it's cleaner to separate the two kinds of params.
So both "functions and data" are effectively and usefully implemented as classes. The key is to make some classes like functions, and some classes like data. And have more of a bipartite dependency graph, where functions depend on data, and data depends on functions.
When all your classes are an equal mix of data and behavior, that's when they start getting "hard-coded" weird-shaped dependencies, and your program turns into fragile spaghetti. Functions and data are a useful architectural technique, and to me it doesn't have that much to do with Clojure or Lisp, although Hickey is certainly a great advocate.
- Roboprog 10y agoInteresting points. As a matter of style, I still prefer using currying over "one trick pony" (single method/function) classes, though. Sometimes this means I have several "layers" of references to the original function, with varying numbers of parameters applied as each layer further specializes (adds configuration). I'm doing most of this type of work in Javascript, though, so YMMV. (PS - also did some work with Lisp in Uni back in the 80s, and sundry imperative/oop/func ; static/dynamic things since)
- chubot 10y agoIf you're using JavaScript, I think that's actually an advantage because your closures can return multiple named methods (in a JS dictionary). To me, closures in Lisp seem a bit impoverished since it's awkward to return more than one method. (Another problem is that I don't like reifying random local variables as program state. State is important; it should be both minimized and made explicit. Classes make it explicit.) Classes with one method are useful, but so are classes with multiple methods. I just stumbled across this post again, and HIGHLY agree with it. Yegge is basically outlining why JavaScript is a better language than Emacs Lisp. I had the same experience with hacking on femtolisp and trying to write my shell in it. http://steve-yegge.blogspot.com/2008/11/ejacs-javascript-interpreter-for-emacs.html http://steve-yegge.blogspot.com/2008/11/ejacs-javascript-int... OCaml and Lisp both have problems with polymorphic print. There were some recent posts on HN about the expression problem, and the duality between FP and OOP, which I liked. But I have to say that print should be polymorphic, full stop. And if your functional language has problems with that, that's the language's problem and not my problem :) Related: http://stackoverflow.com/questions/2497801/closures-are-poor-mans-objects-and-vice-versa-what-does-this-mean http://stackoverflow.com/questions/2497801/closures-are-poor... http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent
- lispm 10y agoIn Common Lisp it is easy to return multiple closures. Emacs Lisp now has lexical closures, too. Common Lisp has no problems with 'polymorphic print'.