А еще в рефале есть сконки. Интересно, как зверушке зайдет такая функция?
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 <[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 не содержит никакой логики и
> просто возвращает пустой список. Однако, из-за бесконечной рекурсии, это не
> верно.
>
> Ответ неверный, но теперь рассуждение выглядит разумным (не совсем
> галлюцинация): видно, где этот «студент» провирается. Привлечь
> соображение о бесконечной рекурсии — это нетривиально!
>
> Ладно, на сегодня хватит. Я и так замучил вас длинным протоколом.
> Андрей
>
--
С уважением,
Абрамов С.М. mailto:[email protected]