Основы программирования экзамен янв 2018


#1

Опубликованы конспекты лекций по курсу Основы программирования (сен-дек 2017)

https://drive.google.com/file/d/1bmzWPX5PFwoUwJXYAlDVK-Ri7AnhFeBj/view?usp=sharing

Огромное спасибо Ломакиной Евгении!


#2

Опубликована программа курса Основы программирования для подготовки к экзамену

https://drive.google.com/file/d/1AoXj7LLErlURN01cKT7U4ZBpkGoqf13H/view?usp=sharing


#3

Станислав Станиславович, подскажите, пожалуйста, почему тип предиката, объявленный в библиотеке, не виден в основной программе? На лекции мы разбирали такой пример, относящийся к 54 вопросу экзаменационной программы:

library MyLib;

procedure p := Print(1);

function add(a, b: real) := a + b;

type
  IntPredicate = integer->boolean;
end.
  • Основная программа
{$reference MyLib.dll}

begin
  p;
  println;
  print(Add(7, 333));
  var f: IntPredicate;
  f := x -> x < 5;
  if f(2) then 
    print('<5');
end.

При компилировании основной программы возникает ошибка: Неизвестное имя 'IntPredicate', при этом подпрограммы библиотеки (p и add) работают нормально.


#4

Хороший вопрос. Синонимы типов не сохраняются в dll, потому что в .NET для них нет никаких сущностей. Поэтому это можно считать особенностью PascalABC.NET


#5

Станислав Станиславович,как правильно реализовать печать последовательности? Нужен ли для этого оператор yield? Дело в том, что тот вариант, который мы писали на лекции ничего не печатает. А если попытаться взять напечатанные элементы и еще раз их напечатать, то получится что-то странное.

///Метод взятия первых n элементов последовательности 
function Take<T>(seq: sequence of T; n: integer): sequence of T;
begin
  var c := 0;
  foreach var x in seq do
  begin
    yield x;
    c += 1;
    if c = n then 
      exit
  end
end;

///Метод печати элементов последовательности 
function MyPrint<T>(seq: sequence of T): sequence of T;
begin
  foreach var x in seq do 
  begin
    print(x);
    yield x
  end
end;


begin
  var q := Seq(5, 6, -5, 1, 2, 3, 4, 7, 8, 9, -11);
  
  MyPrint(Take(q, 6));
  println;
  
  Take(MyPrint(q), 6).Print;
  
end.

#6

Да, не очень удачную функцию написал я на лекции для печати. Дело в том, что она возвращает последовательность, а последовательность ленива. Чтобы она “выполнилась”, необходимо превратить её в скаляр любым способом - например:

MyPrint(Take(q, 6)).Count;

Немного глуповато выглядит.

Правильнее написать просто процедуру, печатающую последовательность безо всякого yield:

procedure MyPrint<T>(seq: sequence of T);
begin
  foreach var x in seq do 
    print(x);
end;

#7

Понятно. Спасибо большое!


#8

Станислав Станиславович, проконсультируйте, пожалуйста, насчет использования метода GroupBy. В примере мы группировали массив студентов. Однако возникает сложность при проходе по каждому элементу группы. То есть не работает цикл foreach var s in g do, где g — элемент условно двумерной последовательности gg. Возникает ошибка «name не объявлен в типе integer».

type
  student = auto class
  public 
    Name: string;
    Age: integer;
    Group: integer;
  end;

begin
  var a := arr(new Student('Иванов', 20, 1), new Student('Петров', 19, 2),
  new Student('Сидоров', 17, 1), new Student('Зайцев', 16, 3), new Student('Шевченко', 21, 2));
  
  var gg := a.GroupBy(s -> s.Group).OrderBy(g -> g.Key);
  gg.Println;
  
  foreach var g in gg do
  begin
    print(g.key);
    {g.println;}
    foreach var s in g do
      print(s.name, s.Age);
  end;
  
end.

Можно, конечно, убрать внутренний foreach и печатать через g.println;. Но так неудобно, ведь будет выводиться группа студента несколько раз:

1 (Иванов,20,1) (Сидоров,17,1)


#9

Я скопировал код к себе - он работает. Выводит:

[(Иванов,20,1),(Сидоров,17,1)] [(Петров,19,2),(Шевченко,21,2)] [(Зайцев,16,3)]
1 Иванов 20 Сидоров 17 2 Петров 19 Шевченко 21 3 Зайцев 16 

Может, у Вас старая версия Паскаля? Посмотрите, какая версия и от какого числа


#10

Да, действительно, дело было в версии Паскаля. На сборке 1534 от 09.09.17 не работает, а вот на 1611 от 06.01.18 все в порядке


#12

Мне кажется, что в выложенных лекциях ошибка в бинарном поиске, там не r:=k, а r:=k-1 иначе цикл не прервется


#13

Да, точно. Правильный код такой:

function BinarySearch(a: array of integer; x: integer): integer;
begin
  var k: integer;
  var (l,r) := (0, a.Length-1); 
  repeat
    k := (l+r) div 2;
    if x>a[k] then
      l := k+1
    else r := k-1;
  until (a[k]=x) or (l>r);
  Result := a[k]=x ? k : -1;
end;


#14

Станислав Станиславович, у меня какая-то проблема с композицией функция, если я ее делаю обобщенной функцией(как на лекции) возникает исключение, но с определенным типом все хорошо, можете проконсультировать?


#15

Это связано с тем, что Sin и Cos перегружены для типа Complex. И компилятор не может выбрать. Так всё работает:

function Si(x: real) := Sin(x);
function Co(x: real) := Cos(x);

function Comp<T>(f,g: T->T): T->T := x->f(g(x));

begin
  Comp(Si,Co);
end.

#16

Нам на практике еще давали такой способ решения: явно указать тип, подставляемый вместо T, насколько я понимаю.

function Composition<T>(f1, f2: T->T): T->T := x -> f1(f2(x));

begin
  var f := Composition&<Real>(sin, cos);
  print(f(pi));
end.

Так тоже работает :slightly_smiling_face:


#17

Какую официальную шпаргалку можно взять на экзамен? Случайно, не этот файл? Шпаргалка PascalABC.NET 2017.pdf (232,6 КБ)


#18

Да, она самая


#19

Конечно работает! В моём примере компилятор тип T сам старается - выводит, а тут Вы ему явно помогаете :slight_smile:


#20

Извините пожалуйста, забыл спросить на консультации, а как работает сортировка массива записи по критерию сравнения(это вопрос 86), как я понял, мы придумываем критерий, определяем для него в отдельной процедуре правило, по которому будем сравнивать и затем просто сортируем массив, используя вместо операции сравнения нашу процедуру. Так ли это?


#21

Ну да, именно так. И можно тогда сделать процедуру обобщённой