Замечания и предложения

Тогда держите сборку 1198.

[11.03.16] Версия 3.1.0.1198 Реализованы слайсы a[2:4:2]

Так обрадовался, что не стал даже искать эти самые “слайсы” в справочной системе (по предыдущей хронологии событий счел, что это окажется пресловутой черной кошкой в темной комнате) и полез тестировать обновку. Пользуясь случаем, хочу отметить, что последние версии очень радуют обилием новых возможностей и нельзя не поблагодарить за это разработчиков. Итак, слайсы.

Насколько я понял, реализация предусматривает манипулирование с порядковыми номерами элементов независимо от их индексов, если таковые имеются. Т.е. отсчет идет от нуля до <количество элементов>-1. Это хорошо видно на примере статического массива и заодно демонстрирует, что лучше в такой ипостаси с ними не связываться: можно и забыть где-то пересчитать (в приведенном примере) индексы [2…9] к [0…7]. С динамическими все ожидаемо (видимо, под них и шла реализация).

И - маленький сюрпризик для строк. У них слайсы считают, что символы нумерованы от 1, а не от нуля. С одной стороны хорошо: привычно для строк, с другой - нет единообразия. Но в любом случае- отдельное спасибо за слайсы в строках.

Интересно, слайсы пока реализованы только в формах [m:n] и [m:n:k], где m,n,k неотрицательные? Т.е. не планируется сделать как в Python, отсчет от конца строк/последовательностей с отрицательными значениями? И еще: планируются ли конструкции по типу [m:], означающие “с номера m и до конца” и [:-n], означающие “n последних элементов”? Очень бы хотелось, поскольку есть аппетиты заполучить в будущем возможность в матрицах делать срезы в строках и столбцах, а без этих возможностей будут получаться очень громоздкие конструкции.

P.S. Пока вместо s[m:] пишу s[m:100000], странновато выглядит, но это лучше, чем s[m:s.Length], потому что в цепочке вычислений s может образоваться неявно:

Writeln(ArrRandom(50,-5,5).Where(x->x>0)[3:100000].Sum);

Это выход, конечно, но… костыль.

Добавилось в процессе. Почему-то компилятор ругается на Iterate: утверждает, что неизвестное имя. Нельзя ли дать пример использования Iterate для генерации последовательности целых псевдослучайных чисел на [0;2], которая должна быть терминирована первым же встреченным нулём (сам 0 не войдет в последовательность)?

Забыли запретить. Запретим. Статические массивы - зло. Слайсы определены для всех последовательностей, но для строк, дин.массивов и списков возвращают объекты того же типа.

Любые. Шаг только не может быть равен 0.

Планируются. Если сможем обуздать грамматику

Вы пишите s.Slice(m,1) - и всё будет хорошо.

Нет. Отрицательные значения имеют у нас другой смысл.

Обращаю внимание, что слайсы у нас доступны только на чтение. На запись - не уверен, что будем это делать. А срезы в матрицах - дело хорошее. На чтение - можно хоть сейчас сделать. Ну только это - копирование.

Это сюрприз.

По поводу отрицательных:

a[3:1:-1] - это a[3] a[2]
a[-2:2] - это a[0] a[1]

begin
  var t := ('Иванов',15);
  t.Iterate(s->(s[0],s[1]+1)).Take(5).Println;
end.
2 лайка

Слайсы на запись - это конструкция левой части оператора присваивания?. Такая возможность не так уж часто нужна.

Да, я заметил, что отрицательные значения используются в значении шага для получения реверса T. А как все же быть с конструкцией “n последних”? С последовательностями проще - там есть .TakeLast(), но строки он превращает в последовательность символов, а Intellisence просто сходит с ума, считая, что возвращается значение типа integer. В дальнейшем он и список расширений раскрывает для типа integer.

К тому же, получая из строки последовательность, мы должны снова приводить её к строке. Громоздко. Может быть, что-то можно придумать все же? Конечно, без затрагивания .TakeLast(). Может, написать TakeLastString() какой-нибудь…

Да, со строками точно сюрприз. Если имеется некая s:string, то в конструкции s[m:n] символы нумеруются от единицы, а в конструкции s.Slice(m,h,n) они уже нумеруются от нуля.

Т.е. любые отрицательные значения в указании номера первого элемента просто заменяются нулём, как и любые значения в указании номера последнего элемента, превышающего максимальный для последовательности, приводятся к номеру последнего элемента.

Спасибо за пример, кое-что с Iterate прояснилось. Но вот что у меня получается.

И про матрицы.

Чтобы матрицы были матрицами, а не последовательностью, которая лишь внешне похожа на матрицу ("Боевой листок должен быть “Боевым листком”, потому что это же “Боевой листок” (с)), они должны допускать оперирование понятиями “строка” и “столбец”. С этой целью нужны срезы, которые позволят формировать из матрицы строки, столбцы и их наборы, образующие подматрицу. Т.е. срез матрицы должен уметь делать как вектор, так и вектор-столбец, либо вектор-строку. Либо, нужны расширения, позволяющие сформировать из вектора вектор-столбец и вектор-строку. Нужна и обратная операция: формирование матрицы из набора векторов.

Вот пример задачи, в которой может понадобиться многое из перечисленного. Для целочисленного массива размера MxN построить вектор P, содержащий средние арифметические элементов каждой строки и вектор Q, содержащий средние геометрические элементов каждого столбца. Если максимальный элемент вектора P отличается от минимального элемента вектора Q более чем в 2 раза, получить результирующую матрицу путем удаления из исходной матрицы четных строк, в противном случае - путем удаления из исходной матрицы первых и последних строк и колонок.

Конечно, все элементарно решается при помощи циклов. Но интересно решить это в Паскале средствами функционального программирования.

Пользуйтесь для строк s.Right(n)

Подлечим

Понимаю Ваш юмор. У нас во всех методах строк нумерация с нуля потому что они пришли из .NET. А вот индексация у строк - с единицы. И расширенная индексация ей следует.

Не вполне так. Логика такая. Слайс рассматривается на прямой. Если часть последовательности при этом попадает в слайс, то результат не пустой, иначе пустой.

Да, прикольно, спасибо. Для всего метод расширения Iterate работает, а для Seq - нет. Но собственно, а что Вы хотели? Iterate по x возвращает последовательность x f(x) f(f(x)) и т.д. Вы хотели вернуть последовательность последовательностей? Это как-то я слабо представляю, хотя… Т.к. последовательность - это алгоритм, то последовательность последовательностей - это алгоритм получения алгоритмов. Извращение какое-то… И у Вас x+1 - Вы наверное не думали, что x - это последовательность?

Я согласен. Надо делать класс матрицы и всё это туда пилить. Может, займётесь, набросаете?

1 лайк

Реализовать класс не обещаю))) А вот построить какой-то минимально-достаточный набор могу попытаться, только не мгновенно. Но ведь и спешить-то некуда особенно.

На самом деле все совсем непросто. Если реализацию делать на базе array[,] of T с числовыми типами, то при использовании большинства расширений будут возникать проблемы, связанные с отрывом от индексов по строке/столбцу. А если использовать в качестве типа Т записи с тройками (row,column,value), получим тормоза. Можно, конечно, как это делалось в компиляторах Фотрана, хранить обобщенный индекс - простой хэш от номеров строки и столбца, но и двойки (commonindex,value) тоже не сахар, плюс функция преобразования.

Я хотел не очень многого: найти замену циклу с предусловием. Изначально - вот такому:

var x:=Random(10);
while x<>0 do begin
   x:=Random(10);
   if x.IsEven then Print(x)
   end;

Но уже нашел вот такую и успокоился:

// PascalABC.NET 3.1, сборка 1198 от 11.03.2016
begin
  SeqWhile(Random(10),x->Random(10),x->(x<>0) and x.IsEven).Println
end.

Я обдумал проблемы и хотел бы услышать Ваше мнение о направлении реализации векторов и матриц.

Пока просматривается два основных пути. Первый - строить векторы и матрицы из элементов уже имеющихся типов. Например, целочисленных элементов, вещественных и т.д. Это позволит создать классы для векторных и матричных вычислений примерно так, как они определены в линейной алгебре. Второй путь - создать класс для базового элемента, представляющий запись из трех полей (строка, столбец, значение). Тогда не будет отдельного класса векторов, а вектор будет рассматриваться как вектор-строка или вектор-столбец, который при вырезке из матрицы будет в себе нести унаследованные индексы. Это позволит при необходимости ответить на вопрос, где в матрице изначально находился тот или иной элемент полученного вектора и больше ориентировано на поиск в матрицах и векторах различных значений и т.п.

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

Доброй ночи! Возникла такая проблема: FloodFill оставляет маленькие некрасивые дыры. Мне предложили использовать Polygon, но он требует тяжёлого синтаксиса массива точек. @bravit высказал идею, что можно было бы добавить версию Polygon с массивом кортежей, тогда синтаксис облегчился бы. Собственно, примеры и код. Было бы хорошо добавить полигон от массива кортежей.

Как вариант: params. Чтобы вообще не создавать отдельный массив.

uses GraphABC;

begin
  // Вариант 1: плохое качество
  Line(20,20, 300, 10);
  Line(20,20, 10, 150);
  Line(10,150, 300, 10);
  FloodFill(25,25, clRed);
  
  SetCoordinateOrigin(150,150);
  
  // Вариант 2: хорошее качество, но громоздко
  Brush.Color := clRed;
  var ap : array of Point := (new Point(20,20), new Point(10, 150), new Point(300, 10));
  Polygon(ap);

  // Вариант 3: идеально, но требуется Polygon(array of Tuple), может, с params
  var ap1 := Arr((20,20), (10, 150), (300, 10));
  //Polygon(ap1);
  // Или сразу:
  //Polygon((20,20), (10, 150), (300, 10));
end.

Да, принимаю все предложения.

В последней версии можно так:

uses GraphABC;

begin
  SetSmoothingOff;

  var p1 := (20,20);
  var p2 := (300,10);
  var p3 := (10,150);
  
  Line(p1, p2);
  Line(p2, p3);
  Line(p3, p1);
  FloodFill(25,25, clRed);
  
  SetSmoothingOn;
  SetCoordinateOrigin(150,150);
  
  Brush.Color := clRed;
//  Polygon((20,20), (10, 150), (300, 10));
  Polygon(p1, p2, p3);
end.
1 лайк

Кстати, вот это стало работать

function Odds(a: array of integer) := a.Where(x -> x mod 2 <> 0);

begin
  Println(Odds(Arr(1,3,2,5,4,7,6,8)));
end.
2 лайка

Это тоже работает.

 begin
   writeln('введите a:');
   var a := System.Console.ReadLine;
   writeln('a = ', a)
 end.

если писать так, то окно ввода не открыается

Правильно - и не откроется. Процедура Readln дает команду открытия этого окна оболочке, а System.Console.ReadLine написана в Microsoft.

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

1 лайк

Делюсь следующим наблюдением.

Строки PascalABC.NET являются частным случаем последовательности и к ним применимы методы последовательностей, что очень удобно. Однако есть проблема: если использовать метод, который возвращает снова последовательность, то при печати результата будет [a, b, c], в то время как хотелось бы abc. Нельзя ли как-то добиться того, чтобы или последовательность char печаталась как строка или чтобы методы возвращали string?

Я на занятии говорил студентам, что для превращения результата в настоящую строку можно сделать свёртку результата (Aggregate). Сейчас вижу, что можно вызывать String.Concat для результата. Но было бы хорошо это не делать. В Хаскеле вот нашли способ подменить метод show для списка Char, причём без расширений языка.

// PascalABC.NET 3.1, сборка 1239 от 08.05.2016
// Также проверено в WDE: http://pascalabc.net/WDE
begin
  var s:='My test string';
  Writeln(s);
  var a:=s.Select(c->UpCase(c)); Writeln(a);
  a.Println;
  a.Println('');
  var b:=a.ToString; Writeln(b);
  var c:=a.JoinIntoString(''); Writeln(c);
  // Как итог: .JoinIntoString('') для получения строки
  var s1:=s.Select(c->UpCase(c)).JoinIntoString('');
  Writeln('-'*10,NewLine,s1);
end.

Результаты:

My test string
[M,Y, ,T,E,S,T, ,S,T,R,I,N,G]
M Y   T E S T   S T R I N G
MY TEST STRING
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Char,System.Char]
MY TEST STRING
----------
MY TEST STRING

Небольшое хулиганство:

begin
  var s:='My test string';
  Writeln(s);
  var s1:=s.Select(c->UpCase(c)).Println('').JoinIntoString('')
    .Replace('T','?').Println('').Select(c->c*2).Println('')
    .JoinIntoString('');
  Writeln(s1);
end.

Очень много всего, тяжело разбираться без пояснений, но спасибо.

А, увидел итог, спасибо.

При попытке скачать последний билд Паскаля Windows Defender удаляет его и очень ругается=(. StandartPack, MiniPack и PABCNETC.ZIP. Полный пакет для первой установки позволяет скачать нормально. Раньше при клике по экзешнику он уже предупреждал, что ему этот файл не нравится, но установить можно было, а сейчас такие дела=(

@Admin, Вы злоумышленник? =) Или проблема всё же на моей стороне?

1 лайк

<img src="/uploads/default/original/1X/c65af70fe4932b0259868a347303908362b6df88.jpg" width=“474” height=“199”

Результат проверки Kaspersky Endpoint Security 10 для Windows 10.2.1.23 Так что выбросьте свой “Дефендер” подальше…

С вирусами трудно сказать наверняка. Вот проверка virustotal: https://virustotal.com/ru/url/65bc6041964df16c5f393e5ff37fb1f8c0817c0db50e8324271a475d4565766f/analysis/ Говорит, что нет.