17324

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

Лекция

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

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

Украинкский

2013-06-30

115.85 KB

13 чел.

Лекция 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 по функциональности к другим современным языкам.


 

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

48350. Методы формирования и классификация электронно-дырочных переходов 32 KB
  Электроннодырочный переход полученный методом вплавления в полупроводник металла или сплава содержащего донорные или акцепторные примеси называют сплавным переходом а переход полученный в результате диффузии атомов примеси в полупроводник диффузионным. Диффузионный рппереход образованный в результате диффузии примеси сквозь отверстие в защитном слое нанесенном на поверхность полупроводника называют планарным рппереходом. Электроннодырочный переход образованный в результате конверсии полупроводника вызванной обратной диффузией...
48351. РОЛЬ И МЕСТО СТРОИТЕЛЬСТВА В ЭКОНОМИКЕ СТРАНЫ 1.85 MB
  Неустойчивость соотношения строительномонтажных работ по их сложности и видам в течение месяца что затрудняет расчет численного и профессиональноквалификационного состава рабочих. Роль климата и местных условий в строительных работах. К наиболее значимым нарушениям природной среды относятся: нарушение верхнего покрова почвы при выполнении земляных работ и потеря растительного слоя; вырубка лесов и зеленых насаждений и т. Структура сметной стоимости строительства и строительномонтажных работ.
48352. Технология конструкционных материалов. Материаловедение, конспект лекций 1.25 MB
  Поверхностное упрочнение стали Поверхностная закалка стали Углеродистые стали Легированные стали и сплавы. Проектирование рациональных, конкурентоспособных изделий, организация их производства невозможны без должного технологического обеспечения и достаточного уровня знаний в области материаловедения и технологии. Последние являются важнейшим показателем образованности инженера в области техники.
48353. Русский язык и культура речи 283 KB
  Культура речи как учебная дисциплина Культура речи изучается в высших учебных заведениях как составная часть цикла гуманитарных дисциплин предназначенного для студентов всех специальностей. Предметом культуры речи как учебной дисциплины являются нормы литературного языка виды общения его принципы и правила этические нормы общения функциональные стили речи основы искусства речи а также трудности применения речевых норм и проблемы современного состояния речевой культуры общества.; повышение культуры разговорной речи обучение речевым...
48354. Социология 526.5 KB
  Социология logos учение наука об обществе о законах строения функционирования изменения и развития как общества в целом так и отдельных его систем и подсистем вплоть до малых групп. Так история изучает прошлое человеческого общества политология политические процессы и явления экономическая наука экономические процессы во всей их полноте и разнообразии демография количественные показатели рождаемости и смертности т. Метод социологии это специфическое проявление социально-философского метода во всестороннем изучении общества как...
48355. Исследование операций в бухгалтерском учете 272.5 KB
  Проблема выбора решения в условиях неопределенности. Решения могут быть удачными и неудачными разумными и неразумными. Оптимальными называются решения по тем или другим признакам предпочтительные перед другими. Заметим что само принятие решения выходит за рамки исследования операций и относится к компетенции ответственного лица чаще группы лиц которым предоставлено право окончательного выбора и на которых возложена ответственность за этот выбор.
48356. Лекции по акушерству 753 KB
  Гипоксия плода и новорожденного 6 Лекция №6. Гипоксия плода продолжение лекции №5 13 Лекция №9. Родовые травмы плода и новорожденного 61 VII семестр. Морфогенез плаценты зависит от развития маточноплацентарного кровообращения а не от кровообращения у плода.
48357. Дошкольная педагогика 1.61 MB
  В своих научных труда Всеобщий совет Великая дидактика Материнская школа он отразил цели и задачи формы и методы воспитания и обучения детей. Предмет дошкольной педагогики процесс воспитания его цель задачи содержание формы методы средства воспитания детей дошкольного возраста. способствовать воспитанию и обучению детей от рождения до школы теоретический и методический аспект в соответствии с требованиями современного общества; 2. разработать новые концепции и технологии воспитания и обучения детей дошкольного возраста.
48358. Концепции современного естествознания 764 KB
  Специфические черты науки: Наука универсальна она сообщает знания истинные для всего универсума при тех условиях при которых они добыты человеком. сложилась следующая система наук: математические и естественные науки естествознание система наук о природе; социальные науки человекознание система наук о человеке и обществе; технические науки техникознание система наук наиболее тесно связанных с реализацией теоретического знания. Выделяются науки фундаментальные и прикладные. Фундаментальные науки...