Неохота выкладывать всю переписку, но в общем в достаточно длинном контексте 
ChatGPT подсказал регулярку `^([A-Za-z]*)+$` как регулярку, которая принимает 
любое выражение из букв, и затем упростил её до ` ^([A-Za-z])+$ ` , когда было 
уточнение про два квантификатора. Затем через некоторую боль удалось его 
навести на то, что они не эквивалентны, но без подсказок про пустую строку увы, 
этого сделать не получилось. 
 
Возникает новый тип задач для студентов: ввести такой запрос для ChatGPT, чтобы 
он дал правильный ответ. Если студент хоть немножко плавает и модель не типа 
Hello World, а всё-таки требующая хоть минимального анализа на один-два шага 
(пусть и без рекурсии), то ему будет не особенно просто добиться чистого 
результата (с учётом контекста; без учёта — не знаю, вообще возможно ли за 
адекватное число попыток). Заодно хорошо прочувствуют, что в искусственном 
интеллекте нечего делать без естественного интеллекта постановщика задач, и как 
«приятно» принимать экзамен по много часов, в попытках выудить из их 
семантической модели более глубокие связи.  
 
 
 
  
>Среда, 5 апреля 2023, 19:32 +03:00 от Sergei Skorobogatov 
>s.yu.skorobogatov_AT_gmail.com <[email protected]>:
> 
>ChatGPT ведёт себя даже не как студент, а как участник некоторого 
>интеллектуального блица, в котором нет времени подумать, т.к. ответ нужно 
>давать как можно быстрее. В принципе, из общих соображений понятно, почему так 
>происходит -- каждое слово ответа порождается за константное время, так что 
>чем сложнее вопрос, тем хуже ответ.
> 
>Тем не менее, грамотно составленный запрос может существенно улучшить качество 
>ответа. В частности, очень помогает, если удаётся заставить модель 
>порассуждать, а не прямо сразу выдавать ответ.
> 
>Я тут провёл такой эксперимент -- дал модели пример подробного объяснения 
>работы рефал-программы, а потом попросил так же точно объяснить работу другой 
>программы. Вот, что получилось (мои запросы -- зелёный цвет, ответы ChatGPT -- 
>синий цвет):
>Here is a function in Refal language:
>```
>f {
>    = ;
>    t.1 e.2 = <f e.2>;
>}
>```
>
>Someone explains, how this function works:
>1. Function `f` has two sentences:
>    * first sentence states, that if we pass empty expression to function `f`, 
>it will return empty expression;
>    * pattern in the left side of the second sentence means, that we must bind 
>variable `t.1` to the first term of an expression, passed to function `f`, and 
>then bind variable `e.2` to the rest terms of the expression.
>2. If we call function `f` with empty expression, this expression will satisfy 
>the pattern in the first sentence, and the function will return empty sentence.
>3. If we call function `f` with non-empty expression (e.g. `<f 10 20 30>`), 
>then this expression will satisfy the pattern in the second sentence, and will 
>be split into two parts -- first term (10) will go to the variable `t.1`, and 
>other terms (20 and 30) will go to the variable `e.2`. Then, as it is 
>described at the right side of the second sentence, function `f` will be 
>called recursively with the value of variable `e.2` as its argument.
>4. We see that at every level of recursion the argument passed to function `f` 
>gets shorter by one term. So at some moment it will become empty, and the 
>first sentence of function `f` will fire, returning the empty sentence as a 
>result.
>5. Therefore, function `f` always returns empty expression.
>
>Please, give the same explanation of how the following function `g` works:
>```
> g {
>   = ;
>   t.x e.X =  <g e.X> t.x;
>}
>```
>1. Function `g` has two sentences:
>    * The first sentence states that if we pass an empty expression to 
>function `g`, it will return an empty expression.
>    * The pattern in the left side of the second sentence means that we must 
>bind variable `t.x` to the first term of an expression passed to function `g`, 
>and then bind variable `e.X` to the rest of the terms in the expression.
>2. If we call function `g` with an empty expression, this expression will 
>satisfy the pattern in the first sentence, and the function will return an 
>empty expression.
>3. If we call function `g` with a non-empty expression (e.g. `<g 10 20 30>`), 
>then this expression will satisfy the pattern in the second sentence, and will 
>be split into two parts -- the first term (10) will go to the variable `t.x`, 
>and the other terms (20 and 30) will go to the variable `e.X`. Then, as it is 
>described on the right side of the second sentence, function `g` will be 
>called recursively with the value of variable `e.X` as its argument, and the 
>result of this recursive call will be followed by the value of variable `t.x`.
>4. We see that at every level of recursion, the argument passed to function 
>`g` gets shorter by one term. So at some moment, it will become empty, and the 
>first sentence of function `g` will fire, returning the empty expression as a 
>result. However, unlike function `f`, function `g` appends the value of `t.x` 
>to the result of the recursive call at each level of recursion.
>5. Therefore, function `g` reverses the input expression. For example, if we 
>call `<g 10 20 30>`, the function will return the expression `30 20 10`.
> 
>Как видим, ChatGPT воспроизвела мои рассуждения, подкорректировав их под 
>другую функцию, и в результате догадалась, что функция переворачивает 
>выражение.
>Теперь у ChatGPT можно спросить, что будет, если применить функцию к 
>результату применения этой же функции:
>Imagine, that we call function `g` twice: `<g <g X>>`, where X denotes some 
>expression.
>Explain, what expression will function `g` return.
>When we call function `g` twice as `<g <g X>>`, the following steps occur:
>
>1. The outer call to function `g` receives the result of the inner call to 
>function `g` as its argument. Let's first consider the inner call `<g X>`.
>2. As we explained earlier, function `g` reverses the input expression. So, 
>the inner call `<g X>` will return the reversed expression of X. Let's denote 
>this reversed expression as Y.
>3. Now, the outer call to function `g` receives Y as its argument. Since Y is 
>the reversed expression of X, calling `g` again with Y as the argument will 
>reverse Y.
>4. As function `g` reverses its input expression, the outer callg Y>` will 
>return the reversed expression of Y, which is the original expression X.
>
>Therefore, when we call function `g` twice asg <g X>>`, it returns the 
>original expression X. This is because the two reversals effectively cancel 
>each other out, resulting in the original input expression.
> 
>В итоге мы получаем (почти, с точностью до опечаток) правильный ответ :-)
>   
>ср, 5 апр. 2023г. в 17:02, A N a_nevod_AT_mail.ru < [email protected] >:
>>Семантическая модель и база по Python действительно хорошая, но в конечном 
>>счёте это всё-таки пока-что студент, который пытается угадать, что от него 
>>хочет преподаватель.
>> 
>>Мои запросы — серым, ответы — на зелёном фоне.
>>Вот функция f, написанная на языке Python: ``` def f(a): return f(a[1:]) if a 
>>else [] ``` Верно ли, что на непустом списке, состоящем из списков, f уходит 
>>в бесконечный цикл?
>> 
>>Да, верно. Функция f рекурсивно вызывает сама себя с аргументом a[1:], 
>>который является срезом исходного списка a, начиная со второго элемента. Если 
>>a состоит из списков, то a[1:] также будет непустым списком из списков, и 
>>функция будет вызывать сама себя бесконечно, так как условие a не будет 
>>равным пустому списку.
>> 
>>Видно, что фейл произошёл на понятии рекурсии.
>>Вот функция f, написанная на языке Python: ``` def f(a): return f(a[1:]) + 
>>[a[0]] if a else [] ``` Верно ли, что для любого a: f(f(f(a))) равно a?
>> 
>> 
>> 
>>Да, верно. Функция f(a) реверсирует список a, то есть меняет порядок его 
>>элементов на обратный. Если применить эту функцию три раза подряд, список 
>>вернется к исходному порядку. Давайте рассмотрим это на примере: ``` a = [1, 
>>2, 3, 4, 5] f(a) = [5, 4, 3, 2, 1] f(f(a)) = f([5, 4, 3, 2, 1]) = [1, 2, 3, 
>>4, 5] f(f(f(a))) = f([1, 2, 3, 4, 5]) = [1, 2, 3, 4, 5] ``` Таким образом, 
>>f(f(f(a))) = a для любого списка a.
>>Здесь это тоже видно, фейл на втором рекурсивном вызове.
>> 
>>Верно ли, что регулярное выражение `^[A-Z]*[a-z]$` сопоставляется с любой 
>>последовательностью латинских букв?
>> 
>> 
>> 
>>Нет, это не верно. Регулярное выражение `^[A-Z]*[a-z]$` сопоставляется с 
>>последовательностью латинских букв, которая начинается с нуля или более 
>>заглавных букв (A-Z) и заканчивается одной строчной буквой (a-z). Это 
>>означает, что оно не будет сопоставляться с последовательностями, состоящими 
>>только из заглавных букв или последовательностями, в которых строчные и 
>>заглавные буквы чередуются.
>> 
>> 
>> 
>> 
>>Базовые вещи, которые есть везде и не требуют рекурсивного анализа, он 
>>понимает правильно. Ок!
>> 
>>Верно ли, что регулярное выражение `^[A-Z]*[a-z]*[A-Z]*[a-z]*$` 
>>сопоставляется с любой последовательностью латинских букв?
>> 
>> 
>> 
>>Верно, данное регулярное выражение сопоставляется с любой последовательностью 
>>латинских букв, состоящей из букв верхнего и нижнего регистра, расположенных 
>>в любом порядке. Оно состоит из следующих частей: - `^` - начало строки - 
>>`[A-Z]*` - ноль или более символов верхнего регистра - `[a-z]*` - ноль или 
>>более символов нижнего регистра - `[A-Z]*` - ноль или более символов верхнего 
>>регистра - `[a-z]*` - ноль или более символов нижнего регистра - `$` - конец 
>>строки Таким образом, данное выражение будет сопоставляться с любой строкой, 
>>состоящей из латинских букв верхнего и нижнего регистра, расположенных в 
>>любом порядке.
>> 
>>А вот тут потребовался анализ на шаг дальше, и наблюдаем картину «студент 
>>сочиняет на ходу».
>> 
>>Это замечательный подсказчик, если знать, что именно требуется, но если 
>>«плавать» в области или есть какие-то тонкости — пока что StackOverflow 
>>никуда не девается. 
>> 
>>Посмотрим, подружатся ли с рекурсией новые когнитивные модели...
>> 
>> 
>> 
>>>Понедельник, 3 апреля 2023, 13:29 +03:00 от Sergei Skorobogatov  
>>>s.yu.skorobogatov_AT_gmail.com < [email protected] >:
>>> 
>>>Повторил ваш эксперимент, заменив рефал на питон. (Мой запрос -- зелёный, 
>>>ответ ChatGPT -- синий).
>>> 
>>>Вот функция  f,  написанная на языке Python:
>>>```
>>>def f(a):
>>>    return f(a[1:]) if a else []
>>>```
>>>Верно ли, что для любого a: f(a) равно пустому списку?
>>> 
>>>Да, верно. Функция f(a) рекурсивно удаляет первый элемент списка a до тех 
>>>пор, пока список не станет пустым, и возвращает пустой список.
>>> 
>>>Заметно, что питон ей знаком гораздо лучше рефала.
>>> 
>>>А теперь с переворачиванием списка:
>>>Вот функция  f,  написанная на языке Python:
>>>```
>>>def f(a):
>>>    return f(a[1:]) + [a[0]] if a else []
>>>```
>>>Верно ли, что для любого a: f(f(a)) равно a?
>>> 
>>>Да, верно. Функция f(a) переворачивает список a, и вызывая её дважды, мы 
>>>получаем исходный список.
>>>
>>>Давайте разберёмся, как работает функция f(a). Если список a пуст, функция 
>>>возвращает пустой список. Если список a не пуст, функция рекурсивно вызывает 
>>>себя для хвоста списка a (a[1:]) и добавляет голову списка a (a[0]) в конец 
>>>результата. Таким образом, функция переворачивает список a.
>>>
>>>Теперь, если мы вызовем функцию f дважды, то есть f(f(a)), то получим 
>>>следующее:
>>>
>>>1. Первый вызов f(a) переворачивает список a.
>>>2. Второй вызов f(f(a)) переворачивает результат первого вызова, то есть 
>>>переворачивает перевёрнутый список a.
>>>
>>>В итоге мы получаем исходный список a, так как двойное переворачивание 
>>>списка равно самому списку.
>>> 
>>>И напоследок вот такая бомба:
>>>Вот функция  f,  написанная на языке Python:
>>>```
>>>def f(a: List[int]) -> bool:
>>>    return len(a) == 0 or a[0:-1] == a[1:]
>>>```
>>>Что надо передать функции f в качестве аргумента, чтобы она вернула True?
>>> 
>>>Функция `f` принимает список целых чисел `a` и возвращает `True` в двух 
>>>случаях:
>>>
>>>1. Если список `a` пустой (длина списка равна 0).
>>>2. Если все элементы списка `a`, кроме последнего, равны всем элементам 
>>>списка `a`, начиная со второго элемента. В других словах, если все элементы 
>>>списка `a` одинаковые.
>>>
>>>Примеры аргументов, при которых функция вернет `True`:
>>>
>>>1. `[]` - пустой список.
>>>2. `[1, 1, 1]` - список, состоящий из одинаковых элементов.
>>>3. `[42, 42, 42, 42]` - еще один список с одинаковыми элементами.
>>> 
>>>Не очень гладко с точки зрения русского языка (выражение "в других словах"), 
>>>но ответ совершенно правильный.  
>>>вс, 2 апр. 2023г. в 23:51, Andrei Klimov klimov_AT_keldysh.ru < 
>>>[email protected] >:
>>>>Сергей, добрый вечер!
>>>> 
>>>>Поскольку вы не в списке рассылки, ваше письмо получил только я — 
>>>>администратор. (У нас такая строгость, так как иначе refal@botik будет 
>>>>сильно заспамлен.) Хорошо, что я заметил ваше письме в длинном треде. 
>>>>Сначала воспроизвожу ваше письме для всех, а ниже отвечаю.
>>>>   
>>>>On Fri, Mar 31, 2023 at 2:44PM < [email protected] > wrote:
>>>>>> On Thu, 30 Mar 2023 at 14:57, Sergei Skorobogatov
>>>>>>  s.yu.skorobogatov_AT_gmail.com [1] < [email protected] > wrote:
>>>>>>
>>>>>> Всем привет!
>>>>>>
>>>>>> Я тут поразвлекался с четвёртой
>>>>>> версией ChatGPT, выдав ей следующее
>>>>>> задание:Please, write a short specification for a new
>>>>>> functional programming language. The language should preserve the
>>>>>> syntax and semantics of Refal language as much as possible, but every
>>>>>> function declaration in it must be typed.
>>>>>>
>>>>>> Результат получился довольно забавный, и мне захотелось им поделиться:
>>>>>>
>>>>>> Title: TypedRefal - A Typed Functional Programming Language Based on
>>>>>> Refal
>>>>>>
>>>>>> [..]
>>>>>
>>>>>
>>>>>Зачем задавать такие сложные философские вопросы?
>>>>>Этому ИИ надо задать для начала простой вопрос. Например такой.
>>>>>
>>>>>Вот функция  rev,  написанная на Рефале, она переворачивает список:
>>>>>   rev = ;
>>>>>   rev t.x eX =  <rev eX> tx;
>>>>>
>>>>>(не помню, как пишется).
>>>>>Верно ли, что для любого eX  (<rev <rev eX>> == eX)
>>>>>?
>>>>>Можно ещё спросить про доказательство.
>>>>>?
>>>>>
>>>>>-----------------
>>>>>Сергей Мешвелиани
>>>>>(я не в списке, мне переслал письмо Андрей Немытых)
>>>> 
>>>> 
>>>>Пожалуйста, вот результат (зеленым мой запрос, потом ее ответ):
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция  rev,  написанная на Рефале, которая переворачивает список:
>>>> rev { = ;
>>>>   t.x e.X =  <rev e.X> t.x;
>>>>}
>>>>
>>>>Верно ли, что для любого eX: <rev <rev eX>> равно eX
>>>>
>>>>Да, верно. Функция rev переворачивает список, а двойной вызов rev дважды 
>>>>переворачивает список, то есть возвращает его в исходном порядке. Таким 
>>>>образом, для любого списка eX, <rev <rev eX>> вернет исходный список eX.
>>>>----------------------------------------------------------------------
>>>> 
>>>>Я этого не ожидал, полагая, что оно не умеет математически доказывать. Но 
>>>>все-таки подозреваю здесь подвох в том, что оно не «поняло» задачу, а 
>>>>где-то «списало» ответ.
>>>>
>>>>Еще подумал, что оно отреагировало на слова «которая переворачивает список» 
>>>>и списало ответ по ним. Повторил запрос, убрав эти слова. Правда, как 
>>>>пишут, оно учитывает контекст разговора и эксперимент нечистый. Но все-так 
>>>>смотрим:
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция  rev,  написанная на Рефале:
>>>> rev { = ;
>>>>   t.x e.X =  <rev e.X> t.x;
>>>>}
>>>>
>>>>Верно ли, что для любого eX: <rev <rev eX>> равно eX
>>>>
>>>>Да, это верно. Функция rev рекурсивно переворачивает список e.X, помещая 
>>>>каждый элемент  в начало нового списка t.x. Переворачивание списка дважды 
>>>>приводит к возвращению исходного списка, так как каждый элемент будет 
>>>>перемещен  в начало списка дважды, в исходном порядке. Таким образом, для 
>>>>любого e.X, <rev <revX>> будет равно eX.
>>>>----------------------------------------------------------------------
>>>>
>>>>В комментарии оно переврало семантику функции (см. подчеркнутое), но 
>>>>объяснило более подробно. Теперь попытаемся сбить с толку:
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция rev, написанная на Рефале: rev { = ; t.x e.X = t.x <rev e.X>; } 
>>>>Верно ли, что для любого eX: <rev eX> равно eX ?
>>>> 
>>>> 
>>>> 
>>>>Нет, это не всегда верно. Например, если eX равно "abc", то <rev eX> будет 
>>>>равно "cba". 
>>>>----------------------------------------------------------------------
>>>>Соврало. Видно, что отреагировало на название функции, отождествив его со 
>>>>«знанием» из какого-то учебника.
>>>>
>>>>Ставим еще эксперимент, заменив имя функции:
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция F, написанная на Рефале: F { = ; t.x e.X = t.x <F e.X>; } Верно 
>>>>ли, что для любого eX: <F eX> равно eX ?
>>>> 
>>>> 
>>>> 
>>>>Нет, это не верно. Функция F применяет рекурсивно функцию <F> ко всем 
>>>>элементам списка e.X, и возвращает список, в котором каждый элемент заменен 
>>>>на результат применения <F>. Если список e.X пустой, то результатом будет 
>>>>пустой список. Если список не пустой, то результатом будет список, в 
>>>>котором каждый элемент заменен на e.X. Например, если e.X = (1 2 3), тоF 
>>>>e.X> вернет (e.X e.X e.X), а не e.X.
>>>>----------------------------------------------------------------------
>>>>
>>>>Хоть ответ не верен, но рассуждение занятное. Оно пытается объяснить ответ 
>>>>и запутывается, хотя и «понимает», что речь о потермовой обработке, что не 
>>>>совсем тривиально.
>>>>
>>>>Ставим еще два эксперимента:
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция F, написанная на Рефале: F { = ; t.x e.X = <F e.X>; } Верно ли, 
>>>>что для любого eX: <F eX> равно eX ?
>>>> 
>>>> 
>>>> 
>>>>Нет, это неверно. Функция F рекурсивно вызывает саму себя с аргументом e.X, 
>>>>что может привести к бесконечной рекурсии. Если F вызывается с аргументом, 
>>>>который не является списком, то она вернет пустой список. Если F вызывается 
>>>>с непустым списком, то она вернет список, состоящий из рекурсивного вызова 
>>>>F с первым элементом списка в качестве аргумента. Таким образом,F eX> может 
>>>>быть равно eX только если eX является пустым списком или списком из одного 
>>>>элемента.
>>>> 
>>>> 
>>>> 
>>>>Вот функция F, написанная на Рефале: F { = ; t.x e.X = <F e.X>; } Верно ли, 
>>>>что для любого eX: <F eX> равно пустому выражению ?
>>>> 
>>>> 
>>>> 
>>>>Нет, это не верно. Функция F бескечно рекурсивна и будет вызываться до тех 
>>>>пор, пока не будет достигнута максимальная глубина рекурсии или не будет 
>>>>достигнутто другая остановочная точка. Если eX содержит какие-то элементы, 
>>>>то <F eX> будет содержать вызов функции F с другими элементами, и так 
>>>>далее, пока не будет достигнута остановочная точка. Поэтому <F eX> не 
>>>>всегда будет равно пустому выражению.
>>>>----------------------------------------------------------------------
>>>>
>>>>Ух ты! На первый запрос ответило правильно. А на второй запуталось. 
>>>>Занятно, что вовлекло понятия «максимальная глубина рекурсии» и 
>>>>«остановочная точк» (где оно услышало слово «остановочная»?).
>>>>
>>>>Я заподозрил, что оно не поняло слово «выражение», так как в проедыдущих 
>>>>ответах употребляло слово «список». Заменим «пустое выражение» на «пустой 
>>>>список»:
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция F, написанная на Рефале: F { = ; t.x e.X = <F e.X>; } Верно ли, 
>>>>что для любого eX: <F eX> равно пустому списку?
>>>> 
>>>> 
>>>> 
>>>>Нет, это неверно. Функция F рекурсивно вызывает себя для каждого элемента 
>>>>списка e.X, поэтому результат будет зависеть от того, что содержится в e.X. 
>>>>Если e.X пустой список, то результатом будет пустой список. Однако, если 
>>>>e.X содержит другие списки, то результат может быть непустым. Например, 
>>>>если e.X = (1 (2 3) 4), то <F e.X> будет равно ((()) (() ()) (() () ()) (() 
>>>>())).
>>>>----------------------------------------------------------------------
>>>> 
>>>>Врет, но врет занятно. ИНтересно, откуда у него такие ассоциации: из каких 
>>>>учебников, от каких примеров, на каких языках?
>>>>
>>>>На жаргоне спецов по ИИ это называется «галлюцинациями». Уже появились 
>>>>заметки с заголовками типа: «Как избегать галлюцинации у GPT?».
>>>> 
>>>>И последний эксперимент на закуску. Подумал: «А хорошо ли оно понимает 
>>>>синтаксис Рефала?» — и убрал точки в переменных. Ожидал тот же самый ответ, 
>>>>но...
>>>> 
>>>>----------------------------------------------------------------------
>>>>Вот функция F, написанная на Рефале: F { = ; tx eX = <F eX>; } Верно ли, 
>>>>что для любого eX: <F eX> равно пустому списку?
>>>> 
>>>> 
>>>> 
>>>>Нет, это неверно. Функция F бесконечно рекурсивна, поэтому ее выполнение не 
>>>>завершится для любого входного значения eX. Если бы функция F завершалась 
>>>>для любого eX, тоF eX> действительно было бы пустым списком, так как 
>>>>функция F не содержит никакой логики и просто возвращает пустой список. 
>>>>Однако, из-за бесконечной рекурсии, это не верно.
>>>>----------------------------------------------------------------------
>>>> 
>>>>Ответ неверный, но теперь рассуждение выглядит разумным (не совсем 
>>>>галлюцинация): видно, где этот «студент» провирается. Привлечь соображение 
>>>>о бесконечной рекурсии — это нетривиально!
>>>> 
>>>>Ладно, на сегодня хватит. Я и так замучил вас длинным протоколом. 
>>>>
>>>>Андрей
>> 
 

Ответить