To wit, with some reader-macro magic, the initial impetus for the investigation, i.e. with-handlers
, can be dealt with, handily.
( infix
begin
× □ println □ error 'oops
[ with-handlers
× { □ exn:fail?
□ lambda ( _ × 'fail )
}
] @
)
( infix
begin
× □ println □ error 'oops
□₁ with-handlers
{ □ exn:fail?
□ lambda ( _ × 'fail )
}
)
(with-handlers ((exn:fail? (lambda _ 'fail)))
(println (error 'oops)))
There's quite a bit to unpack here.
Firstly, I changed the delimiter for argument separation to ×
and the delimiter for "operator promotion" to □
. This allows for clean translation between infix and normal Racket.
Second, I implemented some admittedly still-hacky reader macros for [ ... ]
which is read as "operator of ...
", and { ... }
which is read as "artefact of ...
".
The first is the same as when I was using quasiquote
/←
, in that it converts the contents of the square brackets into an operator expression. Basically, operator expressions end up at the head of a parenthesized expression. So, (a) [operator] (b)
means (operator a b)
.
The second is a shorthand for [ ... ] ()
--that is, apply the (unary) operator to nothing--which means that [ ... ]
is converted directly into ( ... )
in the eventual Racket.
You'll also notice a sneaky subscript in the second version of the infix, which basically means that the argument at index 1, coming from the subscript, will be at the head of the eventual Racket expression.
That is, □₁ operator (a × b)
means (operator b a)
.
I think this syntax has some nice properties, but it still feels brittle and in need of refinement.
Edit: the infix if
!
(define condition #false)
( infix
quote
× 'true [ if × condition ] 'else
)
;=> '(if condition 'true 'else)
( infix
quote
× 'true □₁ if (□ not condition × 'else)
)
;=> '(if (not condition) 'true 'else)