Как аргумент вложенной переменной интерпретируется в схеме?

Следующий минимальный пример основан на этом блоке кода:

(define (nested_var_arg . (arg_1 . args))
  (if (list? args)
    (begin
      (displayln "args")
      (displayln args))
    (if (arg_1)
      (displayln arg_1)
      (displayln "nothing"))))

Кажется, мы можем использовать 0 arg, как это делает (define (var_arg . lst) ... ). Но (nested_var_arg) выдаст ошибку «;Процедура #[communde-procedure 12nested_var_arg] была вызвана с 0 аргументами; для нее требуется как минимум 1 аргумент.».

R7RS 4.1.4 Процедуры дают пример без вложенного_var_arged (x y . z) и «n или более аргументов», по-видимому, подразумевают, что и var_arg, и nested_var_arg принимают 0 аргументов.

Тогда как интерпретировать вышесказанное (nested_var_arg . (arg_1 . args))?

Подсказка: (nested_var_arg . (arg_1 . args)) пишется более традиционно (nested_var_arg arg_1 . args)

Shawn 27.07.2024 18:55

В языках Lispy по соглашению используется kebab-case, а не Snake_case. nested-var-arg, arg-1 и т. д.

Shawn 27.07.2024 18:57

@Шон 1. Есть ли хоть одна ссылка на «более традиционно написанное (nested_var_arg arg_1 . args)»? 2. «В языках Lispy по соглашению используется kebab-case, а не Snake_case». Вероятно, это правда, поскольку SICP и SDF обычно его используют. Я использую «snake_case», так как в VSCode удобно выделять слово двойным кликом при использовании Snake_case вместо kebab-case.

An5Drama 28.07.2024 01:49

Это фундаментальный аспект того, как средство записи отображает пары и как читатель интерпретирует литералы списка. См., например, раздел 6.4 R7RS.

Shawn 28.07.2024 02:38

@Шон Спасибо. Вы имеете в виду, что (arg_1 . args) можно рассматривать как пару? Это нормально, поскольку args может быть одним списком в (arg_1 . args). В standards.scheme.org/corrected-r7rs/… «(a b c . d) эквивалентно (a . (b . (c . d)))» подразумевает, что (c . d) можно рассматривать как (. (c . d)), хотя кажется невозможным составить вот такую, казалось бы, странную пару (. (c . d)). Демонстрация: '(. (1 . 2)) выдаст ошибку «;Плохо сформированный пунктирный список: (.» и (cons '. (cons 1 2)) выдаст ошибку «;Точка разрешена только в списке».

An5Drama 28.07.2024 02:50
(. (c . d)) — это синтаксическая ошибка, поскольку в (. whatever) нет значения автомобиля, чтобы сделать его парой.
Shawn 28.07.2024 06:57

@ Шон Файн. Возможно, в Scheme есть какие-то специальные манипуляции с . (arg_1 . args) в (nested-var-arg . (arg_1 . args)), чтобы сделать его таким же, как (arg_1 . args), хотя я не знаю подробностей этого.

An5Drama 28.07.2024 07:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Возможно, это технически недопустимый синтаксис Scheme, поскольку синтаксис программ, я считаю, не определен в терминах «синтаксиса данных», который, например, понимается, а в терминах чего-то вроде BNF.

Таким образом, синтаксис процедуры в R7RS — это read, а (lambda <formals> <body>) — это <formals>, <variable> или (<variable> ...).

Но синтаксис данных для Scheme включает обычную нотацию Lisp для пар (conses) и эквивалентное сокращение для списков: пара — это (<variable> ... . <variable>), и вы всегда можете написать (x . y) как (x . ()) и (x) как (x . (y ...)).

Таким образом, любая схема, которая использует обычный читатель для чтения программ, а также данных (а это, вероятно, все они), будет читать форму типа (x y . (...)) как полностью эквивалентную (define (nested_var_arg . (arg_1 . args)) ...).

Юрист по языку Scheme может ответить, законно ли это с технической точки зрения. Я попробовал три реализации, и все они в порядке.

Спасибо за ваше объяснение, основанное на программах чтения для чтения. Это подразумевается в первом комментарии Шона, но я не заметил этого, пока не прочитал ваш ответ. Итак, здесь нам следует рассматривать (nested_var_arg . (arg_1 . args)) как одну целую сущность, а не думать отдельно о . (arg_1 . args) как о списке аргументов nested_var_arg.

An5Drama 28.07.2024 12:13
Ответ принят как подходящий

Тогда как интерпретировать вышесказанное (nested_var_arg . (arg_1 . args))?

У пары есть машина и cdr. Список (x y) представляет собой пару со списком (y) в cdr (что вы можете проверить, вычислив (cdr '(x y)). Это то же самое, что (x . (y)), что то же самое, что и (x . (y . ())). Обычно вы пишете (x y) вместо любой другой формы, представляющей это список, а (x y) — это то, как принтер Scheme будет представлять любую из этих форм, но в каждом случае эти формы представляют один и тот же объект: список, содержащий x и y. Любая из этих форм является внешним представлением списка, содержащего x и y. и программа чтения схем преобразует внешние представления в объекты схемы. Это обсуждается в R7RS 3.3 Внешние представления , R7RS 7.1.2 Внешние представления и R7RS 6.13.2 Ввод.

Форма (nested_var_arg . (arg_1 . args)) — неправильный список или пунктирный список. Автомобиль nested_var_arg и CDR (arg_1 . args). Это можно эквивалентно выразить как (nested_var_arg arg_1 . args); это внешние представления одного и того же несобственного списка. Внешние представления правильных и неправильных списков обсуждаются в R7RS 6.4 Пары и списки.

Определение может принимать одну из трех форм:

  1. (define <variable> <expression>)
  2. (define (<variable> <formals>) <body>), или
  3. (define (<variable> . <formal>) <body>).

В третьем из них <formal> обозначает одну переменную, поэтому (define (nested_var_arg arg_1 . args) ;...) соответствует второму из них. Это описано в R7RS 5.3 Определения переменных. Здесь <formals> соответствует формальному лямбда-выражению (lambda (arg_1 . args) ;...).

Формалы лямбда-выражения могут принимать одну из трех форм:

  1. (<variable1> ...)
  2. <variable>, или
  3. (<variable1> ... <variablen> . <variablen+1>).

Поскольку (arg_1 . args) соответствует третьему из них, давайте сосредоточимся на этом. Тройная точка указывает, что для этой формы требуется хотя бы одна переменная (<variablen>), за которой следует еще одна переменная (<variablen+1>). Это обозначение описано в R7RS 1.3.3 Формат ввода. Полученная функция связывает аргументы, предшествующие точке, по отдельности и оборачивает все оставшиеся аргументы в список, привязанный к <variablen+1>. Это означает, что функция, определенная с использованием формы (define (nested_var_arg . (arg_1 . args)) ;...), требует хотя бы одного аргумента, поскольку эта форма представляет собой неправильный список (define (nested_var_arg arg_1 . args) ;...). Вызов результирующей функции без аргументов вызывает ошибку, поскольку она была определена как требующая хотя бы одного аргумента, т. е. эта функция предполагает привязать аргумент к arg_1 и обернет все оставшиеся (необязательные) аргументы в список, привязанный к args.

Кажется, мы можем использовать 0 arg, как это делает (define (var_arg . lst) ... ).

Это другая форма определения, которая соответствует третьей форме выше: (define (<variable> . <formal>) <body>). Здесь <formal> соответствует формальному лямбда-выражению (lambda <formal> <body>) (форма 2 выше, где <formal> соответствует <variable>). В результате этой формы получается функция, которая принимает любое количество аргументов и оборачивает их в список, привязанный к <variable>. Вызов такой функции без аргументов допустим, и в результате к <variable> будет привязан пустой список.

Является ли (define (nested_var_arg . (arg_1 . args)) ;...) строго законной схемой?

Схема требует, чтобы процедура read анализировала форму (define (nested_var_arg . (arg_1 . args)) ;...), эквивалентную (define (nested_var_arg arg_1 . args) ;...), но только эта вторая форма является строго допустимым синтаксисом для define. Схема позволяет реализации использовать read для анализа программ, но не требует этого. Насколько я понимаю ситуацию, реализациям разрешено принимать форму OP define и, скорее всего, так и будет, но реализация имеет право отклонить ее.

Я проголосовал за ваш ответ. Ваш ответ лучше, чем ответ ignis volens, если предположить меньший уровень знаний (я прочитал только главу 2 SICP и главу 2 SDF, чтобы изучить программирование). Поэтому я изменился, чтобы принять ваше. 1. 3 ссылки-ссылки в 1-м пункте очень помогают, особенно "скорее это внешнее представление трехэлементного списка, элементами которого являются символ + и целые числа 2 и 6". в 3.3. Это подразумевается в третьем комментарии Шона, но я не обратил на них внимания и сосредоточился только на «разделе 6.4 R7RS».

An5Drama 29.07.2024 04:25

2. Спасибо за очень подробное объяснение, особенно за указание на «неправильный список». 3. Спасибо, что указали на мою ошибку, подразумеваемую в моем ручном соотношении (var_arg . lst) и (nested_var_arg . (arg_1 . args)) и в вашем ответе «(<variable> . <formal>)». 4. <variable1> ... кажется особым случаем, поскольку в 1.3.3 говорится «указывает на ноль или более вхождений <вещи>», а в 4.1.4 standards.scheme.org/corrected-r7rs/… говорится «(это ошибка, если нет хотя бы одной)». Это также подразумевается в четвертом комментарии Шона.

An5Drama 29.07.2024 04:25

Возможно, одна опечатка: (<variable1> . ... <variablen> <variablen+1>) -> (<variable1> ... <variablen> . <variablen+1>).

An5Drama 29.07.2024 04:27

Возможно, одна опечатка..." -- спасибо: исправлено. «кажется, это особый случай...» — мое объяснение здесь было туманным и немного небрежным; Я сделал некоторые уточнения. <variable1> ... действительно указывает на ноль или более переменных, но <variable1> ... <variablen> указывает на ноль или более переменных, за которыми следует одна обязательная переменная (<variablen>).

ad absurdum 29.07.2024 07:42

Другие вопросы по теме