FAQ
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

Search Discussions

  • Etienne Kneuss at Mar 1, 2010 at 1:30 pm
    Hello,
    On Mon, Mar 1, 2010 at 1:33 PM, mathieu.suen wrote:
    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

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php


    --
    Etienne Kneuss
    http://www.colder.ch
  • Mathieu.suen at Mar 1, 2010 at 2:15 pm

    Etienne Kneuss wrote:
    Hello,
    On Mon, Mar 1, 2010 at 1:33 PM, mathieu.suen wrote:

    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;".
    You call it import by copy. I would rather say a mix-up of concept
    between value and variable.
    Thanks for your attention

    -- Mathieu Suen

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php

    -- Mathieu Suen
  • Ionut G. Stan at Mar 1, 2010 at 10:06 pm
    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
    On 3/1/10 2:33 PM, mathieu.suen wrote:
    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/

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedMar 1, '10 at 12:33p
activeMar 1, '10 at 10:06p
posts4
users3
websitephp.net

People

Translate

site design / logo © 2022 Grokbase