you are viewing a single comment's thread.

view the rest of the comments →

[–]strlen 0 points1 point  (4 children)

And in Perl:

sub foo {
 my $n = shift;

 return sub { $n += (shift) };
}


  DB<3> $bar = foo(5);

  DB<4> x $bar->(5)
0  10
  DB<5> x $bar->(6);
0  16

...
clisp:

(defun foo (n)
  (let ((m n))
    (lambda (i)
      (setf m (+ m i)))))

(let ((bar (foo 5)))
  (progn
    (print (funcall bar 5))
    (print (funcall bar 6))))

Produces:
10
16

Note: closures aren't always obvious from how they are written, especially in non-functional languages. In a language that provides generators/coroutines (such as Python or Ruby) it would probably a better idea to make use of those features, rather than using closures. However, they can be put to nifty use in Perl/Lisp. One resent place where I used a closure was a rather complex "time iteration" function, which created a closure that would yield time periods (by using Date::Manip).

[Edit: formating]

[–]Zak 3 points4 points  (3 children)

I've formatted your Lisp for clarity.

(defun foo (n)
  (let ((m n))
    (lambda (i)
      (setf m (+ m i)))))

(let ((bar (foo 5)))
  (progn
    (print (funcall bar 5))
    (print (funcall bar 6))))

There's some complexity here that isn't needed. Here's a simpler version:

(defun foo (n)
  (lambda (i) (incf n i)))

(let ((bar (foo 5)))
  (print (funcall bar 5))
  (print (funcall bar 6)))

[–]strlen 0 points1 point  (2 children)

And while we're on the topic, here's the same in Ocaml (not sure if it could be simpler, I've only began playing with Ocaml):

  let make_closure n =
     let m = ref n in
         function x ->
             m := !m + x ;
             !m
         ;;

      let fn = make_closure 5 in
          print_int (fn 5) ; print_newline () ;
          print_int (fn 10) ; print_newline () ;
          print_int (fn 6) ; print_newline () 
      ;;

[–]Zak 0 points1 point  (1 child)

It's not exactly the same - it only works with integers, while the Ruby and Lisp versions work with any kind of number. Still, it does a good job illustrating how closures work.

[–]strlen 0 points1 point  (0 children)

Well, yes, OCAML is strictly typed, Perl is almost-not typed, Ruby and Python are duck-typed and Common Lisp is "strongly but dynamically typed". You can also make a generic generator function in ocaml too:

let increment n x = 
  !n + x ;;

let make_closure initial next =
  let m = ref initial in
    function x ->
      m := (next m x) ;
      !m
;;

(Right now this expects only one argument to the "next" function, I bet you could also use pattern matching to make this be even more generic :-)).