А еще в рефале есть сконки. Интересно, как зверушке зайдет такая функция?

f {
 = ;
 s.1 e.2 = <f e.2> s.1
 (e.1) e.2 = <f e.2> (<f e.1>);
}

Ну, там стандартные вопросы: чему равно <f <f e.x>> и т.п.

Всего доброго,

Сергей Абрамов


Вы писали 05 апреля 2023 г., 19:31:15:

> 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 <refal@botik.ru>:

>  
> Семантическая модель и база по 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 <refal@botik.ru>:
>  
> Повторил ваш эксперимент, заменив рефал на питон. (Мой запрос -- зелёный, 
> ответ 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 
> <refal@botik.ru>:
> Сергей, добрый вечер!
>  
> Поскольку вы не в списке рассылки, ваше письмо получил только я —
> администратор. (У нас такая строгость, так как иначе refal@botik
> будет сильно заспамлен.) Хорошо, что я заметил ваше письме в длинном
> треде. Сначала воспроизвожу ваше письме для всех, а ниже отвечаю.
>   
> On Fri, Mar 31, 2023 at 2:44PM <mech...@scico.botik.ru> wrote:
>> On Thu, 30 Mar 2023 at 14:57, Sergei Skorobogatov
>> s.yu.skorobogatov_AT_gmail.com [1] <refal@botik.ru> 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 не содержит никакой логики и
> просто возвращает пустой список. Однако, из-за бесконечной рекурсии, это не 
> верно.


>  
> Ответ неверный, но теперь рассуждение выглядит разумным (не совсем
> галлюцинация): видно, где этот «студент» провирается. Привлечь
> соображение о бесконечной рекурсии — это нетривиально!
>  
> Ладно, на сегодня хватит. Я и так замучил вас длинным протоколом. 

> Андрей


>   



-- 
С уважением,
Абрамов С.М.                          mailto:ab...@botik.ru

Ответить