# Closure/lambda semantic comparaison

- Thread: https://externals.io/message/47070
- Original archive: https://news-web.php.net/php.internals/47070
- Started by mathieu.suen on 2010-03-01T12:33:29+00:00
- Messages: 4
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #47070 — mathieu.suen — 2010-03-01T12:33:29+00:00

URL: https://externals.io/message/47070#47070

Hi,

I am proposing a comparison between PHP closure with lisp one.

First thing to compare is how scope are capture:
Suppose I want to create a function that add.
The common idiom to do it in lisp is:

(defun adder (x) #'(lambda (y) (+ x y)))

Then if I want the add3 method you can do:

(setf (symbol-function 'add3) (adder 3))
(add3 4) => 7


Now let reproduce that in php:

$adder = function ($x) {return function ($y) use($x)  {return $y + $x;};};
$add3 = $adder(3);
echo $add3(4); => 7

Every thing is fine but let change the adder into a counter :
In lisp you could do:

(let ((sum 0))
      (defun counter () (setf sum (1+ sum))))
(counter) => 1
(counter) => 2
(counter) => 3 ...

In other to have the same behavior in PHP you first need to transform 
the let into a lambda which make no difference in lisp:

(funcall #'(lambda (sum) (defun counter () (setf sum (1+ sum)))) 0)

Now we are ready to do it in PHP.

$createCounter = function ($sum) { return function () use ($sum) {return 
++$sum;};};
$counter = $createCounter(0);
$counter(); => 1
$counter(); => 1
$counter(); => 1
...

So that's not the expected behavior.
In oder to have the expected behavior you need to add & in front of $sum.
But & is kind of evil since it mimics dynamic scoping:

$array = array(1, 2, 3);
foreach($array as $pos)
{
    $adders[] = function ($x) use (&$pos) { return $pos+ $x;};
}

foreach($adders as $addIt)
{
   echo $addIt(5);
}

Thanks for your attention

-- Mathieu Suen

---

## #47071 — Etienne Kneuss — 2010-03-01T13:30:02+00:00

URL: https://externals.io/message/47070#47071 · In reply to: #47070

Hello,


> Hi,
>
> I am proposing a comparison between PHP closure with lisp one.
>
> First thing to compare is how scope are capture:
> Suppose I want to create a function that add.
> The common idiom to do it in lisp is:
>
> (defun adder (x) #'(lambda (y) (+ x y)))
>
> Then if I want the add3 method you can do:
>
> (setf (symbol-function 'add3) (adder 3))
> (add3 4) => 7
>
>
> Now let reproduce that in php:
>
> $adder = function ($x) {return function ($y) use($x)  {return $y + $x;};};
> $add3 = $adder(3);
> echo $add3(4); => 7
>
> Every thing is fine but let change the adder into a counter :
> In lisp you could do:
>
> (let ((sum 0))
>     (defun counter () (setf sum (1+ sum))))
> (counter) => 1
> (counter) => 2
> (counter) => 3 ...
>
> In other to have the same behavior in PHP you first need to transform the
> let into a lambda which make no difference in lisp:
>
> (funcall #'(lambda (sum) (defun counter () (setf sum (1+ sum)))) 0)
>
> Now we are ready to do it in PHP.
>
> $createCounter = function ($sum) { return function () use ($sum) {return
> ++$sum;};};
> $counter = $createCounter(0);
> $counter(); => 1
> $counter(); => 1
> $counter(); => 1
> ...
>
> So that's not the expected behavior.
> In oder to have the expected behavior you need to add & in front of $sum.
> But & is kind of evil since it mimics dynamic scoping:
>
> $array = array(1, 2, 3);
> foreach($array as $pos)
> {
>   $adders[] = function ($x) use (&$pos) { return $pos+ $x;};
> }
>
> foreach($adders as $addIt)
> {
>  echo $addIt(5);
> }
>

use($var) will import by copy, so you won't have the behavior you
expect. If you want to keep a value in a function between calls, you
can use "static $sum = 0;".

> Thanks for your attention
>
> -- Mathieu Suen
>
> --
> 
> 
>
>



-- 
Etienne Kneuss
http://www.colder.ch

---

## #47072 — mathieu.suen — 2010-03-01T14:14:52+00:00

URL: https://externals.io/message/47070#47072 · In reply to: #47071

Etienne Kneuss wrote:
> Hello,
>
> 
>   
> > […]
>
> use($var) will import by copy, so you won't have the behavior you
> expect. If you want to keep a value in a function between calls, you
> can use "static $sum = 0;".
>   

You call it import by copy. I would rather say a mix-up of concept 
between value and variable.

>   
> > […]

-- Mathieu Suen

---

## #47075 — Ionut G. Stan — 2010-03-01T22:08:18+00:00

URL: https://externals.io/message/47070#47075 · In reply to: #47070

In my opinion this is consistent with the fact that PHP has no 
block-scoped variables. The situation is similar with the one in JavaScript.

In JavaScript the problem has been solved by Mozilla with so-called let 
definitions[1], which are block-scoped.

1: 
https://developer.mozilla.org/en/New_in_JavaScript_1.7#Block_scope_with_let


> Hi,
>
> I am proposing a comparison between PHP closure with lisp one.
>
> First thing to compare is how scope are capture:
> Suppose I want to create a function that add.
> The common idiom to do it in lisp is:
>
> (defun adder (x) #'(lambda (y) (+ x y)))
>
> Then if I want the add3 method you can do:
>
> (setf (symbol-function 'add3) (adder 3))
> (add3 4) => 7
>
>
> Now let reproduce that in php:
>
> $adder = function ($x) {return function ($y) use($x) {return $y + $x;};};
> $add3 = $adder(3);
> echo $add3(4); => 7
>
> Every thing is fine but let change the adder into a counter :
> In lisp you could do:
>
> (let ((sum 0))
> (defun counter () (setf sum (1+ sum))))
> (counter) => 1
> (counter) => 2
> (counter) => 3 ...
>
> In other to have the same behavior in PHP you first need to transform
> the let into a lambda which make no difference in lisp:
>
> (funcall #'(lambda (sum) (defun counter () (setf sum (1+ sum)))) 0)
>
> Now we are ready to do it in PHP.
>
> $createCounter = function ($sum) { return function () use ($sum) {return
> ++$sum;};};
> $counter = $createCounter(0);
> $counter(); => 1
> $counter(); => 1
> $counter(); => 1
> ...
>
> So that's not the expected behavior.
> In oder to have the expected behavior you need to add & in front of $sum.
> But & is kind of evil since it mimics dynamic scoping:
>
> $array = array(1, 2, 3);
> foreach($array as $pos)
> {
> $adders[] = function ($x) use (&$pos) { return $pos+ $x;};
> }
>
> foreach($adders as $addIt)
> {
> echo $addIt(5);
> }
>
> Thanks for your attention
>
> -- Mathieu Suen
>

-- 
Ionut G. Stan
I'm under construction  |  http://blog.igstan.ro/
