17324

Элементы функционального программирования в C#

Лекция

Информатика, кибернетика и программирование

Лекция 10. Элементы функционального программирования в C План 1. Элементы функционального программирования в C 2. Делегаты 3. Лямбдавыражения и лямбдафункции 1. Элементы функционального программирования в C Даже из названия функциональное программирован...

Украинкский

2013-06-30

115.85 KB

16 чел.

Лекция 10. Элементы функционального программирования в C#

План

1. Элементы функционального программирования в C#

2. Делегаты

3. Лямбда-выражения и лямбда-функции

1. Элементы функционального программирования в C#

Даже из названия «функциональное программирование» ясно, что основной упор в нем делается на функции (в математическом смысле), т. есть, y=f(x). Функциональное вычисление – функция (или если быть точнее – «чистая функция», pure function) – должна принимать некоторые аргументы (входящие данные) на входе, производить вычисление и возвращать некоторый результат. При этом функция не должна создавать никаких побочных эффектов. Под побочными эффектами понимается возможность функции:

  1.  Изменять глобальные (статические в терминах C#) переменные.
  2.  Вызывать другие функции, которые могут создать побочный эффект.
  3.  Заниматься любым вводом/выводом внутри функции.
  4.  Посылать или принимать некие сообщения.

По сути, пункты 2-4 представляют собой разновидности одного и того же – изменение состояния посредством вызова.

Таким образом, функция не имеет право делать ничего, что могло бы изменить состояние чего бы то ни было (например, переменных в памяти). Все, что может сделать функция – это произвести вычисления и выдать результат.

Программирование в функциональном стиле позволяет сделать код короче и безопаснее.

C# не является полностью языком функционального программирования, но содержит элементы, позволяющие писать программы в функциональном стиле.

К основным элементам функционального программирования, поддерживаемых в C#, можно отнести: делегаты, лямбда-выражения и деревья выражений, а также новый интегрированный язык запросов Language Integrated Query (LINQ).

2. Делегаты

Делегаты в C# являются аналогом ссылки на функцию C++. Сама по себе функция (метод) или ее имя не является чем-то, чем можно было бы манипулировать, но если поместить ее в делегат, появится возможность ссылаться на нее, а значит передавать в другие функции и возвращать функции из других функций. Таким образом, можно (с большой натяжкой) сказать, что делегаты являются аналогами функциональных типов в языках функционального программирования.

Основное применение делегатов с C# - обработка событий.

Многие классы стандартной библиотеки .Net Framework используют делегаты для уведомления о произошедших в них событиях. Соответственно, разработчики среды .NET сочли, что будет целесообразно ввести общий стандартный тип делегата, который будет использоваться во всей библиотеке. Его прототип представлен ниже.

public delegate void EventHandler(

  // Ссылка на объект, вызвавший событие.

  object sender,    

  // Параметры, описывающие событие.  

  EventArgs e

);

Этот делегат принимает всего лишь два параметра, что явно маловато для универсального делегата. Но все же оказывается, параметров с лихвой хватает для передачи любой информации. Сам по себе класс EventArgs не содержит ни одного члена, способного передавать какую бы то ни было информацию. Он введен лишь для обобщения. Когда необходимо передать дополнительную информацию, вводится новый класс, производный от EventArgs, в котором уже и вводятся поля, передающие необходимую информацию. В одной общей библиотеке у класса EventArgs 100 потомков, и их количество от версии к версии среды исполнения неуклонно растет.

При обращении к событию, имеющему тип данного делегата, в качестве параметра необходимо передать ссылку на текущий объект (this), а во втором параметре экземпляр класса EventArgs или производного от него.

SomeEvent(this, EventArgs.Empty);

где свойство Empty попросту возвращает пустой экземпляр типа EventArgs. В принципе, его можно создать и самому воспользовавшись оператором new.

SomeEvent(this, new EventArgs());

Пример

Приложение для генерации вариантов тестов. Используются стандартые делегаты.

Одни и те же действия можно выполнить при нажатии кнопки, выбором пункта меню или кнопки панели инструментов. Например, генерация вариантов.

     private void btmGentest_Click(object sender, EventArgs e)

       {

//кнопка Button – фрагмент кода

           DateTime Date;  //дата с календаря в формате DateTime

           //Снимаем данные с полей формы

           string Disc = txtDisc.Text;                     //Дисциплина

           string Teacher = comboBox1.Text;            //Преподаватель

           try

           {

               if (Disc.Length == 0)

               {

                   throw new Exception("Введіть назву дисципліни");

               }

               if (Teacher.Length == 0)

               {

                   throw new Exception("Введіть прізвище викладача");

               }

               Date = monthCalendar1.SelectionRange.Start;   //дата, выбрання на календаре. По умолчанию, текущая дата

               string strDate = Date.ToString();             //преобразование даты в строку

               int numberVariant = (int)numericUpDown1.Value; //к-во вариантов заданий.

           

}

---------------------------  ----------------------------------

      private void toolStripButton1_Click(object sender, EventArgs e)

       {

           //кнопка панели инструментов Генерувати - делегат события btmGentest_Click

           btmGentest_Click(this, new EventArgs());

       }

--------- ------------------- ------------------------------

       private void генеруватиToolStripMenuItem1_Click(object sender, EventArgs e)

       {

           //меню Генерувати

           //кнопка генерации - делегат события btmGentest_Click

            btmGentest_Click(this, new EventArgs());

}

3. Лямбда-выражения и лямбда-функции

Функциональное программирование основано на лямбда исчислении, предложенным Алонзо Черчем.

Википедия дает такое определение:

Ля́мбда-исчисле́ние (λ-исчисление, лямбда-исчисление) — формальная система, разработанная американским математиком Алонзо Чёрчем, для формализации и анализа понятия вычислимости.

λ-исчисление может рассматриваться как семейство прототипных языков программирования. Их основная особенность состоит в том, что они являются языками высших порядков. Тем самым обеспечивается систематический подход к исследованию операторов, аргументами которых могут быть другие операторы, а значением также может быть оператор. Языки в этом семействе являются функциональными, поскольку они основаны на представлении о функции или операторе, включая функциональную аппликацию и функциональную абстракцию.

Базисом функционального программирования являются лямбда выражения и анонимные функции.

Анонимные функции позволяют создать функции, у которых нет имени.

В контексте языков программирования под лямбда-функцией понимают анонимную функцию. Т.е. функцию, которой не сопоставлено никакое имя, просто значение функционального типа.

Анонимная функция – это оператор или выражение "inline", которое можно использовать каждый раз, когда ожидается тип делегата. Ее можно использовать для инициализации именованного делегата или подставить вместо типа именованного делегата в качестве параметра метода.

Существует два типа анонимных функций:

  1.  Лямбда-выражения
  2.  Анонимные методы  

Лямбда-выражение — это анонимная функция, которая содержит выражения и операторы и может использоваться для создания делегатов или типов дерева выражений.

Во всех лямбда-выражениях используется лямбда-оператор =>, который читается как "переходит в". Левая часть лямбда-оператора определяет параметры ввода (если таковые имеются), а правая часть содержит выражение или блок оператора.

Лямбда-выражение x => x * x читается как "x переходит в x x раз". Это выражение может быть назначено типу делегата следующим образом:

delegate int del(int i);

static void Main(string[] args)

{

   del myDelegate = x => x * x;

   int j = myDelegate(5); //j = 25

}

Оператор => имеет тот же приоритет, что и оператор присваивания (=) и является правоассоциативным.

Многие языки программирования поддерживают работу с анонимными функциями.

Примеры

С#

delegate(int x){return x +1; }

Pyton

lambda x: x + 1

Lisp

(lambda (x) (+ x 1))

PHP (http://blog.kron0s.com/anonymous-functions-in-php )

Переменные-функции

До того как сказать что-либо об анонимных функциях, взглянем на концепцию PHP известную как переменные-функции. Она заключается в том, что если добавить к переменной круглые скобки, то интерпретатор PHP сначала проверит, не существует ли функции с именем равным значению переменной и если она есть - выполнить ее. Это можно увидеть на следующем примере:

  1.  function Hello($name)
  2.  {
  3.      echo "Привет, $name";
  4.  }

Мы можем вызвать эту функцию, используя переменную, хранящую ее имя. И это может быть очень полезно, если имя функции не определенно до момента выполнения.

  1.  $func = "Hello";
  2.  $func("Мир!");
  3.   
  4.  // результат:
  5.  //Привет, Мир!

Другой пример, используя класс и статический метод:

  1.  <?php
  2.  class CHello
  3.  {
  4.      static function Hello($name)
  5.      {
  6.          echo "Привет, $name";
  7.      }
  8.  }
  9.  $func = "Hello";
  10.  CHello::$func("Мир!");
  11.   
  12.  // результат:
  13.  // Привет, мир!
  14.  ?>

Анонимные или лямбда функцииc php

Бывает, необходимо создать небольшую локальную функцию, состоящую всего из нескольких строк, например, для обратного вызова. Глупо загрязнять глобальное пространство имен такого рода одноразовыми функциями. Гораздо лучше создать анонимную или лямбда функцию используя create_function.

Рассмотрим на примере:

  1.  <?php
  2.  $str = "Привет, Мир!";
  3.  $lambda = create_function('$match', 'return "Друг!";');
  4.  $str = preg_replace_callback('/Мир/', $lambda, $str);
  5.  echo $str ;
  6.  ?>

Здесь мы создали маленькую безымянную (анонимную) функцию, которая вызывается в функции preg_replace_callback. Хотя create_function позволяет создать анонимные функции, это не часть языка, а "хак". PHP 5.3 поддерживает по настоящему анонимные функции как часть языка. Мы создаем безымянную функцию и присваиваем её переменной и затем просто используем эту переменную как функцию.

Пример:

  1.  <?php
  2.  $func = function($name)
  3.  {
  4.      echo "Привет, $name\n";
  5.  };
  6.   
  7.  $func("Мир!");
  8.  $func("Алексей!");
  9.   
  10.  // результат:
  11.  //Привет, Мир!
  12.  //Привет, Алексей!
  13.  ?>

Заметьте, что в конце определения функции есть точка с запятой. Она необходима, так как такое определение функции это утверждение, а после определения утверждения всегда должна быть точка с запятой. Еще один пример:

  1.  <?php
  2.  $str = "Привет, Мир!";
  3.  $func = function($match)
  4.  {
  5.      return "друг!";
  6.  };
  7.   
  8.  $str = preg_replace_callback('/Мир/', $func, $str);
  9.  echo $str ;
  10.  ?>

Анонимные и вложенные функции

PHP позволяет вкладывать функции внутрь друг друга. Рассмотрим на примере. Функция censorString принимает строку как параметр и заменяет нужные слова в строке на "*". Функция censorString определяет вложенную функцию replace, которая используется при вызове preg_replace_callback. Учитывая то, что функция replace используется в нашей программе только в функции censorString, лучше всего определить ее как вложенную, чтобы не загрязнять пространство имен.

  1.  <?php
  2.  function censorString($string, $censor)
  3.  {
  4.      function replace($match)
  5.      {
  6.          return str_repeat("*", strlen($match[0]));
  7.      }
  8.   
  9.      return preg_replace_callback('/'.$censor.'/', 'replace', $string);
  10.   
  11.  }
  12.   
  13.  echo censorString("Привет, мир!", "мир");
  14.  echo censorString("Привет, мир!", "Привет");
  15.   
  16.  // результат:
  17.  // Привет, ***!
  18.  // Fatal error: Cannot redeclare replace()
  19.  ?>
  20.  

При таком определении функции как в примере выше, вложенная функция не существует до тех пор, пока не начнется выполняться родительская функция. Как только выполняется родительская функция (censorString), вложенная функция появляется в глобальном пространстве имен. Теперь мы можем получить доступ к вложенной функции из любого места программы. Проблема состоит в том, что при повторном вызове родительской функции будет сделана попытка передекларировать вложенную функцию, что вызовет ошибку, так как она уже существует. Решение в том, чтобы использовать вложенную функцию, как это показано ниже. (Обратите внимание на точку с запятой в конце вложенной функции.)

  1.  <?php
  2.   function censorString($string, $censor)
  3.  {
  4.      $func = function($match)
  5.      {
  6.          return str_repeat("*", strlen($match[0]));
  7.      };
  8.   
  9.      return preg_replace_callback('/'.$censor.'/', $func, $string);
  10.   
  11.  }
  12.   
  13.  echo censorString("Привет, мир!", "мир");
  14.  echo censorString("Привет мир!", "Привет");
  15.  
  16.  // результат:
  17.  // Привет, ***!
  18.  // ******, мир!
  19.  ?>

Теперь вложенная функция появляется только на время выполнения censorString. Итак, мы можем повторно вызывать функцию censorString без того, чтобы вызвать ошибку передекларации.

Другой способ определить вложенную функцию:

  1.  <?php
  2.  function censorString($string, $censor)
  3.  {
  4.   
  5.      return preg_replace_callback('/'.$censor.'/', 
  6.                                  function($match) 
  7.                                  {
  8.                                      return str_repeat("*", 
  9.                                             strlen($match[0]));
  10.                                  },
  11.                                  $string);
  12.   
  13.  }
  14.   
  15.  echo censorString("Привет, мир!", "мир");
  16.  echo censorString("Привет, мир!", "Привет");
  17.   
  18.  // результат:
  19.  // Привет, ***!
  20.  // ******, мир!
  21.  ?>

Замыкания

Замыкание это анонимная функция со своим контекстом. Короче говоря, это функция, которая знает о переменных, не определенных в ней. Рассмотрим на простом примере. Скажем, мы хотим создать анонимную функцию, которая умножает число на 5.

  1.  <?php
  2.  $mult = function($x)
  3.  {
  4.      return $x * 5;
  5.  };
  6.   
  7.  echo $mult(2);
  8.   
  9.  // результат:
  10.  // 10
  11.  ?>

Если мы хотим чтобы число умножалось на 7 вместо 5, нам необходимо создавать другую функцию. Вместо того чтобы создавать несколько почти одинаковых функций, создадим замыкание, используя конструкцию use, которая дает анонимной функции доступ к внешним переменным и "замыкает" их в текущей функции.

  1.  <?php
  2.  $multiply = function($multiplier)
  3.  {
  4.      return function($x) use ($multiplier)
  5.      {
  6.          return $x * $multiplier;
  7.      };
  8.  };
  9.   
  10.  // $mul5 теперь содержит функцию, которая умножает аргумент на пять
  11.  $mult5 = $multiply(5);
  12.   
  13.  // $mul7 теперь содержит функцию, которая умножает аргумент на семь
  14.  $mult7 = $multiply(7);
  15.   
  16.  echo $mult5(5);
  17.  echo $mult7(5);
  18.   
  19.  // результат:
  20.  // 25
  21.  // 35
  22.  ?>

Лямбда функции и замыкания приближают PHP по функциональности к другим современным языкам.


 

А также другие работы, которые могут Вас заинтересовать

30854. Функциональные системы 23 KB
  Функциональные системы Функциональная система это временная динамическая саморегулирующаяся организация все составные компоненты которой взаимодействуя обеспечивают достижение полезных приспособительных результатов. В функциональной системе есть периферические и центральные составляющие: Периферические составляющие: А Исполнительные соматические вегетативные и эндокринные компоненты в том числе и поведенческие включающие механизмы формирование результата. Б Полезный приспособительный результат. В Рецепторы...
30855. Рефлекторная регуляция 34.5 KB
  Передача возбуждения в синапсе . иррадиация возникшего возбужденияраспространение возбуждения на рядом лежащие нейроны. концентрация возбуждениястягивание возбуждения на один или несколько нейронов. Индукция бывает: положительная когда наводится процесс возбуждения отрицательная когда наводится процесс торможения.
30856. Рефлексы 31 KB
  Рефлексы Рефлексы делятся на безусловные и условные. Безусловные рефлексы Это врожденные рефлексы которые не требуют предварительной выработки при действии раздражителя реализуются однотипно без особых предварительных условий. Безусловные рефлексы являются видовыми т. Рефлексы направленные на сохранение вида.
30857. Вегетативная нервная система 35.5 KB
  Очаговое представительство нервных центров СНС и ПСНС в ЦНС и. СНС боковые рога тораколюмбального отдела спинного мозга. ПСНС три зоны где лежат её центры:а мезенцефальный отдел ветви в составе глазодвигательного нерва зрачок некоторые слюнные железы;б бульбарный отдел лицевой языкоглоточный нерв и n. ВНС представлена двумя отделами: а симпатическая нервная система СНС б парасимпатическая нервная система ПСНС.
30858. Гуморальная регуляция функций 39.5 KB
  Классификация биологически активных веществ БАВ: Неспецифические метаболиты. Специфические метаболиты: а тканевые гормоны парагормоны; б истинные гормоны. Неспецифические метаболиты продукты метаболизма вырабатываемые любой клеткой в процессе жизнедеятельности и обладающие биологической активностью СО2 молочная кислота. Специфические метаболиты продукты жизнедеятельности вырабатываемые определенными специализированными видами клеток обладающие биологической активностью и специфичностью действия: а тканевые...
30859. Гуморальная регуляция функций. Межсистемный уровень 29.5 KB
  Истинные гормоны. Парагормоны. Истинные гормоны БАВ вырабатывающиеся в специализированных железах внутренней секреции обладающие дистантным действием и высокой активностью. Делятся по принадлежности к железам внутренней секреции половые гормоны тиреоидные гормоны и т.
30860. Гипоталамо-гипофизарная система 24 KB
  Меланостатин Релизингфакторы регулируют выделение гормонов передней доли гипофиза большая часть которых гландулярные регулируют деятельность других желез внутренней секреции выделение ими гормонов. Регуляция в системе гипоталамус гипофиз осуществляется по принципу отрицательной обратной связи избыток гормонов в крови торможение их выработки: 1. Короткая петля регуляции: Рецепторы ГФ реагируют на концентрацию тропныхсобственных гормонов изменяют их выделение и опосредовано уровень гормонов периферических желез вн. Длинная...
30861. Передняя, задняя и промежуточная доли гипофиза 35.5 KB
  Передняя доля гипофиза Все гормоны передней доли являются веществами белковой природы пептиды белки гликопротеиды. Гормоны передней доли гипофиза: 1. Соматотропный гормон СТГ гормон роста соматотропин. Этот гормон белковой природы 191 аминокислота 1стимулирует синтез белка в органах и тканях 2способствует утилизации аминокислот 3увеличивает дифференцировку и созревание клеток.
30862. Щитовидная железа 32.5 KB
  Тиреокальцитонин гормон сберегающий кальций в организме снижает его уровень в крови способствует переходу кальция в костную ткань усиливает минирализацию костной ткани угнетает активность остеокластов ; активирует активность остеобластов угнетает процессы всасывания Са в кишечнике; угнетает процесс реабсорбции Са в почечных канальцах. Паратгормон повышает содержание кальция в крови: активирует функцию остеокластов разрушающих костную ткань активирует процессы всасывания Са в кишечнике; усиливает процесс реабсорбции Са в...