Карринг и Частичное применение функции в PHP

    Что такой карринг и частичное применение функции можно прочитать вот в этой статье.

    Собственно вот реализация на PHP: github.com/Elfet/Functional

    Пример использования частичного применения:


    use Functional\Partial;
    
    function foo($a, $b, $c)
    {
        return "foo<$a, $b, $c>\n";
    }
    
    $p = Partial::apply('foo', 1, 2);
    
    echo $p(3); // foo<1, 2, 3>
    


    Так же можно использовать именованные параметры:

    $p = Partial::applyNamed('foo', array('a' => 1, 'c' => 3));
    
    echo $p(2); // foo<1, 2, 3>
    


    Можно задавать значения по умолчанию:

    $p = Partial::apply(function ($a, $b, $c = 'c') {
        return "function()<$a-$b-$c>\n";
    }, 1);
    
    echo $p(2); // function()<1-2-c>
    


    Или добавить параметры позже:

    class Boo
    {
        public function woo($a, $b, $c)
        {
            return "Boo::woo<$a, $b, $c>\n";
        }
    }
    
    $p = Partial::apply(array($boo, 'woo'));
    $p->applyArgs(1, 2);
    $p->applyNamedArgs(array('b' => 3));
    
    echo $p(); // Boo::woo<1, 3, 2>
    


    Пример карринга:

    use Functional\Curry;
    
    function foo($a, $b, $c)
    {
        return "foo<$a, $b, $c>\n";
    }
    
    $c = new Curry('foo');
    
    echo $c->invoke(1)->invoke(2)->invoke(3); // foo<1, 2, 3>
    


    Или использовать сокращённый синтаксис:

    echo $c[1][2][3]; // foo<1, 2, 3>
    
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 37

      +16
      для меня тема оказалась сложной. Можете помимо технических деталей описать где это использовать, в чем плюсы использования данного метода перед стандартными?
        +7
        Присоединяюсь к просьбе, еще хотелось бы примеров кода, как оно используется на практике в реальных задачах.
          –3
          Это осколки функционального программирования и ленивого выполнения кода. Из того что я читал, можно посмотреть в сторону learnyouahaskell.com/: интересный учебник по хаскелу.
          Например learnyouahaskell.com/higher-order-functions#curried-functions. Но лучше прочтите книжку с самого начала.
            0
            Хотелось бы от кого-нибудь услышать два абзаца: где использовать и пример кода. Две книги — это многовато.
          +2
          Как по мне — переведенные примеры в ридми с гитхаба — недостаточно для статьи
            +5
            Вообще то тут ридми является переводом статьи на хабре. :)
              +1
              Хотел поделиться с обществом, а что ещё написать не знаю.
            +3
            В начале статьи надо было указать, что для ее усвоения требуется знание базовых принципов функционального программирования.

            По крайней мере, если бы я не прочитал Programming Erlang, то думаю вообще закрыл бы эту статью, даже не читая.
              +1
              Чтобы понять принцип и успешно применять на практике частичное применение функций никакого предварительного знания функционального программирования не нужно.
              +3
              return "foo<$a, $b, $c>\n";
              

              Думаю, это неудачный пример кода. Мне сначала показалось, что эта строка имеет какую-то роль в определении частичной функции (какая-то магия с eval'ом, например).
              На самом же деле это просто код, чтобы продемонстрировать, что с поданными аргументами что-то происходит.
                +1
                Угу, простое
                return "Called foo({$a}, {$b}, {$c})\n"
                
                было бы очевидней.

                P.S. Люблю {} использовать при подстановке
                +2
                Такое можно проделать и без библиотек, не так гибко, но большая часть функционала останется, а учитывая что такие вещи не так часто нужны, использования того класса не очень то и оправдывает себя.
                class Boo
                {
                    public function woo($a, $b, $c)
                    {
                        return "Boo::woo<$a, $b, $c>\n";
                    }
                }
                
                $f = array('Boo', 'woo');
                $params = array(1, 2);
                $params[] = 3;
                
                echo call_user_func($f, $params);
                
                  +3
                  На тему смешивания парадигм есть забавная статья lukeplant.me.uk/blog/posts/why-learning-haskell-python-makes-you-a-worse-programmer/
                  Это прикольно конечно, но лично мне не хотелось бы подобную магию увидеть в коде с которым я работаю
                    –2
                    Это же PHP. Смешивание парадигм тут было отродясь.
                      0
                      Второй пункт для C# из статьи устарел. А вот для PHP, в который пришли лямбды — да, стал верен…
                      0
                      А почему вы сделали что карринг нельзя вызвать через __invoke?
                      Идейно же результатом карринга является функция.
                        0
                        Действительно offsetGet вместо __invoke. Очень странно. Еще более странно, что я нашел куда притулить данные инструменты :)
                          0
                          Я понял. ()()()() syntax error, а [][][][] нормально.
                          Хотя может в PHP 5.4 исправили.
                            0
                            Исправили.
                          +1
                          Круть. Мысли правильные.
                          Теперь ждем реализацию монад в PHP! =)
                            +2
                            Товарищи, уже второй день думаю куда это присобачить. Придумать не получается. Может кто-нибудь предложит конкретный пример? А лучше три.
                              –3
                              считаю, что раз найти применение не получается, то не пришло еще время (и опыт), либо оно просто не нужно Вам. У вас свои парадигмы/стили/подходы программирования
                                0
                                Это понятно, что умный и опытный человек сам до всего додумается со временем. А хочется видеть пример, который позволит не слишком умным и не слишком опытным людям понять как это использовать.
                                  –3
                                  я к тому, что если это еще не используешь, значит это еще тебе не нужно. имхо.
                                    +2
                                    Интересный подход. Надо развить эту мысль.

                                    Берём постулат:
                                    1. Если что-то не используешь, значит тебе это ещё не нужно.

                                    Берём программиста, который ещё ничего не использует. Из постулата значит, что ему ничего не надо. Значит он ничего не напишет. Но как видно, программисты что-то пишут. Значит одного этого постулата мало. Дополним.

                                    2. Некоторые вещи, которые использует программист получаются случайно.

                                    Из этих двух постулатов следует вывод: всё, что использует программист, когда-то начал использовать случайно.
                                0
                                Такие инструменты используют из-за удобства, а не из-за того, что это клево.
                                Если можно обойтись более простым решением — совсем необязательно прибегать к карри/партиал. Можно писать без всего этого в веб.

                                PHP нужен для сайтов/админок/форумов/блогов/итд, а не различных телекомуникационных систем, для которых существуют «всякие» эрланги.
                                  +1
                                  Понятно, что это делается для удобства. Но понять в чём именно удобство не всегда можно понять только по описанию и применению.

                                  Взять хотя бы портянки.

                                  Портянка — кусок ткани для обматывания ноги, нижнее бельё для ног, прямоугольный кусок тёплой и прочной ткани, который использовался в старину вместо носка.

                                  Чтобы портянка не разматывалась при ходьбе и беге, её нужно особым образом (плотно) наматывать на ногу. Делать это следует от носка ноги и непременно «наружу», а не «внутрь», чтобы при ходьбе она не сбивалась и не натирала ногу.

                                  А из этого описания и способа применения нифига непонятно какие у неё есть достоинства.

                                  Поэтому хотелось бы посмотреть на примеры и именно для этого языка.
                                  +1
                                  Можно использовать как замену ООП, когда у нас класс с конструктором с параметрами и кучей вызовов одного метода. Например, логеры, мэйлеры и т. п.
                                    +1
                                    Возможно, как раз будет полезно в свете этой статьи «Перестаньте писать классы».

                                    А ещё такой подход мог бы добавить некоторого изящества в код:
                                    $ch = curl_init();
                                    // set URL and other appropriate options
                                    curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
                                    curl_setopt($ch, CURLOPT_HEADER, 0);
                                    // grab URL and pass it to the browser
                                    curl_exec($ch);
                                    // close cURL resource, and free up system resources
                                    curl_close($ch);
                                    

                                    Примерно вот так:
                                    $ch = curl_init();
                                    $setUrl = Partial::apply('curl_setopt', $ch, CURLOPT_URL);
                                    $setOutputHeader = Partial::apply('curl_setopt', $ch, CURLOPT_HEADER);
                                    $exec = Partial::apply('curl_exec', $ch);
                                    $close = Partial::apply('curl_close', $ch);
                                    
                                    // set URL and other appropriate options
                                    $setUrl("http://www.example.com/");
                                    $setOutputHeader(0);
                                    // grab URL and pass it to the browser
                                    $exec();
                                    // close cURL resource, and free up system resources
                                    $close();
                                    
                                      –1
                                      Это же ужас. Вы удвоили код и не сделали его более легкочитаемым.
                                        +1
                                        А то, я ещё и не так умею. Тем более, если подвернётся какой-нибудь новый приём.
                                • UFO just landed and posted this here
                                    0
                                    Польза есть — узнать, хотя бы, что такая штука вообще существует.
                                    • UFO just landed and posted this here
                                        0
                                        Я предлагаю производить меньше негатива :)
                                        Вот для меня польза была — я узнал о такой штуке, о чем собственно честно и написал.
                                        Да может для кого-то пользы от статьи и немного, и тема может быть не совсем раскрыта, но говорить категорично, что пользы НОЛЬ не совсем верно, по-моему.
                                        • UFO just landed and posted this here
                                            +1
                                            Повторюсь, я не спорю что статья отличная хорошая или какая-то еще, я лишь написал в ответ на «Пользы от публикации хабрапользователям — НОЛЬ!», что лично мне она принесла пользу. К тому же, как часто бывает на хабре, — возможно в комментарии придут люди, знающие по теме и напишут что-то полезное.
                                            Вот вы, на сколько я понимаю, в этой теме разбираетесь? Ну так может быть лучше вместо гневных комментариев написать что-то полезное по этой теме?

                                  Only users with full accounts can post comments. Log in, please.