7 ms·
Here's an example of why arc/lisp are great: (mac awhen (expr . body) `(let it ,expr (if it (do ,@body)))) This basically add a new syntax to the la
by d0m 11y ago
Here's an example of why arc/lisp are great:
(mac awhen (expr . body)
`(let it ,expr (if it (do ,@body))))
This basically add a new syntax to the language. How often did you do in python:
some_value = my_function()
if some_value:
call_something_with(some_value)
With the small macro defined earlier, we can do:
(awhen (my_function)
(call_something_with it))
Basically, binding (my_function) to the variable named "it".
It's amazing to be able to add new syntax/features to the language without having to wait for a new version. Imagine if you could add any features you want to javascript or python without having to wait 5 years for the spec to be approved and implemented..
It's possible because the code is written in the same data structure that you use to manipulate normal values. I.e.:
(let x 1
(prn x))
Is the code of the program but also simply a list of 4 elements. And since the code itself is a data structure that you can manipulate with normal functions, there's something called "Macro" in Lisp (not to confuse with C++ macros), which essentially are functions that receive code and returns code, instead of receiving values and returning values.
So: (some_macro (prn 1)). some_macro would receive a list of two elements (prn and 1) and could do some operation to it and returns some new code.. such as (prn 2), which will then get evaluated to print 2. Whereas (some_fn (prn 1)) would evaluate (prn 1) (which returns nil), and pass nil to some_fn.
That's why it's so hard to impress a lisp programmer with any other languages because if a feature doesn't exist, they can add it with a macro. I.e. Actors or OO, or whatever really.
- laarc 11y agoThis is way better than what I wrote. Thanks! Here's an example in concrete terms of the power of this technique: https://github.com/laarc/monki/blob/master/sudoarc.l https://github.com/laarc/monki/blob/master/sudoarc.l That's a file which adds many of Arc's constructs to Lumen: printing (pr, prn), list building (accum), structure (w/uniq, aif, awhen), etc. To put it another way: At the top of the file, the language available to you is Lumen. But at the bottom of the file, the language available to you resembles Arc. (It doesn't redefine anything from Lumen, though, so it's not a destructive change.) That must sound pretty dubious. It probably sounds like it's useful only for lone-wolf programmers rather than a team. If you give people the power to reshape the language, wouldn't it wreak havoc in a team setting? The answer turns out to be no, and it's surprising enough to write an essay about. Having macros available to your team ends up making your team more powerful, not less. It's simply a technique to generate patterns of code. When coupled with a good debugger, there's no mystery when things break. When an error happens, you get a debug breakpoint right where the error occurred. It makes no difference whether the error occurs during a macro expansion or during a function call, because macros are simply functions that answer "What should happen next?" It's like having a function that takes code as input and returns code as output, which is then executed. Except in Javascript, you'd have to do that by representing code as strings, which get passed to eval. In Lisp, code is a list. Meaning you can walk through it and see "This is an if statement. This is a function call." Etc. It's true that there are ways to abuse macros which make them difficult to understand or debug. But this is rare. The most common case is a short, simple transformation like d0m showed: "here is a pattern; please generate it."
- jdc 11y agoThat may not be the best example of macros since you can do the same thing in Python: def awhen(func, callback): val = func() if val: callback(val)
- voltagex_ 11y agoThere's probably also a way to write a decorator that does the same thing.
- d0m 11y agoBy the way, I love Python and use it every day, so I'm not trying to get into a language war. The difference between using a decorator and a lisp macro is that using a decorator is "using the syntax of the language to solve your problem", while a macro is "adding a new syntax". I do think there are way in Python (or in C++) to use meta-programming to tweak the language but it always feel very hacky. I.e. I'd hate to jump into a python code-base that isn't standard, such as using @awhen decorator instead of a normal if ;-) What about you? But in Lisp, there's no difference in the syntax.. and adding missing features to the language instead of repeating the same pattern is the standard way to code.
- mikaelj 11y agoIf we were to name your operator "aif" instead (since there is no "when" in Python), and compare if and aif: ## if val = func() if val: # standard form code(val) # of if ## aif aif(func, code) # not obvious that it does the same thing # and limits you to using a function defined # elsewhere, or Python's crippled one-line lambda. Whereas in Lisp, you'd do: ;; regular when (let (val (func)) (when val ; standard form (func val))) ; of when ;; awhen (awhen (func) ; standard form of (func it) ; when, with added bound value ; possibly other ; code goes here ) Do you see how the two forms of Python look very different, and the two forms of Lisp look the same? If you don't like magic, you could invent an awhen that took an extra parameter that designates the name to bind the result to, e.g. (awhen val test). So. Yes - you can achieve the same thing, as in any programming language that is Turing complete. No - you cannot get the same syntax. And syntax affects readability and familiarity.
- millstone 11y agoI don't know much about LISP. What you showed looks nice and useful, but I would not consider it new syntax. Is it possible to use this technique to introduce, say, infix arithmetic operators, or ObjC's dot syntax? Or can you just trade one S-expression for another?
- laarc 11y agoObjC's dot syntax? Sure. That's easy in Lumen: https://github.com/sctb/lumen/commit/6410c8cc2de66d1976515bdd71ab9b65c12cbf10#diff-910c7ff4864f437a8c67427b7b055657R70 https://github.com/sctb/lumen/commit/6410c8cc2de66d1976515bd... Is it possible to use this technique to introduce, say, infix arithmetic operators? Yep! I wrote a macro to swap any instance of `x with the previous expression. Meaning, it allows you to write: (foo `= (x `+ y)) rather than (= foo (+ x y)) The reason it was so easy to do this is because `foo is shorthand for (quasiquote foo). So the macro simply steps through a body of code, looks for any instance of quasiquote followed by an atom, and then swaps it with the previous expression. But more generally, it's easy to write a macro to do whatever you want. If you really want infix expressions all of the time, I could imagine writing a macro which matches the pattern (... + ... + ...) and replaces it with (+ ... ... ...) That's made-up notation, but the idea is just "look for some set of symbols, like + or /, which occur within a list in between all of the other elements, and then move the symbol to the front of the list." The power is available to you, but whether you choose to use it is a separate question. Prefix notation tends to be a win for everything except math. And even for math, it's usually a matter of code formatting. Rather than (- (* 2 (/ (+ x y) (+ a b c))) 1) try (- (* 2 (/ (+ x y) (+ a b c))) 1) or (let u (+ x y) (/= u (+ a b c)) (*= u 2) (-- u)) Once Laarc has support for indentation-as-parens, it'd look like: let u (+ x y) /= u (+ a b c) *= u 2 -- u which is rather pretty, and has no ambiguity. One of pg's essays on Arc mentioned this feature, and it seems like a good idea, so I hope to pursue it.
- akkartik 11y ago0. Is Laarc an arc variant you're working on? I don't see it on the github page. 1. You might be interested in how my arc-inspired language did indent-sensitivity and infix: http://akkartik.name/post/wart http://akkartik.name/post/wart. For example, here's bresenham's line-drawing algorithm in wart: https://gist.github.com/akkartik/4320819 https://gist.github.com/akkartik/4320819. There are more code samples at http://rosettacode.org/wiki/Category:Wart http://rosettacode.org/wiki/Category:Wart. 2. Do you have a username on arclanguage.org? Perhaps we've met!