6 ms·
One thing you haven't mentioned but it is related to anonymous functions (or lambdas) and is an important part of the fp style is passing around functions as fi
by DrJokepu 16y ago
One thing you haven't mentioned but it is related to anonymous functions (or lambdas) and is an important part of the fp style is passing around functions as first class objects. It is quite unusual in imperative programming and it is normally only used there to provide callbacks.
Let's say, you want to write a function that exports your video library to an arbitrary medium. In FP, one way to do this is to create generator functions that create DVDs, Blu-Ray discs, etc. Then your export function would take the input and a generator function, and export the library using that function. In Common Lisp:
(defun make-dvd () ... )
(defun make-blu-ray () ... )
(defun export-library (data make-medium) ... )
And then you would
(export-library *my-data* #'make-dvd)
(export-library *my-data* #'make-blu-ray)
Or if you want to use an inline lambda (anonymous) function:
(export-library *my-data* (lambda () ...))
- jacquesm 16y agoI'm going to do a completely separate post on the subject of first class functions because I think it is too complicated a subject (and with too many implications) to be squeezed in there as an aside, besides that I don't think I'm qualified just yet to write the article in a strong enough way yet. More understanding is required first. It must be funny to all the FP gurus here to see someone struggling to understand the things that are second nature to them, but I find that it is surprisingly hard to teach this old dog a new trick. One part of me wants to say 'enough of this' all the time and reach for a C compiler just to get the job done :)
- ww520 16y agoJavascript's treatment of anonymous function is the easiest to understand for imperative background since it uses the same syntax as a named function. Defining an anonymous function: function(a, b) { return a+b; } Giving an anonymous function a name (or assigning to a variable): var add = function(a, b) { return a+b; } Defining a function with a name (just a shorthand of the above): function add(a, b) { return a+b; } This makes it clear that the object stored in 'add' is a function object and can be passed around like other objects. That's the essence of the 'function as a first class object' concept. If you have the time, I highly recommend watching the SICP video. It very gently introduces most of the FP concepts and many others. It's a classic. http://freevideolectures.com/Course/2378/Structure-and-Interpretation-of-Computer-Programs/1 http://freevideolectures.com/Course/2378/Structure-and-Inter...
- kanak 16y agoWow that's almost the same as scheme. Here's the scheme version of the above code: Your example would be translated as: (lambda (a b) (+ a b)) ;; making an anonymous function (define add (lambda (a b) (+ a b))); ;; calling the anonymous function "add" (define (add a b) (+ a b)) ;; syntactic sugar for above.
- mquander 16y agoI haven't had the chance to test it out yet, but my impression has always been that first-class functions should be presented to imperative/OO programmers as a replacement for polymorphic functions. Frequently, for an abstraction X where I need different but similar behavior in different situations, I'll implement X by passing around functions in Scheme or Clojure, but I'd implement X with inheritance and polymorphism in C#. The frequent advantage (in my opinion) is that passing functions is more flexible, conceptually simpler, and usually shorter to write. Do you see it that way?
- jules 16y agoThe real trouble here is probably closures. function foo(x) { return function(y) { return x+y; }; } bar = foo(3) bar(5) // Returns 8, wait how did the x in the inner function remember the 3?! // It's supposed to be gone already because the call to foo is over... One way to understand this is to notice that it always "just works". It seems like magic. The 'aha' for me was when I learned how closures are implemented.
- ww520 16y agoOne way to understand closure is to know that a function object actually contains both the instruction code and an environment table holding the variable bindings, bar = [ code = { return x+y; }, env = [x:3] ]. When bar is called, it uses x's value in its environment. That's closure. Easy, right?
- jules 16y agoYes, although it gets trickier with mutation. For example: x = 0 foo = function(){ x += 1 } bar = function(){ x -= 1 } Somehow you need to update bar's x too when you call foo and foo's x when you call bar. One way to do this by wrapping x in an object of its own, for example in a single element array that just contains x. I think the implementation of closures in Mono got this wrong, calling foo would have no effect on bar and vice versa (perhaps it's fixed now).
- ww520 16y agoI was hoping to keep thing nice and simple. :) You brought up a good point in the subtle problem in using closure. Yes, in some implementation of closure, both foo and bar access the same closed variable x. The best way to treat this is to view closed variables as global variables in different scopes. Global variables imply they are shared. e.g. x = 1 // environment in the global scope function baz() // environment in baz's scope shared by foo and bar x = 3 foo = function() { x += 1 } bar = function(){ x -= 1 } return [foo, bar] foo1, bar1 = baz() // create a baz_env1 [x:3] bar1() // baz_env1 [x:2] foo1() // baz_env1 [x:3] foo1() // baz_env1 [x:4] foo2, bar2 = baz() // create a baz_env2 [x:3] bar2() // baz_env2 [x:2] x = 10 // At this point, // global environment's x is 10 // baz_env1 x is 4 // baz_env2 x is 2 Hope that clarifies things.
- eru 16y agoI don't really get why people are so excited about anonymous functions. First class functions may be exciting. Not having to give a name to your functions, is not.
- xiongchiamiov 16y agoImagine if you were forced to program where you had to do, say, foo = 'foo' baz(foo) When a language forces the same thing upon you with functions (damn you, Python!), it's rather nice to be free of it.
- eru 16y agoPython forces you to name functions, if you want to use the full power of function abstraction. If you just want to compose functions or so, you do not need to name them. But I see your point.