~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ 9E9D2622E16F07583163C77B232CD09E__1698928320 ✰
Заголовок документа оригинал.:
✰ Continuation-passing style - Wikipedia ✰
Заголовок документа перевод.:
✰ Стиль продолжения прохождения — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Continuation_passing_style ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/9e/9e/9e9d2622e16f07583163c77b232cd09e.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/9e/9e/9e9d2622e16f07583163c77b232cd09e__translat.html ✰
Дата и время сохранения документа:
✰ 16.06.2024 09:29:37 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 2 November 2023, at 15:32 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Стиль продолжения прохождения — Jump to content

Стиль продолжения прохождения

Из Википедии, бесплатной энциклопедии

В функциональном программировании стиль передачи продолжения ( CPS ) — это стиль программирования, в котором управление передается явно в форме продолжения . Это контрастирует с прямым стилем, который является обычным стилем программирования. Джеральд Джей Сассман и Гай Л. Стил-младший придумали эту фразу в AI Memo 349 (1975), в которой изложена первая версия языка программирования Scheme . [1] [2] Джон К. Рейнольдс подробно описывает многочисленные открытия продолжений. [3]

Функция, написанная в стиле передачи продолжения, принимает дополнительный аргумент: явное «продолжение»; т.е. функция одного аргумента. Когда функция CPS вычислила свое значение результата, она «возвращает» его, вызывая функцию продолжения с этим значением в качестве аргумента. Это означает, что при вызове функции CPS вызывающая функция должна предоставить вызываемой процедуре «возвращаемое» значение подпрограммы. Выражение кода в такой форме делает явными многие вещи, которые неявно подразумеваются в прямом стиле. К ним относятся: возвраты процедур, которые проявляются как вызовы продолжения; промежуточные значения, которым присвоены имена; порядок вычисления аргументов, который сделан явным; и хвостовые вызовы , которые просто вызывают процедуру с тем же неизмененным продолжением, которое было передано вызывающей стороне.

Программы могут быть автоматически преобразованы из прямого стиля в CPS. Функциональные и логические компиляторы часто используют CPS в качестве промежуточного представления , тогда как компилятор для императивного или процедурного языка программирования будет использовать статическую форму одиночного присваивания (SSA). [4] SSA формально эквивалентен подмножеству CPS (исключая нелокальный поток управления, который не возникает, когда CPS используется в качестве промежуточного представления). [5] Функциональные компиляторы также могут использовать A-нормальную форму (ANF) (но только для языков, требующих быстрой оценки), а не с помощью « thunk » (описанных в примерах ниже) в CPS. CPS чаще используется компиляторами , чем программистами, как локальный или глобальный стиль.

Примеры [ править ]

В CPS каждая процедура принимает дополнительный аргумент, представляющий, что следует делать с результатом, который вычисляет функция. Это, наряду с ограничительным стилем, запрещающим различные обычно доступные конструкции, используется для раскрытия семантики программ, что упрощает их анализ. Этот стиль также позволяет легко выражать необычные структуры управления, такие как захват/бросок или другие нелокальные передачи управления.

Ключом к CPS является запоминание того, что (а) каждая функция принимает дополнительный аргумент, известный как ее продолжение, и (б) каждый аргумент в вызове функции должен быть либо переменной, либо лямбда-выражением (а не более сложным выражением). Это приводит к переворачиванию выражений «наизнанку», поскольку сначала должны быть вычислены самые внутренние части выражения, таким образом, CPS четко определяет порядок вычисления, а также поток управления. Некоторые примеры кода в прямом стиле и соответствующие CPS приведены ниже. Эти примеры написаны на языке программирования Scheme ; по соглашению функция продолжения представлена ​​как параметр с именем " k":

Прямой стиль
Продолжение стиля прохождения
(  define   (  pyth   x   y  ) 
  (  sqrt   (  +   (  *   x   x  )   (  *   y   y  )))) 
(  define   (  pyth&   x   y   k  ) 
  (  *&   x   x   (  лямбда   (  x2  ) 
           (  *&   y   y   (  лямбда   (  y2  ) 
                    (  +&   x2   y2   (  лямбда   (  x2py2  ) 
                               (  sqrt&   x2py2   k  ))))))) 
(  define   (  факториал   n  ) 
  (  if   (  =   n   0  ) 
      1       ; НЕ хвостовая рекурсия 
      (  *   n   (  факториал   (  -   n   1  ))))) 
(  define   (  factorial&   n   k  ) 
  (  =&   n   0   (  лямбда   (  b  ) 
           (  if   b                      ; продолжение роста 
               (  k   1  )                  ; в рекурсивном вызове 
               (  -&   n   1   (  лямбда   (  nm1  ) 
                        (  факториал&   nm1   (  лямбда   (  f  )) 
                                         (  *&   н   ж   к  ))))))))) 
(  определить   (  факториал   n  ) 
  (  f-aux   n   1  )) 
 (  определить   (  f-aux   n   a  ) 
  (  if   (  =   n   0  ) 
      a          ; хвостовая рекурсия 
      (  f-aux   (  -   n   1  )   (  *   n   a  )) )) 
(  define   (  факториал&   n   k  )   (  f-aux&   n   1   k  )) 
 (  define   (  f-aux&   n   a   k  ) 
  (  =&   n   0   (  лямбда   (  b  ) 
           (  if   b                      ; немодифицированное продолжение 
               (  k   a  )                  ; в рекурсивном вызов 
               (  -&   n   1   (  лямбда   (  nm1  )  
                        (  *&   n   a   (  лямбда   (  nta  ) 
                                 (  f-aux&   nm1   nta   k  ))))))))) 

Обратите внимание, что в версиях CPS используются примитивы, например +& и *& сами по себе являются CPS, а не прямым стилем, поэтому, чтобы приведенные выше примеры работали в системе Scheme, нам нужно будет написать эти версии примитивов CPS, например, *& определяется:

(  определить   (  *&   x   y   k  ) 
  (  k   (  *   x   y  ))) 

В общем, чтобы сделать это, мы могли бы написать процедуру преобразования:

(  define   (  cps-prim   f  ) 
  (  лямбда-   аргументы 
   (  let   ((  r   (  reverse   args  ))) 
    ((  car   r  )   (  apply   f 
              (  reverse   (  cdr   r  ))))))) 
 (  define   *&   (  cps-prim   *  )) 
 (  определить   +&   (  cps-prim   +  )) 

Чтобы вызвать процедуру, написанную на CPS, из процедуры, написанной в прямом стиле, необходимо предоставить продолжение, которое будет получать результат, вычисленный процедурой CPS. В приведенном выше примере (при условии, что были предоставлены примитивы CPS) мы могли бы вызвать (factorial& 10 (lambda (x) (display x) (newline))).

Между компиляторами существуют некоторые различия в способах предоставления примитивных функций в CPS. Выше мы использовали простейшее соглашение, однако иногда предоставляются логические примитивы, для вызова которых в двух возможных случаях требуется два преобразователя , поэтому (=& n 0 (lambda (b) (if b ...))) позвони внутрь f-aux& определение выше будет записано вместо этого как (=& n 0 (lambda () (k a)) (lambda () (-& n 1 ...))). Аналогично, иногда if Сам примитив не включен в CPS, а вместо него используется функция if& предоставляется, который принимает три аргумента: логическое условие и два переходника, соответствующие двум ветвям условного выражения.

Приведенные выше переводы показывают, что CPS представляет собой глобальную трансформацию. прямого типа Как и следовало ожидать, факториал принимает один аргумент; CPS факториал& принимает два аргумента: аргумент и продолжение. Любая функция, вызывающая функцию CPS, должна либо предоставить новое продолжение, либо передать свое собственное; любые вызовы функции, поддерживающей CPS, к функции, не поддерживающей CPS, будут использовать неявные продолжения. Таким образом, чтобы обеспечить полное отсутствие стека функций, вся программа должна находиться в CPS.

CPS в Haskell [ править ]

В этом разделе мы напишем функцию pythкоторый вычисляет гипотенузу по теореме Пифагора . Традиционная реализация pyth функция выглядит следующим образом:

pow2   ::   Float   ->   Float 
 pow2   x   =   x   **   2 

 add   ::   Float   ->   Float   -   > Float 
 add   x   y   =   x   +   y 

 pyth   ::   Float   ->   Float   ->   Float 
 pyth   x   y   =   sqrt   (  add   (  pow2   х  )   (  pow2   y  )) 

Чтобы преобразовать традиционную функцию в CPS, нам нужно изменить ее сигнатуру. Функция получит еще один аргумент типа функции, и ее тип возвращаемого значения зависит от этой функции:

pow2'   ::   Float   -   (  Float   - >   a  )   -   a 
 pow2'   x   cont   =   cont   (  x   **   2  ) 

 add'   ::   Float   ->   > Float   ->   (  Float   ->   a  )   ->   > a 
 add'   x   y   cont   =   cont   (  x   +   y  ) 

 -- Типы a -> (b -> c) и a -> b -> c эквивалентны, поэтому функцию CPS 
 можно рассматривать как функцию более высокого порядка 
 sqrt'   ::   Float   ->   ((  Float   ->   a  )   ->   a  ) 
 sqrt'   x   =   \  cont   ->   cont   (  sqrt   x  ) 

 pyth'   ::   Float   ->   Float   ->   (  Float   ->   a  )   ->   a 
 pyth'   x   y   cont   =   pow2'   x   (  \  x2   ->   pow2'   y   (  \  y2   ->   add'   x2   y2   (  \  anb   ->   sqrt'   anb   cont  ))) 

Сначала вычислим квадрат а в pyth'функцию и передать лямбда-функцию в качестве продолжения, которая будет принимать квадрат a в качестве первого аргумента. И так до тех пор, пока не дойдем до результата наших расчетов. Чтобы получить результат этой функции, мы можем передать id функция в качестве последнего аргумента, который возвращает переданное ей значение без изменений: pyth' 3 4 id == 5.0.

Библиотека mtl, поставляемая с GHC , имеет модуль Control.Monad.Cont. Этот модуль предоставляет тип Cont, который реализует Monad и некоторые другие полезные функции. В следующем фрагменте показано pyth' функция с использованием Cont:

pow2_m   ::   Float   ->   Cont   a   Float 
 pow2_m   a   =   return   (  a   **   2  ) 

 pyth_m   ::   Float   ->   Float   ->   Cont   a   Float 
 pyth_m   a   b   =   do 
   a2   <-   pow2_m   a 
   b2   <-   pow2_m   b 
   anb   <-   cont   (  add'   a2   b2  ) 
   r   <-   cont   (  sqrt'   anb  ) 
   return   r 

Синтаксис не только стал чище, но и этот тип позволяет нам использовать функцию callCC с типом MonadCont m => ((a -> m b) -> m a) -> m a. Эта функция имеет один аргумент типа функции; этот аргумент функции также принимает функцию, которая отбрасывает все вычисления, выполняемые после ее вызова. Например, давайте прервем выполнение pyth функция, если хотя бы один из ее аргументов отрицательный, возвращающий ноль:

pyth_m   ::   Float   ->   Float   ->   Cont   a   Float 
 pyth_m   a   b   =   callCC   $   \  exitF   ->   do   -- $ знак помогает избежать круглых скобок: a $ b + c == a (b + c), 
   когда   (  b   <   0   ||   a   <   0  )   (  exitF   0.0  )   -- когда :: Аппликативный f => Bool -> f () -> f () 
   a2   <-   pow2_m   a 
   b2   <-   pow2_m   b 
   anb   <-   cont   (  add'   a2   b2  ) 
   r   <-   cont   (  sqrt'   anb  ) 
   return   r 

Продолжения как объекты [ править ]

Программирование с использованием продолжений также может быть полезно, когда вызывающая сторона не хочет ждать завершения выполнения вызываемой программы. Например, в программировании пользовательского интерфейса (UI) процедура может настроить поля диалогового окна и передать их вместе с функцией продолжения в структуру пользовательского интерфейса. Этот вызов сразу же возвращается, позволяя коду приложения продолжать работу, пока пользователь взаимодействует с диалоговым окном. Как только пользователь нажимает кнопку «ОК», платформа вызывает функцию продолжения с обновленными полями. Хотя этот стиль кодирования использует продолжения, он не является полным CPS. [ нужны разъяснения ]

функция   подтвержденияИмя  ()   { 
     поля  .   имя   =   имя  ; 
      рамки  .   Show_dialog_box  (  поля  ,   подтверждениеИмениПродолжение  ); 
  } 

 функция   подтвержденияИмяПродолжение  (  поля  )   { 
     имя   =   поля  .   имя  ; 
  } 

Аналогичную идею можно использовать, когда функция должна выполняться в другом потоке или на другом процессоре. Платформа может выполнить вызванную функцию в рабочем потоке, а затем вызвать функцию продолжения в исходном потоке с результатами рабочего потока. Это в Java 8 с использованием инфраструктуры Swing UI:

void   buttonHandler  ()   { 
     // Это выполняется в потоке пользовательского интерфейса Swing. 
      // Здесь мы можем получить доступ к виджетам пользовательского интерфейса, чтобы получить параметры запроса. 
     int    параметр   =   getField  (); 

      new   Thread  (()   ->   { 
         // Этот код выполняется в отдельном потоке. 
         // Мы можем делать такие вещи, как доступ к базе данных или 
         // блокирующему ресурсу, такому как сеть, для получения данных. 
         int   result   =   поиск  (  параметр  ); 

         javax  .  SwingUtilities  .  //  ;  ignoreLater  (()   ->   { 
             // Этот код выполняется в потоке пользовательского интерфейса и может использовать 
             полученные данные для заполнения виджетов пользовательского интерфейса. 
             setField  (  result  ); 
         } 
     )   начинать  (); 
  } 

Хвостовые вызовы [ править ]

Каждый вызов в CPS является хвостовым вызовом , и продолжение передается явно. Использование CPS без оптимизации хвостового вызова (TCO) приведет к потенциальному росту во время рекурсии не только созданного продолжения, но и стека вызовов . Обычно это нежелательно, но его можно использовать интересным образом — см. компилятор Chicken Scheme . Поскольку CPS и TCO устраняют концепцию неявного возврата функции, их совместное использование может устранить необходимость в стеке времени выполнения. Некоторые компиляторы и интерпретаторы функциональных языков программирования используют эту возможность по-новому. [6]

Использование и реализация [ править ]

Стиль передачи продолжения можно использовать для реализации продолжений и операторов потока управления на функциональном языке, который не имеет первоклассных продолжений , но имеет первоклассные функции и оптимизацию хвостовых вызовов . Без оптимизации хвостового вызова такие методы, как трамплин , то есть использование цикла, который итеративно вызывает функции, возвращающие thunk можно использовать ; без первоклассных функций в таком цикле можно даже преобразовать хвостовые вызовы в просто переходы.

Написание кода в CPS хотя и не невозможно, но часто подвержено ошибкам. Существуют различные переводы, обычно определяемые как одно- или двухпроходные преобразования чистого лямбда-исчисления , которые преобразуют выражения прямого стиля в выражения CPS. Однако писать батутным стилем чрезвычайно сложно; при использовании он обычно является целью какого-либо преобразования, например компиляции .

Функции, использующие более одного продолжения, могут быть определены для захвата различных парадигм потока управления, например (в Scheme ):

(  define   (  /&   x   y   ok   err  ) 
  (  =&   y   0.0   (  лямбда   (  b  ) 
             (  if   b 
                 (  err   (  список   «деление на ноль!»   x   y  )) 
                 (  ok   (  /   x   y  )))))) 

Следует отметить, что преобразование CPS концептуально является вложением Йонеды . [7] Это также похоже на встраивание лямбда-исчисления в π-исчисление . [8] [9]

Использование в других областях [ править ]

За пределами информатики CPS представляет более общий интерес как альтернатива традиционному методу составления простых выражений в сложные. Например, в рамках лингвистической Крис семантики Баркер и его коллеги предположили, что определение значений предложений с использованием CPS может объяснить определенные явления в естественном языке . [10]

В математике изоморфизм Карри -Ховарда между компьютерными программами и математическими доказательствами связывает перевод в стиле передачи продолжения с вариацией вложений двойного отрицания классической логики в интуиционистскую (конструктивную) логику . В отличие от обычного перевода с двойным отрицанием , который отображает атомарные предложения p в (( p → ⊥) → ⊥), стиль передачи продолжения заменяет ⊥ типом конечного выражения. Соответственно, результат получается путем передачи тождественной функции как продолжения выражения CPS, как в приведенном выше примере.

Классическая логика сама по себе связана с непосредственным управлением продолжением программ, как в операторе управления вызовом с текущим продолжением Scheme , наблюдении Тима Гриффина (с использованием тесно связанного оператора управления C). [11]

См. также [ править ]

Примечания [ править ]

  1. ^ Сассман, Джеральд Джей ; Стил, Гай Л. младший (декабрь 1975 г.). «Схема: интерпретатор расширенного лямбда-исчисления» . Памятка AI . 349 : 19. То есть в этом стиле программирования с передачей продолжения функции функция всегда «возвращает» свой результат, «отправляя» его другой . Это ключевая идея.
  2. ^ Сассман, Джеральд Джей ; Стил, Гай Л. младший (декабрь 1998 г.). «Схема: интерпретатор расширенного лямбда-исчисления» (переиздание) . Вычисления высшего порядка и символьные вычисления . 11 (4): 405–439. дои : 10.1023/А:1010035624696 . S2CID   18040106 . термина « стиль продолжения-прохода Мы полагаем, что это было первое появление в литературе ». Это оказалось важной концепцией анализа и преобразования исходного кода для компиляторов и других инструментов метапрограммирования. Он также вдохновил множество других «стилей» программного выражения.
  3. ^ Рейнольдс, Джон К. (1993). «Открытия продолжений». LISP и символьные вычисления . 6 (3–4): 233–248. CiteSeerX   10.1.1.135.4705 . дои : 10.1007/bf01019459 . S2CID   192862 .
  4. ^ * Аппель, Эндрю В. (апрель 1998 г.). «SSA — это функциональное программирование». Уведомления ACM SIGPLAN . 33 (4): 17–20. CiteSeerX   10.1.1.34.3282 . дои : 10.1145/278283.278285 . S2CID   207227209 .
  5. ^ * Келси, Ричард А. (март 1995 г.). «Соответствие между стилем прохождения продолжения и статической формой одиночного задания». Уведомления ACM SIGPLAN . 30 (3): 13–22. CiteSeerX   10.1.1.489.930 . дои : 10.1145/202530.202532 .
  6. ^ Аппель, Эндрю В. (1992). Компиляция с продолжениями. Издательство Кембриджского университета. ISBN   0-521-41695-7 .
  7. ^ Майк Стей, «Преобразование с продолжением передачи и вложение Йонеды»
  8. ^ Майк Стей, "Исчисление Пи II"
  9. ^ Будоль, Жерар (1997). «П-исчисление в прямом стиле». CiteSeerX   10.1.1.52.6034 .
  10. ^ Баркер, Крис (1 сентября 2002 г.). «Продолжение и природа количественной оценки» (PDF) . Семантика естественного языка . 10 (3): 211–242. дои : 10.1023/А:1022183511876 . ISSN   1572-865X . S2CID   118870676 .
  11. ^ Гриффин, Тимоти (январь 1990 г.). «Формула как тип понятия контроля». Материалы 17-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования - POPL '90 . Том. 17. С. 47–58. дои : 10.1145/96709.96714 . ISBN  978-0-89791-343-0 . S2CID   3005134 .

Ссылки [ править ]

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: 9E9D2622E16F07583163C77B232CD09E__1698928320
URL1:https://en.wikipedia.org/wiki/Continuation_passing_style
Заголовок, (Title) документа по адресу, URL1:
Continuation-passing style - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)