лекции (2015) (1160856), страница 6
Текст из файла (страница 6)
Окончательно (83), оставили ленивые andи or.В JavaScript если операнды не bool, то возвращаются сами значения операндов (Денис: еслинаписать 'foo' or 'bar' то получится 'foo', а не true или false)Циклы, переходыFortran: единственный цикл – DO, с фиксированным числом повторений. Все остальное переходы; кконцу — 3 типа goto (+ еще появились).1967: Дейкстра написал статью «Goto statement considired harmful» -- говорит, нужно выбрать 1форму управляющих структур, чтобы ясна была структура алгоритма.Программа — последовательность преобразований предикатов (формальное программирование –дает доказательство правильности программы).P1 (k) P2, где k — управляющая структура с определенной семантикой – четко определено, какойименно предикат P2 получится из P1.P -- инвариант цикла, еслиP – верно для любого состояния при вычислении Swhile B do SP and not S – верно если цикл закончитсяИдея “доказательного программирования” – очень сложна, т.
к. любое доказательство сложное →более современная идея «программа – надежная совокупность ненадежных компонент» → assert,тестирование и т. д.1967 – «Notes on Structural Programming» 3 статьи → появление структурного программирования.Управляющих структур, которые надо использовать достаточно мало – программист тем лучше, чемменьше видов упр. структур он использует201965 – доказали, что любую простую программу можно реализовать только с использованием 0), 1),4).3 статьи:1. Дейскстры о goto (против DS-programs -- Dish of Spagetti, где используется только goto)2. Хоара(на её основе Вирт, добавив for i := e1 to/downto e2 do S, создал Pascal)3.
???1974 -- Д. Кнут, “Structural Programming with goto statements”, пишет, что идея Дейкстры в разделениипрограммы на уровне абстракции и дальнейшей детализации пока не дойдем до уровня операторовЯП.Пишет, что указанных управляющих структур не хватает, т.к. многие программы имеют вид:21prepare;while B dobeginprocess;prepare;end●●●2 раза повторяется prepareпришлось подгоняться подсуществующую структурулучше сделать goto, если такойструктуры нету в ЯПИтого:1) условные переходы -- if-then-else или многовариантный выбор (цепочка if или case)2) циклы (while-do; do-while; for)3) “Заменители goto” (break; continue; return, дополнительные goto, throw)В 70-м появились языки без goto: Java, Modula-2В Java goto зарезервировано, но не используется, и до сих пор не появился. Но зато естьрасширенный break M; где M -- метка начала конструкции, из которой надо выйти (Денис: в случаевложенных for-ов например, можно сделать break для внешнего из внутреннего)RAII -- В C++ Resource Acquisition Is Initialization, любой ресурс надо завернуть в класс,инициализация в конструкторе, а уничтожение в деструкторе, при этом из-за свертки стека всеуничтожится.
Если нет свертки, то возникнет куча проблем (try-catch позволяет не использоватьgoto для чистки ресурсов в конце программы).Составные структурыЗаметим, что простые управляющие структуры составные:if then S1 else S2 -- S1 и S2 операторы, которые надо различать(Учебник: во всех языках: if A if B else C <==> if A { if B else C })Есть два варианта: без явных терминаторов и с явными терминаторами.Без явных терминаторов -- вводится составной оператор (обычно что-то типа блока в C -- {операторы } из него можно делать goto)Но есть объемлющий блок-тело функции -- из него goto наружу сделать нельзяPascalCwhile B do Srepeat S1...S2 until Bwhile (B) Sdo S while (B)Везде -- ровно 1 операторЯвный терминатор -- явно составной операторbegin ...
end -- связан с понятием блока, а не составного оператораПоявился особый оператор многовариантного выбора:Ada: <Modula-2, Fortran, Oberon>Python(явный терминатор -- “отсутствие отступа”)if B1 thenS1elsif B2 thenS2elsif B3 thenусловный операторсостоит из 3 частейelseif несчитается if (иначеif B:pass - явный пустой опер.elif B2:S2else:22S3elseS4endifS3нужно было быстолько же endifписать).4 типа циклов в Modula-2:while B doloopSendloopdoloopSend loopuntil BOberonfor …loopSend looploopSend loopAdaRubyпридуман японцем и сильноотличается от европ. языковloopSendРешили, что цикл Кнута (выход по?? цикла) выглядит не удобно,поэтому добавили:loopwhen B ==> exit;end loop;можно и отступом и begin-endif BS1else beginS2end(Денис: далее идет описание наворотов, которые относятся к Ruby)X = B? e1 : e2 ←→ X = if B then e1 else e2 end;if B then S1 end ←→ S1 if B (для вложенных ассоциативн.
правая)S1 unless B ←→ S1 if not BЦикл:while BSend(Андрей: Навороты с блоками в Ruby тут вообще не в тему, потому что скорее относятся кзамыканиям и лямбда-функциям, чем к управляющим конструкциям.)Есть возможность присоединения блока к некоторому выражения (можно блок применить китератору).f.readlines do | line |…end← →f.readlines { | line| … }На самом деле эта страшная штука аналогична вызову функции c лямбдой-замыканиемНапример, как это могло выглядеть на JavaScript:f.readlines(function(line) { … });Преимущество блоков над лямбдами в чистоте - нет слова function3.times { … } -- блок выполнится 3 раза23Многовариантный выбор caseМожно сделать много if, а можно эффективно реализовать таблицей переходов.В ЯП высокого уровня есть:case e ofC1 : S1;C2 : S2;…endADARubycase e ofwhen 1, 2, 3, 5, 9, 11 ⇒ seq fwhen list 2 ⇒ seq Nwhen other s == seq Nel(??)end casecasewhenwhenwhenwhenwhenendeval1 then Sval2, val3, … valN then S2Class then S3range then S4predicate then S5здесь добавили специальный сложныйоператор сравнения ===, которыйиспользуется только внутри case и делаетсложные штуки, позволяя писатьумопомрачительные case-ыcase awhen 1..5"It's between 1 and 5"when 6"It's 6"when String"You passed a string"else"You gave me #{a} -- I have noidea what to do with that."endC, Java (незавуалированный goto)switch (e){case N:default:}case и default - простоспециальные метки<==>if (e == i)goto case ielsegoto defaultУчебник: в C# наличие break требуется после всех case и default.В Python нет case, но его можно сомнительно промоделировать:def switch(K):{f1: f1, f2 : f2, … fn : fn}[k]()foreachЦиклы наиболее общего вида:24Cfor (e1; e2; e3) SAdafor f1 := e1 do e2 step e3 do…endСейчас появляются циклы вида:foreach (var t in C) S, где С -- коллекция (последовательность) элементовС# : IEnumerable имеет метод GetEnumerator(), который возвращает интерфейс IEnumerator:свойство Current -- текущий элементbool MoveNext() -- следующий, false если его нетReset() -- переводит в началоforeach берет ссылку на C, получает IEnumerator, и делает Next() и какие-то действия сCurrent.Вид: foreach (T v in C) SC++11: for (T el : C) SJava: for (T v: C) SСредства развития ЯПНужно уметь1.
вводить новые абстракции2. защищать эти абстракцииДругие способы передачи управления, не входящие в базис:● Подпрограммы● Исключительные ситуацииПонятие подпрограммы, как абстракции алгоритма появилось еще в Fortran.Связанные понятия:● передача потоков управления и их управление● потоки данных● подпрограммные ТДПодпрограммы и сопрограммы в ЯПCallee(вызываемая пр-Subroutine в Fortran всегда ведет себяодинаково, когда бы ее не вызвали.Выполнение Subroutine каждый разначинается сначала.Caller25Coroutine (сопрограмма) - вызов происходиттуда, где она потеряла управление, вместоcall и return повявляется resume (1команда вместо двух, но изначально 1 call)Modula-2Введен ТД Coroutine (для адреса сопрограммы).PROCEDURE NEWPROCESS (VAR C : COROUTINE, P : PROC, N : CARDINAL);Строка задает: инициализацию программы, процесс без параметров, размер рабочей области → Сбудет работать по процедуре PPROCEDURE TRANSFER (VAR C1, C2: COROUTINE); → передает управление от C1 к C2.Архитектура стека появилась для реализации подпрограмм (frame, activation record для хранениеданных о вызове).Но у каждой сопрограммы должен быть свой стек, что и подразумевается в передаче параметра N -размера области для стека реализации и т.п.)PythonСопрограммы используются в генераторах (генераторы являются частным случаем итераторов).Пример сопрограммы (возвращает элемент, и далее не выполняется, пока не попросят еще).def fib(): # генерируем числа Фибоначчиn1 = 1yield n1n2 = 1yield n2while True:yield n1 + n2n1, n2 = n2, n1 + n2Теперь можно писать:for f in fib():print(f)Еще можно писать:f = fib()n1 = next(f) // 1n2 = next(f) // 2n3 = next(f) // 326(Денис: далее описывается механизм generator.send(value), вставлю лучше сюда выжимку из документации и примерсо stack overflow, т.к.
из лекций я ничего, оказалось, не понял)В конце версий 2.x yield стал полностью выражением → возвращает определенное значение иповявляется функция:generator.send(value)Resumes the execution and “sends” a value into the generator function. The value argument becomes theresult of the current yield expression. The send() method returns the next value yielded by the generator,or raises StopIteration if the generator exits without yielding another value.То есть механизм, позволяет передавать в генератор информацию для обработки. Информацияприходит, как результат вызова yield.Пример:>>> def double_inputs():...while True:...x = yield...yield x * 2...>>> gen = double_inputs()>>> gen.next() #run up to the first yield>>> gen.send(10) #goes into 'x' variable20>>> gen.next() #run up to the next yield>>> gen.send(6) #goes into 'x' again12>>> gen.next() #run up to the next yield>>> gen.send(94.3) #goes into 'x' again188.5999999999999В Python 3.5 возможен реально параллельный запуск сопрограмм, путем использования ключевогослова async.async def readl_db():…data = await(db.fetch(“Select …”)) -- ожидает завершенияyield from -- конкретно указываем от кого хотим получить данныеНакладные расходы в Python на создаение процесса - 8 МБ, для сопрограммы - 1 КБ.C#Для итерирования нужно реализовывать IEnumerable, возвращающий IEnumerator:// Collection of Person objects.