-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quotation Monad #374
base: master
Are you sure you want to change the base?
Quotation Monad #374
Conversation
25e968d
to
d3f2e08
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I experimented around it a lot and I think I understand why the current implementation looks like this. I think this is one of the best we can have for a "quotation monad", but here is my two cents.
Here, we can't make use of the created Expr<'a>
value for anything but executing it, because it contains SpliceExpression
s which make the expression illegal and have to be removed (by eval). This makes me wondering how this "monad" can be useful, since I suppose most people would want to use the computation expression to create a valid Expr<'a>
value that can be consumed by other libraries (without actually running it), but it isn't possible (this is not a problem in MetaOCaml, since it's all about running the code and there is no API to directly manipulate the AST).
Since a F# code can have side effects anywhere, we can't easily define m >>= f
without breaking the semantics. We have to syntactically inspect the f
and replace every occurrence of the argument with x
(this is not much of a problem in Template Haskell since it uses IO monad so it can be done safely). Luckily we can do this for the computation expression binding let! x = m in body
by using [<ReflectedDefinition>]
since it is always a lambda abstraction, but this means generic >>=
operator and generic monad
builder are no more usable for the quotation monad.
So I think we have several options:
- Wrap the
Expr<'a>
type (inWrappedExpr<'a>
, for example) and make it a monad.- Then we define
val WrappedExpr.run : (Expr -> obj) -> WrappedExpr<'a> -> 'a
. - And
val WrappedExpr.toExpr : WrappedExpr<'a> -> Expr<'a>
. This requires the syntactical replacement described above.
- Then we define
- Create a specialized builder like
quotation { ... }
for the purpose described above.- We also have to implement the syntactical replacement for this.
- Then we may or may not make
Expr<'a>
a monad.
- Do both of them.
- Do neither and keep it as is.
Also, I found an interesting paper around this topic: https://www.semanticscholar.org/paper/On-Meta-Programming-and-Code-Generation-in-F-Larjani/ca1a48245a767992f4461fe2e66217e7a4fa83d6
32f5c4a
to
f2d1afd
Compare
5c69948
to
9ca5706
Compare
5b61ffc
to
ad56a34
Compare
5b07481
to
7f93d61
Compare
105ed2c
to
d80a4ad
Compare
f92d910
to
39638fb
Compare
9b34ece
to
b2f3c8c
Compare
484cff5
to
142c806
Compare
eef4e98
to
f2e49ba
Compare
This will implement #44
A quotation monad allow us to compose functions returning expressions.
At the end of the composition we get a single expression, internally containing markers where an evaluate function needs to run a sub-expression.
Since F# doesn't support the "eval" expression, we can't directly run this expressions in existing quotation evaluators, but we include an
Expr.run
function which takes any normal quotation evaluator and takes care of handling the internal marker. So, instead of doingevaluator expr
we doExpr.run evaluator expr
.