Как привязки повысить четкость кода в функциональном программировании

Как привязки повысить четкость кода в функциональном программировании

7 июля 2025 г.
  1. Введение

  2. Перевод на последовательное исчисление

    2.1 Арифметические выражения

    2.2 Пусть привязки

    2.3 Определения верхнего уровня

    2.4 Алгебраические данные и типы кодов

    2.5 первоклассные функции

    2.6 Операторы управления

  3. Оценка в контексте

    3.1 Контексты оценки для развлечения

    3.2 Сосредоточение внимания на оценке в сердечнике

  4. Правила печати

    4.1 Правила печати для развлечения

    4.2 Правила печати для Core

    4.3 Тип. Звукость

  5. Понимание

    5.1 Контексты оценки являются первым классом

    5.2 Данные двойные до кодата

    5.3 LET-связы

    5.4 Трансформация случая

    5.5 Прямой и косвенный потребители

    5.6 Позвоните в запас, вызовов и eta-laws

    5.7 Линейная логика и двойственность исключений

  6. Связанная работа

  7. Заключение, заявление о доступности данных и подтверждение

A. Взаимосвязь с последовательным исчислением

B. Правила набора развлечений

C. Оперативная семантика лейбла/goto

Ссылки

2.2 Пусть привязки

Заветные связки важны, поскольку мы можем использовать их для устранения дублирования и сделать код более читабельным. В этом разделе мы вводим let-bindings для развлечения по дополнительной причине: они позволяют нам представить вторую конструкцию, которая дает 𝜆𝜇𝜇 𝜆𝜇𝜇-calculus его название: 𝜇 𝜇-abstractions.

Веселые развязки являются стандартными и оцениваются путем замены значения 𝔱 на переменную 𝑥 в теле, который является термином. Аналог let-связывания в веселье-это 𝜇 𝜇-связывающее в ядре, которое также связывает переменную, с разницей в том, что тело 𝜇-связывания является утверждением. Легко можно увидеть, что 𝜇 𝜇-связки-это точный двойник 𝜇-связей, которые мы уже представили.

С помощью 𝜇- и 𝜇 𝜇-связки мы должны столкнуться с потенциальной проблемой, а именно утверждения формы ⟨𝜇𝛼.𝑠1 | 𝜇𝑥.𝑠 ˜ 2⟩. Такое утверждение называется критической парой, так как оно потенциально может быть уменьшено как к 𝑠1 [𝜇𝑥.𝑠 ˜ 2/𝛼], так и 𝑠2 [𝜇𝛼.𝑠1/𝑥], которые могут быть источником неконфликта. Более тщательное осмотр правил показывает, что мы избегаем этой ловушки и всегда оцениваем утверждение до 𝑠1 [𝜇𝑥.𝑠 ˜ 2/𝛼]. Мы не допускаем уменьшения оператора до 𝑠2 [𝜇𝛼.𝑠1/𝑥], поскольку только значения 𝔭 могут быть заменены на переменные, а 𝜇𝛼.𝑠1 не является значением. Это ограничение точно отражает ограничение на оценку развязки LET в веселье. Другими словами, мы используем порядок оценки вызовов. Мы рассмотрим критическую пару и то, как она снова относится к различным порядкам оценки в разделе 5.6.

Мы можем заметить, что арифметическое выражение 2 ∗ 2 оценивалось только один раз, что именно то, что мы ожидаем от вызова.

2.3 Определения верхнего уровня

Мы вводим рекурсивные определения верхнего уровня для веселья и основного по двум причинам. Они позволяют нам писать более интересные примеры, и они иллюстрируют разницу в том, как обрабатываются рекурсивные вызовы. Расширение указано в определении 2.4.

Определения верхнего уровня не следует путать с первоклассными функциями, которые будут представлены позже, поскольку они не могут быть переданы в качестве аргумента или возвращены в результате. Они являются частью программы, которая состоит из списка таких определений высшего уровня. Определения верхнего уровня в веселом с любопытством также принимают ковариации как аргументы, даже если язык не содержит потребителей; Вы можете игнорировать это на данный момент. Если вы помните пример из введения, то вы можете вспомнить, что мы используем их для прохождения метки, но мы формально представим эту конструкцию в разделе 2.6.

Мы оцениваем призыв определения верхнего уровня, просматривая тело в программе и заменяя аргументы вызова для параметров в теле определения. Тело определения верхнего уровня-это термин в веселье и заявление в ядре. Эта разница объясняет, почему мы должны добавить дополнительный параметр 𝛼 в каждое определение верхнего уровня, когда мы переводим его; Этот параметр 𝛼 также соответствует дополнительному аргументу продолжения, когда мы обычно переводим функцию в стиль продолжения. Мы также могли бы указать, что корпус определения верхнего уровня в ядре должен быть производителем. Мы не делаем этого, потому что, когда мы в конечном итоге переводим ядро ​​в машинный код, мы хотим, чтобы каждое определение верхнего уровня стало целью прыжка с аргументами без создания стека вызовов функции. В следующем примере показано, как это работает:

Пример 2.3Полем Используя определение верхнего уровня, мы можем представлять факторную функцию в Core.

Для аргумента ⌜1⌝ это оценивается следующим образом:

В точке (∗) оценки мы теперь можем увидеть, как оценивается рекурсивный вызов. В веселье этот рекурсивный вызов будет иметь FAC FAC 1 ∗ (0) и потребовать функционального стека, но в ядре мы можем подняться на определение FAC с потребителем 𝜇𝑟. ˜ ∗ (⌜1⌝, 𝑟; ⋆) как дополнительный аргумент, который содержит информацию, что результат рекурсивного вызова должен быть связан с переменной 𝑟, а затем умножена на ⌜1⌝. Обратите внимание, что этот аргумент потребителя соответствует продолжению в стиле продолжения (в этом смысле, он может рассматриваться как урегулированный стек), и поэтому для ее реализации могут применяться основные методы, используемые в промежуточных представлениях и компиляторах на основе CPS.

Авторы:

(1) Дэвид Биндер, Университет Тюбингена, Германия;

(2) Марко Цшенке, Университет Тюбингена, Германия;

(3) Мариус Мюллер, Университет Тюбингена, Германия;

(4) Клаус Остерманн, Университет Тюбингена, Германия.


Эта статья естьДоступно на Arxivпод CC по 4,0 лицензии.


Ведущее изображение этого ведущего на Pexels.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE