Я работаю над синтаксисом для рэкета, используя каналы, похожие на unix, примерно так:
> ("FOO" > string-replace "O" "E" > string-append "x" > string-downcase)
"feex"
Вот решение грубой силы, которое поддерживает процедуры с 2, 1 и 0 (дополнительными) аргументами:
(require (prefix-in racket/base/ racket/base) syntax/parse/define)
(define-syntax-parser #%app
[(_ data (~literal >) proc a b (~literal >) rest ...) #'(#%app (proc data a b) > rest ...)]
[(_ data (~literal >) proc a (~literal >) rest ...) #'(#%app (proc data a) > rest ...)]
[(_ data (~literal >) proc (~literal >) rest ...) #'(#%app (proc data) > rest ...)]
[(_ data (~literal >) proc rest ...) #'(#%app proc data rest ...)]
[(_ rest ...) #'(racket/base/#%app rest ...)])
Проблема заключается в том, чтобы найти следующий канал, потому что шаблон синтаксиса не позволяет использовать несколько шаблонов .... Макрос должен знать, где следующая труба, чтобы закрыть форму для первой. Если нет способа создавать объекты частичного синтаксиса с непревзойденными скобками?
Я могу вложить многоточие, но тогда мне придется использовать дополнительные скобки:
(define-syntax-parser #%app
[(_ data (~literal >) (proc params ...) > rest ...) #'(#%app (proc data params ...) > rest ...)]
[(_ data (~literal >) proc rest ...) #'(#%app proc data rest ...)]
[(_ rest ...) #'(racket/base/#%app rest ...)])
> ("FOO" > (string-replace "O" "E") > (string-append "x") > string-downcase)
"feex"
Есть ли способ сделать это без дополнительных скобок?
Я знаю о макросах потоков clojure, но им трудно следовать, если вам нужно их вложить.
РЕДАКТИРОВАТЬ: решение этой проблемы теперь доступно в виде пакета racket и на github