Обновить
2
0
Dmitry Soshnikov@dsCode

Пользователь

Отправить сообщение
Спасибо за статью. Не приходилось сталкиваться с F#, но, думаю, язык интересный.

> Преподавали ли вам функциональное программирование в вузе?

Да, в ГУАП'е (питерский универ аэрокосмического приборостроения) практическую часть ФП преподают на Common Lisp'e.

P.S.> прошел по ссылке — blogs.msdn.com/sos/, и понять не могу — что это за мой сайт? Вроде не было таких у меня. =) Вспомнил Вас, мы еще ВКонтакте один раз встречались на почве «Двойного тёзки» ;)
> А ручками создать файлы нельзя?

Правило Генерации: «Избегайте ручного ввода кода, при любом удобном случае пишите программы, которые бы писали программы.» (С) «Философия UNIX».
Да, совершенно верно; уже ниже упомянул — habrahabr.ru/blogs/starting_programming/50120/#comment_1316458
> Единственно возможным вариантом (и то с натяжкой)

Для этого и создан этот синтаксический сахар. Без натяжек.
> То есть мы просто не хотим ловить деление на 0 в данном месте?

Не ловить в смысле в общих except'ax или сделать еще внутренний try-except в основмном try'e? Первый случай, как раз-таки нежелателен — получается мы общими except'ами пытаемся отловить все, соответственно, и в try'e у нас каша — сколько случаев мы в нем пытаемся защитить?

Если будет внутренний try-except во внешнем try — да, так, конечно, можно, тогда не должно быть внешнего else-блока (поскольку он тоже выполнится, т.к. во внешнем try'e все пройдет успешно).

Однако, если вынести успешный код в else и сделать там try-except — мы разграничиваем типы исключений.

В общем, повторю, это лишь удобный синтаксический сахар (ничто не запрещает написать этот успешный код со своими try-except'aми и после основного try'я)

> А если в else будет эксепшн, finally отработает?

Да.
Да? о чем тогда вообще на Хабре пишут? ;)
> Вы пытаетесь делать слишком далеко идущие выводы :)

Я никогда не пытаюсь ;) (либо делаю, либо нет) я лишь размышляю, и делаю выводы (а далеко идущие или нет — это уже другой вопрос)

Да, все зависит лишь от задач конторы. Если у вас прикладные задачи, для которых уже написано тонна готовых решений — нет смысла писать на «ассемблере» интернет-магазин ;)

Если же контора занимается разработкой новых подходов, способных «осчастливить человечество», то — у них и цели здесь другие. Но они так же — работаю и получают зарплату (и, если оценивать справедливо, — получают больше прикладных программистов, поскольку и знаний применяют больше)

По поводу же велосипедов — тоже от уровня и требований зависит. К примеру, у меня в JS всегда свой фреймворк был написан (который легче и быстрее всех этих Prototype'ов.js, jQuery и т.д.).

А полностью подавлять инициативу и самообразование подчиненных — тоже не стоит (иначе — наймите лучше «кодеров» (программистов без собственной мысли), которые будут просто выполнять приказы, не двигаясь ни вправо, ни влево, а не программистов). Наоборот, компания должна сопутствовать образованию своих сотрудников.

Но, другое дело, когда эти «научные изыскания» совсем не связанны с работой — тогда да, здесь уже другой разговор (и вы имеете в виду именно этот случай; я понимаю).
> ((A and S) or B)

только наоборот — S and A or B (если сравнивать с A if S else B), но сути это не меняет:

поскольку, действительно, эти два варианта работают по-разному: второй вариант трактует полученный ноль (S and A) как ложь и, соответственно, переходит к вычислению в B. Поэтому, если нужно учитывать 0, второй вариант уже не подходит. Поэтому, да — для общего случая лучше использовать вариант с A if S else B.

Для одиночных же проверок (a and b, c = x || 'defaultValue'), будут работать нормально.
> Все равно не понятно ЗАЧЕМ это нужно.

a = {'x': 0}
try:
    b = a['x']
    #b = a['c']
    #print(1 / b)
except KeyError as e:
    print('KeyError')
except Exception as e:
    print('Common Exception')
else:
    print(1 / b)
finally:
    print('finally')

В данном случае, программа упадет на else (поскольку будет деление на 0).

Если в try'e использовать только вторую строку (b = a['c']), то поймается KeyError и else не будет обработан.

Если в try'e использовать строки 1 и 3 (b = a['x'] и print(1 / b)), то поймается общий Exception, но! — не для того случая, который мы защищали (b = a['несуществующий_ключ']), а для «непредвиденного» — из «успешного» кода (в данном случае — тривиальный — деление на ноль, где ноль — предварительно полученный код из защищаемого кода). В данном случае, наш Exception поймал исключение, но предназначался этот Exception не для этого исключения. Т.е. мы будем считать, что мы что-то обработали, на самом же деле — код должен упасть в else, сигнализируя, что помимо кода, который мы защитили, есть еще один такой код и его так же надо обрабатывать, но, возможно, совершенно другими классами исключений (это основная суть).

Так что здесь вопрос, скорее, идеологический (ничто не мешает использовать этот «успешный» код и в самом try'e и вообще — за пределами try-блока), просто ввели такой синтаксический сахар в виде else.

P.S> в Ruby этот else-блок тоже присуствует в данном блоке.
flex (сканер) + bison (парсер)
> В университете — да.
> А если этим будет заниматься мой подчинённый в рабочее время — настучу по голове.

Да не только в университетах. Просто условно все задачи можно разделить на:

— задачи на инструментарий (написание языков, сред, фреймворков, виджетов и т.д.)
— прикладные задачи «на данные», с использованием уже готовых вещей из первого пункта.

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

Все это вытекает из усиления абстракций, habrahabr.ru/blogs/webdev/45552/#comment_1152704 — здесь кратко говорил об этом.

И не только в университетах, есть и такие «работы», на которых «подчиненные» пишут для потребителей усиленные абстракции. Далее некоторые потребители сами становятся созидателями (относительно нового уровня абстракции). Вы пользуетесь каким-нибудь фреймворками? Их разве в университетах написали? Нет, так же люди ходят на работу, так же им деньги за это платят.
> чето как то слишком сложно всё… слишком на низком уровне что ли.

Наоборот (если вы про автоматизированные средства построения сканеров и парсеров, типа javacc). Здесь вам не надо самому строить парсеры для LL / LR (1) — грамматик, здесь вы просто описываете формальную грамматику. Да, понадобится знать регулярные выражения, но, все же, это более эффективно и позволит избежать ошибок.

> Ох уж эти велосипедисты

Ну, есть и работы научные и академические, а не только прикладные-потребительские. Кто-то же за вас написал эти автоматизаторы :) Кому-то просто потреблять — мало, им нужно знать, как это работает. И «изобретение велосипеда» — это отличное подтверждение практикой изученной теории.
или jflex + cup (агалоги Си-шных flex'a и bison'a, который часто используются для этих целей) — так же строят сканер и парсер по заданным формальным грамматикам.
habrahabr.ru/blogs/starting_programming/50120/#comment_1315751

Блок else идеологически выделен, чтобы вынести в него код, который должен быть выполнен в случае успеха (в случае, если в try не произойдут исключений). Теоретически и практически, весь код блока else можно и записать в сам try, однако, в try желательно писать только то, что должно быть защищено. Остальной успешный код лучше вынести в else, поскольку в самом этом коде могут быть также исключения и, если они будут в try'e, то будут обрабатываться нашими except'aми, которые предназначены для обработки для конкретных типов исключений.
> else: # ловим все остальные исключения
> То есть смысл в том, чтобы отловить любое исключение, которое вылезет (считаем, что самого базового класса нет)

Ветвь else выполнится только в том случае, если блок try не сгенерировал исключение. Рациональное объяснение: лучше дополнительный код, который должен быть выполнен при успешном try'e помещать в else, это позволит избежать обработку исключений, сгенерированных кодом, который мы не собирались защищать.
elif

P.S> в Ruby еще «интересней» — elsif =)
Поддерживаю. Если официальный сайт технологии выкладывает официальный Programming Stryle Guide, то это правило хорошего тона и профессионализм — использовать эти рекомендации. При обучении, тоже лучше сразу приучать писать согласно этим правилам.
> Существует так же краткая форма записи (аналог тернарного оператора в Си): X = A if условие else B

Можно еще упомянуть про логические операторы or и and, которые так же можно использовать для данной конструкции:

x = условие and a or b


Отсюда можно выводить и следующие производные:

b = a or 10 # либо «а», либо дефолтное значение

# можно, например, и функцию вызвать по условию:


def c(): print('O.k')

b and c() # функция «с» вызовется только в том случае, если b — истинно


Все дело в особенности операторов or и and:

— or возвращает левый операнд, если он истинен, иначе — правый;
— and — вернет результат самого правого операнда, если все предыдущие были истины.

Когда условия одиночны, то такая запись может быть очень удобной (не нужно городить лишние if-else-блоки), если же условий несколько, то лучше воспользоваться if-else'ами, чтобы не портить читаемость кода.

P.S.> в JavaScript и Ruby аналогичная функциональность этих операндов.
> как ты думаешь, стоит?

Ну, в принципе, подобных статей уже навалом. Однако, всегда можно рассказать о некоторой теме предмета более развернуто и, если статья массовая, а не академическая, то — как можно доступней, чтобы не отпугивать людей, а наоборот привлекать, показывая, что JS — прост, но очень изящен. К тому же, если чувствуешь потребность написать, — конечно пиши.
> (замыкания и прототипы)… объясните мне

Было уже много статей, но попробую рассказать кратко (но очень подробно) и простыми словами в этом комменте:

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

Пример:

var a = 10; // глобальная переменная

function b() {
  var c = 20; // локальная переменная
  alert(a + c); // 30
}

В данном случае, функция «b» порождена в глобальной области видимости, и, соответственно, ей доступны как свои локальные переменные, так и глобальные. Однако, переменная «а» является свободной для функции «b» (т.е. переменная «а» не определена в области видимости функции «b»). Не буду вдаваться в подробности и механизм реализации этого эффекта в JS (variable object и scope chain), но главное здесь понять, что функция имеет доступ, помимо своих переменных, к переменным, которые были объявлены в той же области, что и сама функция, а также к переменным из областей стоящих выше в иерархии.

Пример:

var a = 10;
function b() {
  var c = 20;
  function d() {
    var e = 30;
    function f() {
      var g = 40;
      // доступна своя "g", а также 
      // "а", "c" и "е" из областей выше
      alert(a + c + e + g); 
    }
    f();
  }
  d();
}
b();

В принципе, это очевидно, и реализовано практически во всех языках.

При подходе, описанном выше, ни переменная «с», ни переменная «e», ни переменная «g» не будут существовать после вызова функции «b». Т.е. (локальные) переменные доступны только в области видимости, в которой они описаны, а также в областях, стоящих ниже в иерархии.

А теперь главная особенность, которая и позволит создать эффект замыкания. Функции в JS — это обычые (переменные) объекты, которые можно вернуть (после описания) из других функций:

function a(i) {
  var z = 10;
  function b() {
    alert(i + z);
  }
  return b; // возвращаем функцию "b"
}

var c11 = a(1);
var c12 = a(2);

c11(); // 11
c12(); // 12

Т.к. функция «а» возвращает функцию, то переменные с11 и с12 — есть функции. Но! Не просто функции, а функции, помнящие всю цепь областей видимости, начиная от области видимости, в которой они порождены (в данном случае, это внутренняя функция «b»). Т.е. функции c12 и c12 будут помнить область видимости функция «а».

В данном случае, переменные «i» и «z» в отличии от случая, описанного выше (с «с», «е» и «g») живы после того, как функция «а» отработала. Это и есть замыкание (т.е. значения переменных «i» и «z» замкнулись в функции «b», которая затем вернулась из «а» и стала доступна для вызова через переменную c11 (аналогично и с12)).

Поэтому, замыкание — это не только, когда свободные переменные из внешнего scope'a доступны внутреннему, но и тогда, когда они могут быть доступны после того, как функция, порождающая внешний scope отработает.

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Дата рождения
Зарегистрирован
Активность