Химия и PascalABC.Net

А мне больше по душе окислительно-восстановительные реакции. Так что давайте встретимся втроём. Обычно на троих всё легче понимается.

1 лайк

“Облегчения работы мусорщика” может быть только по сравнению с чем то. Раз лямбды это сахар над обычными подпрограммами - это сравнение не может быть с этими подпрограммами (ибо они равны). А с чем ещё сравнивать - не представляют.

Если программа пишется на максимальной производительности - лучше наоборот избавляться от лямбд. Особенно тех, что захватывают переменные. Хоть JIT и неожиданно хорош в оптимизации лямбд, если нужна вся производительность - контролировать захват переменных надо самостоятельно, своими классами-контейнерами.

Когда такой контроль не нужен - в приоритет становится чистота программы. То есть если вы используете какую то подпрограмму 1 раз - это лямбда.

А ещё лямбды не обязательно куда либо передавать. Из них получаются прекрасные вложенные подпрограммы. При чём в отличии от обычных вложенных подпрограмм - они ещё и захватывают переменные:

begin
  
  var MyFunc1: (real, string)->string := (x,s)->
  begin
    Writeln((x,s));
    Result := x.ToString(s);
  end;
  
  // P значит Percent
  MyFunc1(123.456, 'P').Println;
  
end.

Тут MyFunc1 будет видна только в теле begin-end, где объявлена. Это одно из мощнейших средств инкапсуляции (в данном случае - скрытия видимости того, что не должно использоваться во вне) в паскале.

1 лайк

“Окис-востас” мы на первом курсе проходили реально за три занятия )))

А вот почему сульфаты меди и железа кристаллизуются именно в пяти- и семиводные купоросы соответственно, толком так и не объяснили.

И диаграмму “железо-углерод” учили на манер “Отче наш” …

В общем, любой предмет требует изучения, а “Физика за 12 часов”," Паскаль за 2 часа", “Электротехника за три дня” - это лохотроны.

1 лайк

А скажите, это откуда у вас такие слухи?

Что касается памяти:

begin
  var a, b, c: byte;
  
  var p1: Action0 := ()->
  begin
    Writeln(a, b);
  end;
  
  var p2: Action0 := ()->
  begin
    Writeln(b, c);
  end;
  
end.

Обычно лучше когда для p1 и p2 создаётся 1 общий контейнер.
А иногда важно чтоб когда p1 удалена, а p2 ещё используется - сбощик мусора мог удалить a. С лямбдами это невозможно.


Что касается скорости:

procedure p0(var a: byte);
begin
  ...
end;

begin
  var a: byte;
  
  var p: Action0 := ()->
  begin
    p0(a)
  end;
  
  Writeln(a);
end.

Лямбда захватывает и возможно (нельзя знать т.к. передали var-параметром) изменяет a. Значит после лямбды - нужно использовать версию a из контейнера.

Но a из контейнера - это поле класса, хранимое в куче. А что если мы знаем что лямбда точно не изменяет a и нам нужна переменная со стека?
Ну, в отличии от предыдущего случая - это хотя бы реализуемо:

procedure p0(var a: byte);
begin
  ...
end;

begin
  var a: byte;
  
  var captured_a := a;
  var p: Action0 := ()->
  begin
    var a := captured_a;
    p0(a)
  end;
  
  Writeln(a);
end.

Вот только, получается, нам пришлось засорить пространство имён именем, которое нельзя использовать. Это плохо.

Поэтому имеет смысл объявить свой класс-контейнер:

procedure p0(var a: byte);
begin
  ...
end;

type
  //ToDo имя, релевантное для ситуации
  Container1 = auto class
    a: byte;
    
    procedure p;
    begin
      p0(a);
    end;
    
  end;
  
begin
  var a: byte;
  
  var p := Container1.Create(a).p;
  
  Writeln(a);
end.

Конечно оба примера - это случаи чрезвычайно тонкого контроля. Но об этом и шла речь.

А скажите, доктор, откуда у Вас такие картинки? :stuck_out_tongue_winking_eye:

Это понятно. Но это странное утверждение.

Вы говорите, вот лямбды есть в языке. Но не используйте их - это неэффективно.

Что-то здесь не так.

Более того, сильно не так в треде где мы специалисту в области химии пытаемся объяснить, что такое лямбда-выражения и как и зачем их использовать.

В моё время были программисты-ассемблерщики, которые возмущались по любому поводу если программа была написана на языке высокого уровня, и требовали переписать её на ассемблер ради эффективности.

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

Вы всё про своё… Я же не зря это добавил

@John_Nada сказал что думал “использовать лямбды это для особых случаев”, а я ответил “НЕ использовать лямбды - вот что для особых случаев”.

Понятно. Ну - не сбивайте человека.

1 лайк
  • может и неэффективно, но всё равно вместо одной Select, к примеру, не сделаешь 100 на разные случаи жизни.

Эффективно это когда используешь функцию “Замесить” и “Нарубить”, и их выполняют правильно, а не как двое из ларца, которые ожидают что-то вроде вовка.тесто.замесить и вовка.дрова.нарубить :wink:

Ничего не понял )

1 лайк

По моему имелся в виду такой ужас:

{$region Select'ы}

function Select_Sqr(self: sequence of integer): sequence of integer;
begin
  foreach var i in self do
    yield i.Sqr;
end;

function Select_SqrSqr(self: sequence of integer): sequence of integer;
begin
  foreach var i in self do
    yield i.Sqr.Sqr;
end;

{$endregion Select'ы}

Не пишите ужасы в этом треде пожалуйста.

1 лайк

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

В этом плане лямбда-выражения “неэффективны”. Но зато можно сделать один Select , а не много “ужасов” типа Select_Sqr.

На самом деле .Select не эффективен только как метод Linq. Сами колбеки хорошо оптимизируются.
Когда то сам тестировал и впал в ступор когда увидел результат: 0.pas (1,1 КБ)
(не забудьте отключить отладку и запускать через Shift+F9, чтоб включилась оптимизация)

По-моему, химик уже выпал в осадок.

Вы так всех людей лямбдами распугаете.

1 лайк

Хорошо, берем простейшую задачу.

Дан целочисленный массив, длина которого не превышт 10 000, а значения
элементов по абсолютное величине не превышают 99. Найти и вывести
сумму положительных элементов массива, оканчивающихся цифрой 7.

Вот три варианта решения. Первый - без функций, второй - с внешней функцией и третий с “лямбдой”.

begin
  var a := ArrRandom(ReadInteger, -99, 99);
  a.Println;
  var s := 0;
  foreach var k in a do
    if (k > 0) and (k mod 10 = 7) then s += k;
  Print(s);
end.
function Good(t: integer) := (t > 0) and (t mod 10 = 7);

begin
  var a := ArrRandom(ReadInteger, -99, 99);
  a.Println;
  var s := 0;
  foreach var k in a do
    if Good(k) then s += k;
  Print(s);
end.
begin
  var a := ArrRandom(ReadInteger, -99, 99);
  a.Println;
  a.Where(t -> (t > 0) and (t mod 10 = 7)).Sum.Print
end.

Я весь внимание: расскажите, пожалуйста, какая из трех программ “ближе к естественному языку” и на этом основании “требует меньше времени на обучение” ?

В продолжение темы. Сравните код второй и третьей программы. В третьей цикл вместе с “if” превратился в Where, описание параметра функции в t, а тело функции переписано без изменения. Соединив знаком -> параметр и тело функции, мы получили эту непонятную лямбду-страшилку. Или, если посмотреть и подумать - не такую уж непонятную и совсем не страшилку?

Ну вот почему настолько часто на форуме появляются утверждения, на которые приходится писать очередной “Наш ответ Керзону”? :stuck_out_tongue_winking_eye:

По моему под “естественным языком” - имелось в виду что то типа машины Поста. Или, прекрасного идейного наследника - брейнфака.

@Andrej_Rulin это частое ошибочное представление. Под “легко научиться” надо понимать не “легко знать все возможности” а “легко научиться использовать”.

Понять и запомнить принцип брейнфака можно меньше чем за минуту, без особой подготовки. А чтоб научится писать на нём Hello World - надо хотя бы пару часов.

В то же время под .Net - никто не изучает принцип работы маршлинга объектов типа класса в первый (а часто и в пятый) год. Зато написать консольную игру можно вы первый день.

Машина Поста, говорите? А вот так попрограммировать не желаете? ЭВМ “Промiнь”, если кто не в курсе.

1 лайк

Химия наполнена функциями. В теории цвета - там просто чудовищные по виду функции, которые вызывают оторопь у студентов. Да даже простой и попсовый потенциал водородного электрода рассчитывается по достаточно сложной формуле Нернста.

1 лайк