4 ms·
What’s with the macros? With Python you can build fully-featured DSLs without needing macros by simply overriding standard operators.
by heavenlyblue 8y ago
What’s with the macros? With Python you can build fully-featured DSLs without needing macros by simply overriding standard operators.
- 4thaccount 8y agoCan you give an example? I've never heard people talk about Python DSLs (just Lisp, Smalltalk, Rebol, and Forth usually).
- bollu 8y agoPolymage is a good example: http://mcl.csa.iisc.ac.in/polymage.html#examples http://mcl.csa.iisc.ac.in/polymage.html#examples Python embedded DSL for image processing / general matrix munging
- heavenlyblue 8y agoTheano: http://deeplearning.net/software/theano/library/index.html http://deeplearning.net/software/theano/library/index.html Define arbitrary execution graphs that compile to GPU or CPU.
- elcritch 8y agoTrue, you can but it results in a more limited DSL. This is mainly due to variable names needing to exist, be a valid object and chained used method invocations, which results in more awkward expressions (IMHO). Importantly macros enable compile time checking of a DSL rather than only runtime checking. That alone is very powerful. Take a SQL query in Python's SQLAlchemy: s = select([db.func.sum(users.c.id)]).\ .select_from( Users.outerjoin(Posts, Users.id == Posts.user_id)) where(and_( users.c.id == a1.c.user_id, users.c.id == a2.c.user_id, a1.c.email_address == 'jack@msn.com', a2.c.email_address == 'jack@yahoo.com' )).\ group_by(users.c.age) That's not bad, but compare it to a similar query in Elixir's Ecto: from account in App.Account, left_join: t0 in App.Transaction, on: t0.account_id == account.id and t0.user_id == ^current_user.id and t0.deleted == false and t0.type == "inflow", where: account.id == ^id and t1.user_id == t0.user_id, group_by: account.id, select: {account, {sum(t0.amount), sum(t1.amount)}}) The Elixir DSL allows a bit more flexibility when re-using language built-in's such as `and`/`or`, or undefined ones likes `sum` without needing the hacked names like `and_` or `db.func.sum` as in Python (or Java or others OOs). Generally the formatting is easier with macro based DSL's. P.S. The examples might not be exactly correct as I cobbled a couple of different ones together.
- heavenlyblue 8y agoI agree - the truth is that in Python it's easy to define DSLs only if they consist of expressions. It's not that easy to define an arbitrary language that allows you to write code that is close to something else completely (like Ecto vs SQL).
- virtualwhys 8y agoVery cool, does it compose? Some statically typed languages allow you to build up composable query snippets along the lines of (from a Scala DSL): val accountQ = for { (a, t) <- Account leftJoin Transaction (_.id is _.accountId) if a.id is ... && t.userId ... groupBy a.id } yield (a, t.id, t.amount.sum, ...) val invoiceQ = for { (a, transId, total) <- accountQ i <- Invoice join (_.transId is transId) } yield (a, i, total) Basically you can build up arbitrarily complex queries, all compile time checked -- it's really quite wonderful. Haskell has something similar with Esqueleto and C#/F# has LINQ to SQL. I love query DSLs, the more we move away from string-y SQL the better :)
- elcritch 8y agoEcto is pretty composeable [1]. Having a compile time checked SQL DSL was always one of the biggest features I wanted back in my Java days. 1: https://elixirschool.com/blog/ecto-query-composition/ https://elixirschool.com/blog/ecto-query-composition/