Легковесный лисп для правил принятия решений
(Лиспекс)
( скобки как пунктуация, рекурсия как рифма )
Не прячьте сложную логику возврата или проверки прав внутри кода приложения. Лиспекс позволяет писать правила как небольшие независимые программы и получать ответы в виде прозрачных данных. Запускайте их в браузере, в проектах Node.js или на локальном компьютере.
Вот всё правило возврата, целиком.
Запрос приходит в виде списка именованных полей. Любой ответ, включая отказ, возвращается чистым списком, который можно напечатать, сохранить и сравнить с любым другим ответом.
(define (review request)
(let ((days (cdr (assq 'days request)))
(opened (cdr (assq 'opened request)))
(cents (cdr (assq 'cents request))))
(cond ((>= days 15) '(deny outside-window))
(opened '(deny opened-item))
((> cents 50000) '(escalate manual-review))
(else '(allow within-policy)))))
(map review
'(((days . 14) (opened . #f) (cents . 12900))
((days . 14) (opened . #f) (cents . 82000))
((days . 15) (opened . #f) (cents . 12900))))
; => ((allow within-policy) (escalate manual-review) (deny outside-window))Четыре строгих ограничения, которые делают Лиспекс предсказуемым
У каждой формы if обязательна ветвь else. Встроенные процедуры образуют закрытый список из 205 имён. Процедуры высшего порядка, такие как map и filter, принимают ровно один список. Никто не может объявлять макросы, поэтому ни один файл не изменит смысл формы незаметно.
Ценность этих ограничений очевидна. Правило, открытое через год, читается именно так, как написано, а если программа завершается со сбоем, она падает всегда одинаково.
Посмотреть весь синтаксис на одной страницеТри места выполнения, одна эталонная реализация.
Песочница работает внутри вашего браузера, и ваш код из него не уходит. Пакет npm запускает Лиспекс внутри проекта Node.js. Загружаемая программа выполняет его на вашем компьютере и содержит самый широкий набор команд.
Во всех трёх средах работает одна и та же эталонная реализация, написанная на Rust. Браузер и npm добираются до неё через WebAssembly, а загружаемая программа выполняет её напрямую. Различаются набор команд и лимиты памяти или рекурсии, и каждая среда чётко сообщает свои ограничения.
Передайте решение, которое получатель проверит самостоятельно.
Загружаемая программа может подписать запись одного запуска. Выполненное правило, входные данные и итоговый ответ запечатываются в единую подписанную запись.
Получателю не нужно верить вашим заявлениям на слово. Он берёт свою копию правила и входные данные, запускает всё заново на своей машине и проверяет, совпадает ли сегодняшний ответ с подписанной записью. Ключ проверки выбирается получателем, а не берётся из присланной записи.
Успешная проверка служит свидетельством прошлого выполнения, а не автоматическим разрешением. Выполнять ли возврат на самом деле, решает ваше приложение.
В пикселях этой картинки лежит целое правило.

(let ((input '((days . 14) (opened . #f))))
(let ((days (cdr (car input)))
(opened (cdr (car (cdr input)))))
(if (< days 15)
(if opened "deny" "allow")
"deny")))Пиксели содержат точный исходный код, приведённый ниже, байт в байт. Вы можете восстановить код на своём компьютере или прямо в песочнице. Формат задан с точностью до байта, поэтому снимки экрана или изменённые копии не откроются.
Картинка лишь точно переносит байты кода. Это не подпись и не гарантия доверия.