Representation of monadic effects in the non-monadic form

Modern programming relies heavily on effects systems. In the context of the development of programming languages, two approaches to understanding effects are distinguished: the first recognizes an effect as a characteristic of a program that affects the execution environment, separating it from a si...

Full description

Saved in:
Bibliographic Details
Date:2024
Main Author: Shevchenko, R.S.
Format: Article
Language:Ukrainian
Published: PROBLEMS IN PROGRAMMING 2024
Subjects:
Online Access:https://pp.isofts.kiev.ua/index.php/ojs1/article/view/627
Tags: Add Tag
No Tags, Be the first to tag this record!
Journal Title:Problems in programming
Download file: Pdf

Institution

Problems in programming
id pp_isofts_kiev_ua-article-627
record_format ojs
resource_txt_mv ppisoftskievua/93/20764b490db4b7ed35f149a932120f93.pdf
spelling pp_isofts_kiev_ua-article-6272025-02-15T10:28:10Z Representation of monadic effects in the non-monadic form Представлення монадичних ефектів у немонадичній формі Shevchenko, R.S. effects; monads; Scala; programing language; program transformation UDC 004.424 ефекти; монади; Scala; мови програмування; перетворення програм УДК 004.424 Modern programming relies heavily on effects systems. In the context of the development of programming languages, two approaches to understanding effects are distinguished: the first recognizes an effect as a characteristic of a program that affects the execution environment, separating it from a simple calculation (that is, effects are not taken into account in the system of language types, which is typical for imperative programming languages); the second considers an effect as an aspect of program interpretation that affects the process of its interpretation (such effects are considered in the type system as higher-order types, and this approach is characteristic of functional programming). In industrial programming, the first approach is preferred because of its efficiency in rapid development and less complex concepts. However, this leads to the loss of the possibility of automatic analysis of effects using type systems and increases the difficulty of finding errors. Monads are a convenient tool for describing effects because they have a built-in computation composition operation and can sink values into the monadic environment. A direct contextual representation of effects can be useful for application developers because it reduces cognitive load from syntactic noise while preserving information about effects in data types. This representation also allows for cross-platform applications that can use both monadic and non-monadic effect systems. The paper describes the ergonomic programming language interface for working with monadic effects, which encapsulates the logic of computation and associated non-computational operations in the effect system monad, and describes the direct context encoding technique. The translation of the direct context encoding into the monadic form is implemented in the form of a Scala compiler plugin, which is available as an open source. The use of conditional effects compilation to organize cross-platform interfaces that combine different methods of implementing effects on different platforms is also discussed.Prombles in programming 2024; 2-3: 116-123  Сучасне програмування значною мірою покладається на системи ефектів. У контексті розробки мов програмування виокремлюються два підходи до розуміння ефектів: перший визнає ефект як характеристику програми, яка впливає на середовище виконання, відокремлюючи її від простого обчислення (тобто ефекти не враховуються в системі типів мови, що є типовим для імперативних мов програмування); другий розглядає ефект як аспект інтерпретації програми, який впливає на процес її інтерпретації (такі ефекти враховуються в системі типів як типи вищого порядку, і цей підхід характерний для функціонального програмування). В індустріальному програмуванні перевагу надають першому підходу через його ефективність у швидкій розробці та меншій складності концепцій. Проте це призводить до втрати можливості автоматичного аналізу ефектів за допомогою систем типів та збільшує складність знаходження помилок. Монади є зручним інструментом для опису ефектів, оскільки вони мають вбудовану операцію композиції обчислень і можуть занурювати значення у монадичне середовище. Пряме контекстне представлення ефектів може бути корисним для розробників програм, оскільки це дозволяє знизити когнітивне навантаження від синтаксичного шуму і водночас зберігає інформацію про ефекти у типах даних. Таке представлення також дозволяє створювати кросплатформові програми, які можуть використовувати як монадичні, так і немонадичні системи ефектів. У статті розглядається проблематика створення ергономічного інтерфейсу для роботи з монадичними ефектами, які включають логіку обчислень та пов’язані операції у монаді системи ефектів, а також описується пряме контекстне представлення ефектів. Перетворення прямого контекстного представлення на монадичну форму реалізовано через плагін компілятора Scala, що доступний у вигляді відкритого коду. Також розглядається використання умовної компіляції ефектів для створення крос-платформових інтерфейсів, що об’єднують різні методи реалізації ефектів на різних платформах.Prombles in programming 2024; 2-3: 116-123  PROBLEMS IN PROGRAMMING ПРОБЛЕМЫ ПРОГРАММИРОВАНИЯ ПРОБЛЕМИ ПРОГРАМУВАННЯ 2024-12-17 Article Article application/pdf https://pp.isofts.kiev.ua/index.php/ojs1/article/view/627 10.15407/pp2024.02-03.116 PROBLEMS IN PROGRAMMING; No 2-3 (2024); 116-123 ПРОБЛЕМЫ ПРОГРАММИРОВАНИЯ; No 2-3 (2024); 116-123 ПРОБЛЕМИ ПРОГРАМУВАННЯ; No 2-3 (2024); 116-123 1727-4907 10.15407/pp2024.02-03 uk https://pp.isofts.kiev.ua/index.php/ojs1/article/view/627/679 Copyright (c) 2024 PROBLEMS IN PROGRAMMING
institution Problems in programming
baseUrl_str https://pp.isofts.kiev.ua/index.php/ojs1/oai
datestamp_date 2025-02-15T10:28:10Z
collection OJS
language Ukrainian
topic effects
monads
Scala
programing language
program transformation
UDC 004.424
spellingShingle effects
monads
Scala
programing language
program transformation
UDC 004.424
Shevchenko, R.S.
Representation of monadic effects in the non-monadic form
topic_facet effects
monads
Scala
programing language
program transformation
UDC 004.424
ефекти
монади
Scala
мови програмування
перетворення програм
УДК 004.424
format Article
author Shevchenko, R.S.
author_facet Shevchenko, R.S.
author_sort Shevchenko, R.S.
title Representation of monadic effects in the non-monadic form
title_short Representation of monadic effects in the non-monadic form
title_full Representation of monadic effects in the non-monadic form
title_fullStr Representation of monadic effects in the non-monadic form
title_full_unstemmed Representation of monadic effects in the non-monadic form
title_sort representation of monadic effects in the non-monadic form
title_alt Представлення монадичних ефектів у немонадичній формі
description Modern programming relies heavily on effects systems. In the context of the development of programming languages, two approaches to understanding effects are distinguished: the first recognizes an effect as a characteristic of a program that affects the execution environment, separating it from a simple calculation (that is, effects are not taken into account in the system of language types, which is typical for imperative programming languages); the second considers an effect as an aspect of program interpretation that affects the process of its interpretation (such effects are considered in the type system as higher-order types, and this approach is characteristic of functional programming). In industrial programming, the first approach is preferred because of its efficiency in rapid development and less complex concepts. However, this leads to the loss of the possibility of automatic analysis of effects using type systems and increases the difficulty of finding errors. Monads are a convenient tool for describing effects because they have a built-in computation composition operation and can sink values into the monadic environment. A direct contextual representation of effects can be useful for application developers because it reduces cognitive load from syntactic noise while preserving information about effects in data types. This representation also allows for cross-platform applications that can use both monadic and non-monadic effect systems. The paper describes the ergonomic programming language interface for working with monadic effects, which encapsulates the logic of computation and associated non-computational operations in the effect system monad, and describes the direct context encoding technique. The translation of the direct context encoding into the monadic form is implemented in the form of a Scala compiler plugin, which is available as an open source. The use of conditional effects compilation to organize cross-platform interfaces that combine different methods of implementing effects on different platforms is also discussed.Prombles in programming 2024; 2-3: 116-123 
publisher PROBLEMS IN PROGRAMMING
publishDate 2024
url https://pp.isofts.kiev.ua/index.php/ojs1/article/view/627
work_keys_str_mv AT shevchenkors representationofmonadiceffectsinthenonmonadicform
AT shevchenkors predstavlennâmonadičnihefektívunemonadičníjformí
first_indexed 2025-07-17T10:02:34Z
last_indexed 2025-07-17T10:02:34Z
_version_ 1850410742046523392
fulltext Мови програмування 116 УДК 004.424 http://doi.org/10.15407/pp2024.02-03.116 Р.С. Шевченко ПРЕДСТАВЛЕННЯ МОНАДИЧНИХ ЕФЕКТІВ У НЕМОНАДИЧНІЙ ФОРМІ Сучасне програмування значною мірою покладається на системи ефектів. У контексті розробки мов програмування виокремлюються два підходи до розуміння ефектів: перший визнає ефект як характе- ристику програми, яка впливає на середовище виконання, відокремлюючи її від простого обчислення (тобто ефекти не враховуються в системі типів мови, що є типовим для імперативних мов програму- вання); другий розглядає ефект як аспект інтерпретації програми, який впливає на процес її інтерпре- тації (такі ефекти враховуються в системі типів як типи вищого порядку, і цей підхід характерний для функціонального програмування). В індустріальному програмуванні перевагу надають першому підходу через його ефективність у швидкій розробці та меншій складності концепцій. Проте це приз- водить до втрати можливості автоматичного аналізу ефектів за допомогою систем типів та збільшує складність знаходження помилок. Монади є зручним інструментом для опису ефектів, оскільки вони мають вбудовану операцію композиції обчислень і можуть занурювати значення у монадичне сере- довище. Пряме контекстне представлення ефектів може бути корисним для розробників програм, оскільки це дозволяє знизити когнітивне навантаження від синтаксичного шуму і водночас зберігає інформацію про ефекти у типах даних. Таке представлення також дозволяє створювати крос- платформові програми, які можуть використовувати як монадичні, так і немонадичні системи ефек- тів. У статті розглядається проблематика створення ергономічного інтерфейсу для роботи з монадич- ними ефектами, які включають логіку обчислень та пов’язані операції у монаді системи ефектів, а також описується пряме контекстне представлення ефектів. Перетворення прямого контекстного представлення на монадичну форму реалізовано через плагін компілятора Scala, що доступний у ви- гляді відкритого коду. Також розглядається використання умовної компіляції ефектів для створення крос-платформових інтерфейсів, що об’єднують різні методи реалізації ефектів на різних платфор- мах. Ключові слова: ефекти, монади, Scala, мови програмування, перетворення програм. R.S. Shevchenko REPRESENTATION OF MONADIC EFFECTS IN THE NON-MONADIC FORM Modern programming relies heavily on effects systems. In the context of the development of programming languages, two approaches to understanding effects are distinguished: the first recognizes an effect as a characteristic of a program that affects the execution environment, separating it from a simple calculation (that is, effects are not taken into account in the system of language types, which is typical for imperative programming languages); the second considers an effect as an aspect of program interpretation that affects the process of its interpretation (such effects are considered in the type system as higher -order types, and this approach is characteristic of functional programming). In industrial programming, the first approach is preferred because of its efficiency in rapid development and less complex concepts. However, this leads to the loss of the possibility of automatic analysis of effects using type systems and increases the difficulty of finding errors. Monads are a convenient tool for describing effects because they have a built-in computation composition operation and can sink values into the monadic environment. A direct contextual representation of effects can be useful for application developers because it reduces cognitive load from syntactic noise while preserving information about effects in data types. This representation also allows for cross -platform applications that can use both monadic and non-monadic effect systems. The paper describes the ergonomic programming language interface for working with monadic effects, which encapsulates the logic of compu- tation and associated non-computational operations in the effect system monad, and describes the direct con- text encoding technique. The translation of the direct context encoding into the monadic form is implement- ed in the form of a Scala compiler plugin, which is available as an open source. The use of conditional ef- fects compilation to organize cross-platform interfaces that combine different methods of implementing ef- fects on different platforms is also discussed. Key words: effects, monads, Scala, programing language, program transformation. © Р.С. Шевченко, 2024 ISSN 1727-4907. Проблеми програмування. 2024. №2-3 Мови програмування 117 Вступ Системи ефектів зайняли важливе місце у сучасному програмуванні. Водно- час у розробці мов програмування існують два погляди на ефекти: − Ефект - це властивість програми, що продукує зміни у середовище виконан- ня, відмінні від суто обчислень. Ефекти не відображаються у системі типів мови. Цей погляд характерний для імперативних мов програмування; − Ефект - це властивість інтерпре- тації програми, що продукує зміни у про- цесі інтерпретації. Ефекти відображаються у системи типів як типи вищого порядку. Цей погляд характерний для функціональ- ного програмування. В індустріальному програмуванні перший погляд виграє з точки зору швид- кості розробки та меншої кількості опану- вання концепцій, проте ціною є неможли- вість автоматичного аналізу ефектів за допомогою системи типів і більша трудо- місткість знаходження помилок. Зрештою, ці поняття все одно з’являються у вигляді опису exception-free коду та засобів аналі- зу, але вивчати їх доводиться пізніше. Функціональний підхід зазвичай представляється виразом з ефектами, як монадичний вираз F[T], де T — тип вира- зу, який був би без явних ефектів у імпера- тивній мові програмування. Монади є зручним інструментом для опису ефектів завдяки тому, що на них за визначенням існує операція композиції обчислень та занурення значення у мона- дичне середовище. Сигнатура цих опера- цій мовою Scala, яку ми будемо викорис- товувати у прикладах, виглядає як: flatMap[A,B](fa: F[A])(f: A=>F[B]):F[B] та pure[A](a:A): F[A]. У літературі з функціонального програмування часто використовується стандартний монадичний тайпклас для мови Haskell, де ця операція композиції обчислень виглядає як bind: F A -> (A->F B) -> F B, а занурення у середовище як unit: A -> F A. Для детального опису властивостей монадичних інтерфейсів рекомендуємо звернутись до статей Moddy [1] та Wadler [2, 3]. Класичними прикладами монадич- них ефектів є операції вводу/виводу, що як правило, відображаються як IO[X], або аварійне виключення Try [X]. Інтерпретатор монади ефекту це функція, що перетворює монадичний ви- раз на його значення та виконує ефекти. Записати тип можливо у метанотації, що включає до себе також значення середо- вища. Тепер перейдемо від одиночних ефектів до систем ефектів. Нехай ми роз- робляємо програму, що робить одночасно і ввід/вивід, і може аварійно завершитися. Який тип вона може мати? Це не IO[T] і не Try [T]. Це якась монада, яка включає в себе обидва ефекти. Існує багато способів побудови таких монад, наведемо найбільш відомі. Рішення, яке ще не можна назвати повноцінною системою ефектів, але часто використовується на практиці — це так звана “монада-бог” (“god monad”). Тобто можна побудувати монаду, що буде поєд- нувати в собі і обробку вводу/виводу, і генерацію помилок. Якщо кількість ефек- тів, що використовуються, невелика, то такий підхід досить зручний. Проте, на відміну від повноцінних систем ефектів, там неможливо додати новий ефект або замінити імплементацію існуючого без переписування інтерпретатора монади. Історично перший повноцінний стек ефектів був побудований на основі монадних трансформерів [4, 5]. Основна ідея досить проста — логічним типом для результату програми, що має ввід/вивід та може генерувати виключення є IO[Try[T]]. Ми не можемо використовувати IO[T] Мови програмування 118 прямо, але можемо переписати IO у вигля- ді IOT[F[_],T]. Інтерпретатор цієї монади перетворює IOT[F[_],T] у T, використову- ючи інтерпретатор F. (Або у деяких випад- ках можна побудувати частковий інтерп- ретатор, який можна вже називати оброб- ником ефекту, що перетворить IO[F[_],T] у F[T]. А далі ми, вже маючи інтерпретатор F[T], можемо побудувати повний інтерп- ретатор складної монади.) Така схема про- ста та інтуїтивно зрозуміла. Цей підхід використовується у індустріальному фун- кціональному програмуванні, коли в нас є один або два ефекти, що є досить пошире- ним випадком. Але в роботі з великим списком ефектів виникають проблеми продуктивності, оскільки кожна операція має пройти через низку викликів для кож- ної монади у стеку. Наступним кроком є використання горизонтальної композиції замість вкла- дення, тобто розділення “монади, що міс- тить ефекти” та суто ефектів. Тобто, на- приклад, є типи ефектів 1[*], , [*]nE ... E і можливості мови програмування дозволя- ють нам сконструювати список рівня типів 1( , , ).nL E ... E= Тоді можна побудувати монаду 1( ) [( , , ), ]nEff X F E ... E X= разом з інтерпретаторами ефектів, що мають вид: : [ , ] [ , ],k kIE F L X F L E X − де 1 1 1( ... , ... )k k k nL E E E E E− +− = — список типів ефектів L без kE . Самі типи ефектів iE не обов’язково повинні бути монадами. Класичний приклад конструкції та- кого типу — це Freerer монада [6]. Зараз у контексті індустріального програмування, коли кажуть про монадичну систему ефек- тів, то загалом мають на увазі подібну конструкцію з низкою оптимізацій. Для Haskell існують близько десяти реалізацій, для Scala зараз у розробці декілька систем, такі як Eff [7], Kryo [8], Turbolift [9]. Ще слід згадати так званий безтего- вий кінцевий (tagless final) стиль опису [11], де до ефектів звертаються не як конк- ретних типів, а як до тайпкласів, що реалі- зують деяке API [10]. Дійсно, єдине, що характеризує ефект, — це набір методів, як от, гіпотетичний ефект вводу/виводу може характеризуватись парою функцій trait StdIO[X] { def putStrLn(line: String): StdIO[X] def getStrLn: StdIO[String] } Якщо ми можемо “проштовхнути” ці функції у основну монаду, то це API можна записати як trait StdIO[F[_]] { def putStrLn(line: String): F[X] def getStrLn: F[String] } А потім використовувати цей тайпклас як характеристику монади ефек- тів, незалежно від того, як ця монада по- будована — як самостійна монада ефекту або елемент монадного трансформера або елемент системи ефектів. Тепер можемо сформулювати зада- чу. В нас є два методи організації ефектів: чи можемо ми сумістити ці дві форми так, щоб було можливо використовувати мона- дичні ефекти без ускладнення синтаксису, водночас залишаючи можливість аналізу виразів з ефектами за допомогою систем типів? Ця задача має два прикладних за- стосування. Перше — це полегшення ро- боти з монадними інтерфейсами для роз- робників, друге — мультиплатформові системи з різними можливостями рантай- му на різних платформах. Тоді ефекти, що можуть бути представлені у прямій формі на одній платформі (наприклад, асинхрон- ність на post-Loom JVM), мають бути мо- надичними на платформі без підтримки продовжень (continuations), таких як Javascript. Прямий синтаксис Методи полегшення синтаксичного навантаження з’явились одночасно з мо- надичними інтерфейсами. Підходи можна розбити на дві групи: Мови програмування 119 − спеціальні конструкції, що ство- рюють “підмову” мови програмування для монадних DSL; − встановлення псевдооператорів, що перетворюють звичайні конструкції мови у монадичну форму. Прикладом першого підходу є do- notation у Haskell [11], Computation Expres- sions у С# [12] та for-comprehansions у Scala [13]. З одного боку це зручно у реалі- зації, адже ці синтаксичні конструкції компілятор може перетворювати до аналі- зу типів, з іншого — користувач бачить дві схожі, але різні мови, що спричиняє додат- кові складнощі під час вивчення та засто- сування. Прикладом другого підходу є bing notation в Idris [14] та async/await (щоправ- да обмежено асинхронністю) у C# та біль- шості сучасних мов програмування [15]. Автором було розроблено подібну систему для Scala: dotty-cps-async [16–18], що підт- римує пару псевдооператорів reify/reflect (або async/await як традиційні синоніми) для будь-якої монади як макроси. Практи- чно це рішення вирішує питання зменшен- ня когнітивного навантаження у застосу- ванні асинхронних API та “пом’якшення” кривої навчання. Проте, у процесі роботи з монадичними ефектами виникають насту- пні складності. Оскільки у системах ефектів біль- шість операцій монадичні, вихідний код все ж таки перевантажений операторами reflect (або await), що не несуть нетехніч- ного змісту. Так, наприклад, на Рис. 1 ми бачимо “await” майже у кожному рядку. Друга проблема, специфічна для систем ефектів. У наведеному вище прик- ладі ми працюємо з однією монадою IO, яку вказуємо як параметр типу async[IO]. Якщо ми працюємо з системами ефектів, то там тип монади складний і async вираз буде мати вигляд async[[X]=> Eff[IO::*Error::*Config,X]] Програміст мусить написати цю по- вну тайп-сигнатуру, що інколи змінюється залежно від того, які ефекти використову- ються. Але макрос може зібрати типи ефе- ктів, що використовуються, і на основі цього вивести повний тип ефекту. Для вирішення питання переванта- ження async-виразами, в перших версіях dotty-cps-async був запропонований режим автоматичного розфарбовування, що засно- ваний на неявних перетвореннях. Ми до- зволяємо неявне перетворення між IO[T] та T, якщо єдине використання асинхронного виразу це взяття або ігнорування значення. Якщо вираз використовується по-іншому (наприклад, передається в іншу функцію як IO), то ми повідомляємо про помилку. При- клад використання автоматичного розфар- бовування показано на Рис. 2. def myFun(using RunContext): IO[HttpReply] = async[IO] { val results1 = await(talkToServer("request1", None)) await(IO.sleep(100.millis)) val results2 = await(talkToServer("request2", Some(results1.data))) if results2.isOk then await(writeToFile(results2.data)) await(IO.println("done")) else await(IO.println("abort")) results2 } Рис. 1. Використання dotty-cps-async без автоматичного розфарбовування Мови програмування 120 Як бачимо, візуально деяке покра- щення є, але це рішення не набуло широ- кого розповсюдження, оскільки аналіз та- кого коду дещо складніший (скажімо, чо- му біля result1 немає await а біля result2 є ?), і для того, щоб самостійно розуміти, які типи виводяться, потрібно крім правил мови ще враховувати контекст. Незважаю- чи на те, що макрос проводить аналіз типів і генерує помилку під час (можливо) неко- ректного використання, такі перетворення сприймалися розробниками як небезпечні. Наразі на зміну режиму автоматич- ного розфарбовування розроблений плагін компілятора, що дозволяє описувати мо- надичні обчислення у прямому стилі за допомогою контекстних аргументів і кон- текстних функцій. Контекстний аргумент (у Scala 2 він називався неявним аргументом) забезпечує можливість автоматично сконструювати і передати аргумент функції, не відобража- ючи це в коді програми. Списки аргумен- тів функцій та методів можуть маркува- тись як using і компілятор у процесі гене- рування виклику функції буде шукати зна- чення цих параметрів у контексті. Напри- клад, наступне визначення: def write[A](a:A) (using Writer[A]): Unit визначає функцію з контекстним парамет- ром Writer[A], і ми можемо викликати її як write(10). Контекстні функції (A ?=> B) були введені у Scala 3 [13] і означають обчис- лення, що залежать від контексту A та по- вертають B. Корисною для нас особливіс- тю є короткий синтаксис контекстних ля- мбда-функцій: в метод, що приймає на вхід контекстну функцію A ?=> B переда- ти вираз типу B, який містить виклики фу- нкцій з контекстним аргументом, що мо- жуть бути виведені з A. Наприклад, нехай у нас є якийсь об’єкт, з якого ми можемо вивести Writer для елементарних типів: trait Writers { given Writer[Int] ... given Writer[String] ... } і функція def withJsonWriters[A] (f: Writes ?=> A): A Тоді виклик такої функції може ма- ти форму: withJsonWriters { write(1) write("abc") } Повертаючись до монадичних ефе- ктів, ми можемо представити монадичне обчислення F[X] як контекстну функцію, def myFun(using RunContext): IO[HttpReply] = async[IO] { val results1 = talkToServer("request1", None) IO.sleep(100.millis) val results2 = await(talkToServer("request2", Some(results1.data))) if results2.isOk then writeToFile(results2.data) IO.println("done") else IO.println("abort") results2 } Рис. 2. Використання dotty-cps-async з автоматичним розфарбовуванням Мови програмування 121 що повертає X: CpsDirect[F] ?=> X. Вико- ристовуючи описані вище властивості контекстних функцій, ми можемо вільно використовувати результати асинхронних викликів у межах видимості CpsDirect[F] як значення типу X. Плагін компілятору перетворює функції та методи, що містять контекстний параметр CpsDirect[F] та повертають зна- чення типу X, у методи, що повертають F[X] і конвертують тіло цих методів у мо- надичну форму. Попередній приклад з Рис. 1 та Рис. 2 тепер можна записати, як показано на Рис. 3. Тут ми неявно вважаємо, що API, яке використовується, також конвертоване у пряме контекстне представлення. Ми можемо викликати функції із CpsDirect[F] параметром з async блоків і інших прямих контекстних функцій, а та- кож вільно використовувати псевдоопера- тор await/reflect для перетворення F[T] у T за необхідності. Для забезпечення корект- ності перетворень ми накладаємо ряд об- межень на вирази типу CpsDirect[F] — їх не можна використовувати в операторах присвоювання значення, вихідних значень функцій та зіставляти з параметрами типів. Можливо, у майбутньому ці обмеження можна буде виразити за допомогою відс- тежування захоплень (capture tracking), що зараз розробляється як експериментальне розширення Scala [19]. Отримана модель асинхронності на практиці досить близька до моделі призу- пинених функцій Kotlin [20]. Зазначимо, що на відміну від режи- му “автоматичного розфарбовування” фу- нкції, тут типи F[X] та CpsDirect[F] ?=> X є різними типами для програміста, і для кожної функції нам потрібно обирати, як краще представити асинхронне значення — у контекстній чи монадичній формі? Тобто проблема розфарбовування нікуди не зникла: просто з’явилась можливість змінити основний метод виклику на квазі- синхронний. Монадичні інтерфейси можуть ви- користовуватись поряд із прямими. Розг- лянемо приклад, коли монадичний інтер- фейс дійсно потрібен. Наприклад, нехай нам потрібно паралельно прочитати декі- лька потоків даних. Якщо припустити, що fetch також записана у прямій формі, то наступний блок коду - def readFirstN(urls: Seq[String]) (using CpsDirect[Future]):Seq[String = urls.map(url => fetch(url)) - прочитає усі дані послідовно, один за одним. Якщо нам потрібна паралельна def myFun(using RunContext, CpsDirect[IO]): HttpReply = { val results1 = talkToServer("request1", None) sleep(100.millis) val results2 = talkToServer("request2", Some(results1.data)) if results2.isOk then writeToFile(results2.data) println("done") else println("abort") results2 } Рис. 3. Використання dotty-cps-async: пряме контекстне представлення Мови програмування 122 обробка, то ми маємо перевести пряме API у монадичну форму: def readFirstN(urls: Seq[String]) (using CpsDirect[Future]:Seq[String] = urls.map(url => asynchronized(fetch(url)) ).map{ future => await(future) } Тому для прямого синтаксису вве- дений псевдооператор asynchronized (або reifeied), що перетворює псевдосинхрон- ний вираз на монадичний, дуальний до await. Для випадку, коли F[_] — складна монада ефектів, можна розробити корот- кий синтаксис вказання набору ефектів у F як набору контекстів або обмежень типу F. Одним з варіантів є абстракція від конкре- тної системи ефектів F у формі tagless final Оптимальний вигляд такого запису — від- крите питання, що є темою подальших досліджень. Сумісність з немонадичними системами ефектів Ще одна типова проблема розробки — це підтримка міжплатформо- вих бібліотек, де середовище виконання має різні властивості на різних платфор- мах. Зокрема, на платформі Java, почина- ючи з версії 21, стало можливо розробляти системи ефектів [21], засновані на продо- вженнях (continuations), тоді як подібне API в немонадичному вигляді неможливо у scala-js. Чи можливо побудувати такий режим компіляції, щоб один і той же код був сумісний з бібліотекою асинхронного програмування в JVM, заснованій на вір- туальних потоках, та системі, заснованій на асинхронній моделі конкурентності Ja- vascript? Основною проблемою є те, що немонадичні ефекти зараз ніяк не відобра- жаються у системи типів, тому зі сторони системи з продовженнями, в нас немає інформації для коректної трансляції. Отже, ми не можемо перенести код з системи, що ґрунтується на продовженнях, у монадич- ну. Але можемо навпаки: у монадичній системі типи мають всю необхідну інфор- мацію. Отже, можна записати API системи з продовженнями як пряме представлення монадичної форми, потім відкомпілювати його у Javascript як монадичну форму, а в JVM — просто стираючи контекстний па- раметр (тобто плагін повинен перетворю- вати CpsDirect[F] ?=> X в F[X] на Javascript, та в X на JVM для ефектів, що в JVM реалізовані через продовження). Це дозволить програмам використовувати одне й те ж базове API на обох платфор- мах. Висновки Пряме контекстне представлення ефектів може бути корисним інструментом при розробці програм, оскільки знижує когнітивне навантаження на програміста від синтаксичного шуму і в той же час зберігає в типах інформацію про ефекти. Також за допомогою такого представлення можна будувати крос-платформові програми, що можуть використовувати як монадичні, так і немонадичні системи ефектів. У проєкті dotty-cps-async розробле- но плагін компілятора Scala, що перетво- рює пряме контекстне представлення на монадичну форму. Подальші напрямки досліджень включають пошук оптимальної форми підтримки складних систем ефектів типу Eff, продовження експериментів у напрямку крос-платформової трансляції ефектів та вдосконалення генерації мона- дичного представлення програми. References 1. E. Moggi, Notions of computation and monads, in: Information and Computation, 93 1 (1991) 55–92. doi:10.1016/0890-5401(91)90052-4. 2. P. Wadler, Monads for Functional Programming, in: Advanced Functional Programming, First International Spring School on Advanced Functional Programming Techniques-Tutorial, Berlin, Heidelberg, Springer-Verlag, 1995, pp. 24–52. 3. P. Wadler, The essence of functional programming, in: Proceedings of the 19th ACM SIGPLAN-SIGACT symposium on Principles of programming languages Мови програмування 123 (POPL’92), 1992, New York, ACM, pp. 1–14. https://doi.org/10.1145/143165.143169 4. S. Liang, P. Hudak, M. Jones, Monad transformers and modular interpreters, in: Proceedings of the 22nd ACM SIGPLAN-SIGACT symposium on Principles of programming languages (POPL’95), 1995, New York, ACM, pp. 333–343. https://doi.org/10.1145/199448.199528 5. T. Schrijvers, M. Piróg, N. Wu, M. Jaskelioff, Monad transformers and modular algebraic effects: what binds them together, in: Proceedings of the 12th ACM SIGPLAN International Symposium on Haskell (Haskell 2019), 2019, New York, ACM, pp. 98–113. https://doi.org/10.1145/3331545.334259 6. O. Kiselyov, H. Ishii, Freer monads, more extensible effects. SIGPLAN Not. 50, 12 (2015) 94–105. https://doi.org/10.1145/2887747.2804319 7. eff: [cited 08.04.2024] https://github.com/atnos-org/eff 8. kyo: [cited 08.04.2024] https://github.com/getkyo/kyo 9. turbolift [cited 08.04.2024] https://marcinzh.github.io/turbolift/ 10. Carette, J., Kiselyov, O., Shan, C.-C., Finally tagless, partially evaluated: Tagless staged interpreters for simpler typed languages, in: Journal of Functional Programming, 19 5 (2009) 509–543. doi:10.1017/S0956796809007205. 11. P. Hudak, J. Hughes, S. P. Jones, P. Wadler, A history of Haskell: being lazy with class, in: Proceedings of the third ACM SIGPLAN conference on History of programming languages (HOPL III), New York, ACM, 2007, pp. 12–1–12–55. https://doi.org/10.1145/1238844.1238856 12. T. Petricek, D. Syme, The F# Computation Expression Zoo, in: Flatt, M., Guo, HF. (eds) Practical Aspects of Declarative Languages. PADL 2014. Lecture Notes in Computer Science, vol 8324. Cham, Springer, 2014, https://doi.org/10.1007/978-3-319-04132- 2_3 13. Scala 3 Language Reference. cited 08.04.2024 https://docs.scala- lang.org/scala3/reference/ 14. Idris Language Reference. cited 08.04.2024 https://docs.idris- lang.org/en/latest/reference/index.html 15. C# Asyncronious Programming Scenarious. cided 08.04.2024. https://learn.microsoft.com/en- us/dotnet/csharp/asynchronous- programming/async-scenarios 16. R. Shevchenko, Project Paper: Embedding Generic Monadic Transformer into Scala, in: Lecture Notes in Computer Science, 3401 (2022). https://doi.org/10.1007/978-3-031-21314- 4_1 17. dotty-cps-async. Retrieved 09.04.2024 https://github.com/rssh/dotty-cps-async 18. R.S. Shevchenko, А.Yu. Doroshenko, O.A. Yatsenko. Embedding a family of logic languages with custom monadic unification in Scala, in: Problems in programming 1 (2024) 3–11. [in Ukrainian] 19. A. Boruch-Gruszecki, M. Odersky, E. Lee, O. Lhoták, J. Brachthäuser, Capturing Types, in: ACM Trans. Program. Lang. Syst. 45, 4, Article 21 (2023) 52 p. https://doi.org/10.1145/3618003 20. Koltin coroutines guide. Retrieved 09.04.2024 https://kotlinlang.org/docs/coroutines- guide.html 21. Gears. An Async library for Scala. (cited 09.04.2024). https://github.com/lampepfl/gears Одержано: 10.04.2024 Внутрішня рецензія отримана: 18.04.2024 Зовнішня рецензія отримана: 27.04.2024 Про автора: 1Шевченко Руслан Сергійович, кандидат технічних наук старший науковий співробітник. https://orcid.org/0000-0002-1554-2019 Місце роботи автора: 1Інститут програмних систем НАН України, тел. +38-067-407-32-33 E-mail: ruslan@shevchenko.kiev.ua www.iss.nas.gov.ua