Подтвердить что ты не робот

Что означает алгебраические эффекты в FP?

Ref:

Я искал много ссылок, но, кажется, никто не мог объяснить это конкретно. Кто-нибудь может дать какой-нибудь код (использовать javaScript), чтобы объяснить это? Большое спасибо!

4b9b3361

Ответ 1

Насколько я понимаю тему, алгебраические эффекты в настоящее время представляют собой академическую/экспериментальную концепцию, которая позволяет изменять некоторые вычислительные элементы (такие как вызовы функций, операторы печати и т.д.), Называемые "эффектами", с помощью механизма, напоминающего throw catch

Простейший пример, который я могу представить на языке, подобном JavaScript, - это изменение выходного сообщения, скажем, console.log. Предположим, вы хотите добавить "Debug Message:" перед всеми вашими операторами console.log по любой причине. Это было бы проблемой в JavaScript. По сути, вам нужно будет вызывать функцию в каждом console.log следующим образом:

function logTransform(msg) { return "Debug Message: " + msg; }
console.log(logTransform("Hello world"));

Теперь, если у вас много операторов console.log необходимо изменить каждый из них, если вы хотите внести изменения в ведение журнала. Теперь концепция алгебраических эффектов позволит вам обрабатывать "эффект" console.log в системе. Думайте об этом как console.log исключение перед вызовом, и это исключение (эффект) всплывает и может быть обработано. Разница лишь в том, что при отсутствии обработки выполнение будет продолжаться, как будто ничего не произошло. То, что это позволяет вам делать, - это манипулировать поведением console.log в произвольной области (глобальной или просто локальной) без манипулирования фактическим вызовом console.log. Может выглядеть примерно так:

 try
 {
 console.log("Hello world");
 }
 catch effect console.log(continuation, msg)
 {
    msg = "Debug message: " + msg;
    continuation();
 }

Обратите внимание, что это не JavaScript, я просто создаю синтаксис. Поскольку алгебраические эффекты являются экспериментальной конструкцией, они не поддерживаются ни в одном из основных известных мне языков программирования (однако есть несколько экспериментальных языков, таких как eff https://www.eff-lang.org/learn/). Я надеюсь, что вы получите общее представление о том, как должен работать мой составленный код. В блоке try catch можно обработать эффект, который может быть console.log. Continuation - это токеноподобная конструкция, необходимая для контроля того, когда нормальный рабочий процесс должен продолжаться. Не обязательно иметь такую вещь, но это позволит вам делать манипуляции до и после console.log (например, вы можете добавить дополнительное сообщение журнала после каждого console.log)

В целом, алгебраические эффекты представляют собой интересную концепцию, которая помогает решить многие реальные проблемы в кодировании, но она также может создавать определенные подводные камни, если методы неожиданно ведут себя не так, как ожидалось. Если вы хотите использовать алгебраические эффекты прямо сейчас в JavaScript, вам придется написать для него саму основу, и вы, вероятно, не сможете применять алгебраические эффекты к основным функциям, таким как console.log. По сути, все, что вы можете сделать прямо сейчас, это изучить концепцию в абстрактном масштабе и подумать об этом или выучить один из экспериментальных языков. Я думаю, что это также причина, по которой многие из вступительных статей настолько абстрактны.

Ответ 2

Трудно получить твердое теоретическое понимание алгебраических эффектов без каких-либо оснований в теории категорий, поэтому я попытаюсь объяснить его использование в терминах непрофессионала, возможно, пожертвовав некоторой точностью.

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

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

Почему мы это делаем? Потому что иногда большие библиотеки имеют очень длинные цепочки абстракций, которые могут запутаться. Использование "алгебраических эффектов" дает нам своего рода короткий путь для передачи вещей между абстракциями, не проходя через всю цепочку.

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

Это, например, будет представление кнопки.

function Button(name) {
  return { buttonLabel: name, textColor: 'black' };
}

'John Smith' -> { buttonLabel: 'John Smith', textColor: 'black' }

Используя этот формат, мы можем создать длинную цепочку компонуемых абстракций. Вот так

function Button(name) {
  return { buttonLabel: name, textColor: 'black' };
}

function UsernameButton(user) {
  return {
    backgroundColor: 'blue',
    childContent: [
      Button(user.name)
    ]
  }
}

function UserList(users){
  return users.map(eachUser => {
    button: UsernameButton(eachUser.name),
    listStyle: 'ordered'
  })
}

function App(appUsers) {
  return {
    pageTheme: redTheme,
    userList: UserList(appUsers)
  }
}

Этот пример состоит из четырех слоев абстракции, составленных вместе.

Приложение → Список пользователей → Кнопка имени пользователя → Кнопка

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

Данные темы находятся в первой абстракции (приложение). Это должно быть реализовано в последней абстракции (кнопка).

Раздражающим способом было бы передать данные темы, от приложения к кнопке, изменяя каждую абстракцию по пути.

Приложение передает данные темы в UserList UserList передает их в UserButton UserButton передает их в кнопку

Становится очевидным, что в больших библиотеках с сотнями слоев абстракции это огромная боль.

Возможное решение состоит в том, чтобы передать эффект через определенный обработчик эффекта и позволить ему продолжить, когда это необходимо.

function PageThemeRequest() {
  return THEME_EFFECT
}

function App(appUsers) {
  const themeHandler = raise new PageThemeRequest();
  return {
    pageTheme: themeHandler,
    userList: UserList(appUsers)
  }
}



function Button(name) {
  try {
    return { buttonLabel: name, textColor: 'black' };
  }
}