лекции (2015) (1160856), страница 8
Текст из файла (страница 8)
Базовый класс - в нём переопределяем особый вызов родительского base.fm() +делегатский тип данныхСначала не было ничего и надо ?непонятный набор букв похожий на “поре платив”? писать, нопотом появились анонимные классыButton b1, b2,b3;b1 = new Button {protected void onClick() {...super.onClick();}}b2 = …; //тут b2 заменяем без необходимости реально создавать много классов. Тут появилсятермин closure - замыкание{если переменные видны где-то в области; используя внутри нек. области, то она захватывается ипри необходимости видна и вне}33Делегаты в С#.
Ключевое слово eventОбычный процедурный ТД. Крайне ограниченная функц-ть, обычно имеет вид “подписка” ”рассылка”. Язык C# тем не менее включает в себя понятие «делегаты», аналогичноефункциональному типу, но не основанное непосредственно на концепции указателя и являющеесяболее надежным.Делегат – это тип, который представляет собой ссылки на методы с определенным спискомпараметров и возвращаемым типом. Делегаты используются для передачи методов в качествеаргументов к другим методам.Делегаты обладают достоинствами функционального типа данных, и в то же время не имеют егонедостатков.
Внешне объявление делегата очень похоже на объявление функционального типа.Объявление делегата начинается с ключевого слова delegate, за которым идет спецификацияфункции:delegate - только внутри какого-то классаclass X {delegate void f(int); /* в System есть Delegate и цепочкиделегатов;теперь можно писать f d; операции:*/1) :=class y{void m(int p){...}static void R (int i){} //оба полностью удовлетв. виду f}}y = new Y();d = y.m; //ссылка на методd = y.R; //просто функция{//надо было писатьd = new f(y.m);d = new f(y.R);}2) К экземпляру делегата можно применять следующие операцииИзначатьно значение делегата пустое● = - присваивание● += добавление функции● -= удаление функции● вызовПрисваивание делегату какой-то функции - стирает всё содержимое делегата и создает в нёмсписок из одной функции, += добавляет в список ещё функции(удовлетворяющие видуделегата)Теперь операция вызова делегата будет вызывать по очереди все функции из списка,передавая каждой функции аргументы из вызова3) () d(0) - каждый метод вызываетя с параметром 0, порядок не определен.“+=” - “подписка” “()” - “рассылка” //в лекциях 2012 года () называют уведомлениемf d; - каждый может сделать +=, -=, (), =(т.е.
удалить всех), хочется, чтобы был владелец и могчто-то делать, но все ТД единообразны -> !делегаты не являются типом данныхevent - специальное новое ключевое слово, появилось в 99 году. реализует “подписку-рассылку”,является модификатором переменной делегатского типа. + появилась возможность захвата (closure)И если область делегата в области видимость в области видимости local, то local захватывается.События это особый тип многоадресных делегатов, которые можно вызвать только из класса илиструктуры, в которой они объявлены (класс издателя).Если на событие подписаны другие классыили структуры, их методы обработчиков событий будут вызваны когда класс издателя инициируетсобытие.{delegate (int x) {return 2*x;}}34delegate event Run(int x);{ Run f; T local;f = delegate (int x) {return 2*x + local;}}Лямбда-функции●В Python всё простоf = lambda x: 2*xprint(f(1)) // 2Можно использовать замыкания (захват переменных):y = 5f = lambda x : x + yprint(f(3)) // 8Лямбды в питоне могут содержать только одно выражение, результат которого являетсярезультатом функции.Таким образом лямбды являются чистыми функциями (без побочных эффектов).
Нельзяменять переменные из лямбд-замыканий●JavaScriptfunction f(x) { return 2*x; } //определяет функциюfunction g() {...y = 1;function f(x){return x+y;}return f;} // захват уфункции в js - это объекты первого порядка (их можно передавать как аргументы в функции,присваивать переменным и т.п.).Вообще это не лямбда, а замыкание (Closure, захват переменных).Лямбда функция в JS выглядит так:var lambdaSum = function(a, b) { return a + b; };Основная суть лямбд - анонимность (имя функции не обязательно):var sum = [1,2,3].reduce(function(a, b) { return a + b; }); // sum = 6(сумма элементов)Можно еще так писать:var sum = [1,2,3].reduce(lambdaSum);Или даже так:function sum(a,b) { return a + b; }var sum = [1,2,3].reduce(sum);В стандарте языка JS под названием ES6 (он же ES2015) можно писать так:var sum = [1,2,3].reduce( (a,b) => a + b );var sum = [1,2,3].reduce( (a,b) => { return a + b; } );Использование Лямбда + Замыкание:var delta = 10;35var oldArray = [1,2,3];var newArray = oldArray.map(function(n) {return n + delta;});// newArray = [11,12,13]В отличие от Java/Python, замыкания могут изменять переменные:var value = 10;function subtract(n) {value -= n;return value;}var result = subtract(4); // result = value = 6●В компилируемых языках программирования надо добавить делегатов.С#.
(x) => 2*x ⇔ x => 2*x //генератор делегатов, это выражениеdelegate int Run(int)Run f;f = x => 2*x // тут происходит генерация делегата,// идет вывод типа из определения делегата (инт){//есть generic -> можно написатьRun <int, int>Libor<int> ⇔ void Libor(int)}Заметим, что лямбда-выражения не могли появиться без обобщений( generic)● Java. захват, в 2005 появились обобщения, в 2014 в Java8 окончательно появились лямбдафункцииОбщий вид: (список параметров) -> выражение.
// на фото 914 есть пара примеровиспользования.Андрей ([915-924], завершено)Функторы и лямбда-фукнции в С++Если в классе перегружен operator(), то такой класс называется функтором. Это какальтернатива лямбдам.Например можно делать свертки:Есть стандартная функция в <algorithm>:count_if(f1, f2, predicate)где f1 и f2 - итераторы, predicate - функтор от одного аргументаона может принимать как указатель на функцию типа bool (*)(int), либо объект класса сперегруженным operator().В Си++11 появились лямбда-функции:count_if(f1, f2, [](int n) { return n%2 == 0; });Семантика как в лиспе, даже замыкания есть.Про них подробнее тут: http://en.cppreference.com/w/cpp/language/lambdaЕсли внутри блока идет обращение к глобальным переменным, или переменным функции, внутрикоторой создается лямбда, то будет ошибка, т.к.
захват контекста (замыкание) по-умолчанию36выключен. Чтобы включить, надо писать [&] или [=] или [varname] или [&varname] (смотри поссылке выше).Можно даже писать [=, &x, &y]. (Захват x и y по ссылке, остальных по значению)А еще появился обобщенный класс function в библиотеке <functional>. Его можноиспользовать для объявления функций высшего порядка.В Java есть лямбды, но там захват переменных можно делать только read-only.Модульность (C++, Модула-2, Oberon)C++typedef не определяет нового типа, а только создает алиас.Потому что при создании нового типа можно перегружать функции, ноtypedef int newtype;void f(int);void f(newtype);выдает ошибку.Единственное, что в плюсах создает новый тип - это директива class.Физический модуль - это единица компиляции (трансляции)Часто логический и физический модули совпадают (как в плюсах)Модула-2Модули бывают локальные и глобальные (библиотечные).
Весь код по умолчанию пишется вглавном локальном модуле. Локальный модуль содержит и объявления и реализацию.Структура локального модуля:MODULE ModuleName… definitions …BEGIN… module code …END ModuleNmae;module code будет выполнен сразу при инициализации модуля. Поэтому он и используется как точкавхода в программу.Глобальные модули нужны для написания библиотек. В них код разделяется на определения(заголовки) и реализацию. Определение и реализация пишутся в разных файлах. Имя файла какправило совпадает с именем модуля.Файл HELLO.DEFDEFINITION MODULE HelloEXPORT Hello;PROCEDURE Hello;END Hello;Файл HELLO.MODIMPLEMENTATION MODULE Hello;FROM Terminal2 IMPORT WriteString, WriteLn;PROCEDURE Hello;BEGINWriteString(“Hello”);WriteLn;END Hello;37END Hello;TYPE T;PROCEDURE INIT_T(VAR P:T);DESTROY(VAR P:T);Это реализация абстрактного типа данных, внутренней стркутуры которого мы не знаем.У модулей в Модуле-2 можно задать специальную маску устойчивости:MODULE M[4];4 воспринимается как битовая маска.
Суть этой маски в том, что она запрещает некоторыепрерывания при выполнении модуля M.Еще в Модуле-2 есть сопрограммы, но это уже совсем другая историяOberonНет разделения на определение/реализацию, нет главного модуляВсе модули могут экспортировать процедуры типа PROC.MODULE MTYPE Obj* = RECORDX : INTEGER;Y* : INTEGER; ← Экспорт отдельных полей структурыEND;PROCEDURE P*; ← * - значит экспортVAR Done*- : Boolean; ← *- - значит только на чтениеEND MЗа пределами модуля нельзя обращаться к X:VAR V : M.ObjV.Y = 1; ← МожноV.X = 1; ← НельзяВ этом языке к содержимому импортированного модуля можно обращаться только через точку,нельзя как в Модуле-2, импортировать конкретный объект. (см.
ниже)Допускается создать псевдомодуль только с выделенными именами (?)Логические модули (Modula-2, C)Есть в языках Ада, Оберон, Модула-2, Эйфель, … - все основаны на понятии модуля, как на понятииконейнера языковых ресурсовМожно определить интерфейс модуля (перечисление того, что надо экспортировать и реализацию.Тогда реализация экспортирует все в глобальное пространство имен(wtf?)Вообще видимость и доступность - это разные понятия.Видимость бывает двух типов:38а) непосредственная (прямая, доступ к имени модуля/функции/переменной без точки, напримерWriteString)б) потенциальная (доступ к имени только через уточнение модуля/объекта с помощью точки,например Terminal2.WriteString)Modula-2В модуле-2 доступно все что видно (нет модели доступа - все что видим, можно брать)Непосредственно видимы только стандартные имена и имена библиотечных модулей (определениймодулей)Импорт позволяет подгрузить дополнительные модули:IMPORT <список имен модулей>IMPORT M;Доступ после импорта все-равно через точку: M.PХотя можно делать и непосредственный импортFROM M IMPORT P;При компиляции файл с определением модуля M.DEF переходит в M.SYMА файл с реализацией модуля M.MOD переходит в M.OBJC#ifndef FILENAME#define FILENAME...#endifСтандартная защита от повторного включения заголовочных файловextern нужно писать только в заголовочных файлах, но переопределять чужим typedef (wtf?)Модульные языки (Delphi, Object Pascal, Ада)Turbo Pascal, Ada, Modula-2, OberonВ простом случае Модуль - это набор ресурсов, которые можно реиспользовать, а не создаватьзаново.Любой класс - это модуль.DelphiМодульный подход как в Модуле-2, но ОО (объектно-ориентированный?)Общее глобальное пространство именВидимость: потенциальная, непосредственнаяПорождение имен - определяющее (должно быть одно, если без перегрузки), использующиеНепосредственно видимы только именя библиотечных модулейИмпорт: uses M;Все имена непосредственно импортируются (без точки можно юзать)Object Pascalunit:interface ← переходит таблицу символовimplementation ← переходит в obj-файл39Итого получаем, что программа - это набор модулей.