4 ms·
Ok, this is probably me being ignorant, but can't you do stuff like this to get macros in Python: import os, subprocess def macro(string, filename="~/
by JesseAldridge 18y ago
Ok, this is probably me being ignorant, but can't you do stuff like this to get macros in Python:
import os, subprocess
def macro(string, filename="~/macro.py"):
program_name = os.path.expanduser(filename)
out = open(program_name, 'w')
out.write(string)
out.close()
command = ["python"]
command.append(program_name)
subprocess.Popen(command)
macro("print 'Hello macro!'")
It seems like with a bit of ingenuity you could achieve any level of abstraction using a technique like that.
- logjam 18y agoShow us some new control structures using your, um, scheme.
- JesseAldridge 18y agoI'm not exactly sure what you mean by "control structures", but how about this: def switch(case, actions): macro(actions[case]) switch(2, ["print 'foo'", "print 'bar'", "print 'baz'"])
- silentbicycle 18y agoFor one example, what about if the arguments in the switch list had side effects? >>> def boo(x): ... print "BOO" ... return x + 3 >>> [1, 2, 3, boo(4) + 0, 5][1] will result in BOO 2 . Each element of the list would be evaluated down to a result value, then the appropriate one is chosen. I'm pretty sure you would need to wrap every item in the switch list in a function just to delay the evaluation. This is just as true for if a different Python interpreter were executing generated code. Adding control structures means extending the core language, such as being able to add a new exception-catching construct that could return evaluation to where it was thrown if, after passing through the exception handler, the preceding test no longer holds true. Or a command that backs up the surrounding for loop by one step. For example. What you wrote above would be useful for some things (generating boilerplate code, certainly), but it doesn't alter the underlying language.
- BrandonM 18y agoThat's why each of the arguments is supposed to be a string of Python code, instead of raw Python code. That's also why the Python "solution" is much uglier than Lisp macros.
- andreyf 18y agoWhy not just eval?
- JesseAldridge 18y ago>>> eval("print 'Hello macro!'") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 print 'Hello macro!' ^ SyntaxError: invalid syntax I guess you can't do prints in an eval?
- dill_day 18y agoeval(compile("print 'Hello macro!'",'macro','exec'))
- Hexstream 18y agoNice Lisp macro features your naive scheme lacks: - Lisp macros are expanded implicitly at compile-time so you don't have a big mess of temporary files; - Lisp macro calls look just like the built-in operators, unlike your proposed "python macros" where all your macro invocations are a string - For all but the most trivial cases your string-based scheme will force you to use concatenation and it will really get ugly really fast. In contrast, with Lisp it's much easier to represent code as data. For example, (+ 1 2) is the code to add 1 and 2 while '(+ 1 2) is a list representing the code to add 1 and 2 and you can then interpolate that easily in the generated code - And your example is really awesomely constrained, it works but it also doesn't really help with anything. With Lisp, the macro facility scales from trivial problems where the macro code fits in 4 lines to very complex ones where the macro code spans 4 files.
- gaius 18y agoThis is one reason I like Tcl, it's not far off Lisp in the sense that it's a "programmable programming language" and I can get away with using it at work because they think it's just fancy shell-script :-) For an example see http://wiki.tcl.tk/917 http://wiki.tcl.tk/917
- silentbicycle 18y agoAt least part of the significance of Lisp macros is that they let you use the full facilities of the language at compile time. Your method doesn't really do anything but run another Python instance at runtime (assuming there is one available) on a generated file of Python code. You could use eval(str) for that, by the way. You couldn't use this to, say, allow Python's lambda to take multiple lines, or generate boilerplate code at compile time.
- dmoney 18y agoAnother way of getting poor man's macros is using lambdas: function evaluate(arg) { return (arg instanceof Function) ? arg() : arg; } function sweach(tests, cases){ var ret = []; for each (t in tests){ ret.push(evaluate(cases[t])); } return ret; } var twos = 0; sweach([0, 1, 2, 1, 2, 1, 2], {2:function(){twos++;}}); // twos==3 It might get a bit messy though.