Just played with the idea of allowing user-defined operators via macros...
This is working code.
If we continue this idea, right/left associativity and distributivity priority must be implemented (options of the &operator
macro).
module MacroOperators
union Option = {
Some = { value }
None
}
# monadic bind
&operator (">>=", |monad, func| -> match {
when monad is None() then monad
otherwise func(monad: value())
})
# inverse function application, similar to unix pipe
# (since binary operation are right associative, we must check the types)
&operator (">", |value, func| -> match {
when isClosure(value) then value: andThen(func)
otherwise func: invoke(value)
})
# function application operator
&operator ("$", |func, value| -> func: invoke(value))
&operator ("<<", |x| -> 2 * x)
function f = |x| -> x + 1
function g = |x| -> 2 * x
function div = |x| -> match {
when (x % 2) == 0 then Some(x / 2)
otherwise None()
}
function main = |args| {
println(Some(3) &>>= ^div) # None
println(Some(4) &>>= ^div) # Some(2)
println(None() &>>= ^div) # None
println(3 &> ^f &> ^g) # g(f(3)) -> 8
println(^g &$ ^f &$ 3) # g(f(3)) -> 8
println($<< 4) # -> 8
}