5 ms·
The only Arc application I know of is HN - can you show any other examples? As a non-Lisp programmer, can you sell the benefits of Arc to me?
by voltagex_ 11y ago
The only Arc application I know of is HN - can you show any other examples?
As a non-Lisp programmer, can you sell the benefits of Arc to me?
- laarc 11y agoMmhm! But not without confusing the hell out of everyone. But who cares? It's fun! I should start by clarifying that I'm not associated with Arc in any way. Everything that I show should be thought of as an eager derivative, at best. But for several months a colleague and I have been working on a derivative, which we've been calling laarc, which incorporates a few additions that make it a bit easier to write programs with. Here's a debugger similar to pdb.set_trace(), for example: http://i.imgur.com/WWKa4kw.png http://i.imgur.com/WWKa4kw.png Except when it breaks, it shows a list of the values of all the local variables. It's really useful for stepping through macro expansions and understanding them, because there's no longer any mystery when something breaks. Laarc isn't anywhere near ready yet, so it's too early to know whether it'll be useful generally, but the goal is to discover a way to make programming feel like a Tesla. So, what are the benefits? Well, here's an example of a real-world program. It's all pimply and has a few hacks in it, but on the other hand, you can get a gist of how it might look: https://github.com/laarc/monki/blob/master/main.l https://github.com/laarc/monki/blob/master/main.l Note that this was made two days ago, and I've been working very fast. So it's pretty rough. The program (monki) is essentially "cp for git", and while it works, it's not quite finished. Monki is Yet Another alternative to git subtrees / submodules; think of it like "cp for git". `monki clone voltagex/foo foo` would create a clone of that repo into the subdir "foo". But that subdir can be within one of your existing repositories. Here's the scenario it's useful for: https://github.com/tlbtlbtlb/startuptools https://github.com/tlbtlbtlb/startuptools This requires an installation of tlbcore (https://github.com/tlbtlbtlb/tlbcore https://github.com/tlbtlbtlb/tlbcore) symlinked to this directory. With monki, you'd just type `monki clone tlbtlbtlb/tlbcore tlbcore` from within a clone of startuptools, and then you'd commit the result. Monki takes care of pulling updates, so that whenever tlbcore changes, startuptools would also get the new stuff. But you can `monki clone` a specific commit instead, if you want to pin to a "known working" version. Anyway, that monki business was the result of trying to answer "What's a simple way where I can share code between all my repositories, pull in updates as I make them, and not have to worry too much?" And it was a good chance to exercise... Lumen! Confused yet? Ok, so Arc runs on Racket. So did Laarc. Then we had the good fortune to hear about Lumen: https://github.com/sctb/lumen https://github.com/sctb/lumen It's a Lisp that compiles to either Javascript or Lua. It literally exhibits the same behavior whether you're running via luajit, node, or the browser. Since LuaJIT's FFI is awesome, that makes it incredibly easy to interface with existing C libraries using Lumen. Just look how beautiful his postgres bindings are! https://github.com/sctb/motor/blob/master/pq.l https://github.com/sctb/motor/blob/master/pq.l That should catch anyone's attention -- the FFI is literally "copy paste some C declarations and you're done." I want to take that further. In Lumen, it's already possible to interface with node libraries or with lua libraries as-needed. What if we extend it to work with python and go libs as easily as it works with C? You might end up with a language that could do any given task very easily, because you'd simply use whatever library happens to be convenient regardless of whether it's a C lib, a node package, or a Ruby gem. So why have I been yakking about Lumen? Because it seems like it offers a bunch of interesting benefits as a runtime. I've been porting Laarc from Racket to it, slowly. It's extremely early, but here's an early version of the compiler: https://github.com/laarc/lumen-arc/blob/master/arc.l https://github.com/laarc/lumen-arc/blob/master/arc.l ... It's essentially ac.scm. I wanted to make it match as closely as possible, both because ac.scm is a good answer to "What's a good way to write a lisp compiler in a lisp language?" and because it's dangerous to assume you can write from scratch something that a smart team has been thinking about and working on for 13 years. Sooo... That's a whirlwind tour of stuff that's not even ready to tour. On the plus side, the plan is to get an in-browser repl running soon (arc can already run in the browser, so it's a matter of coaxing CodeMirror into submission). There's a server running Lumen over at http://arc.lol:9999 http://arc.lol:9999 which does absolutely nothing useful yet. The plan is to get a REPL up and to dub it "Arc dot tiefighter" since "lol" obviously looks like a tie fighter.
- laarc 11y agoBy the way, Lumen is awesome. They've been working on it for about three years, and it shows. You should totally check it out: https://github.com/sctb/lumen https://github.com/sctb/lumen Imagine a language whose startup time was faster than python / ruby / node, yet could be bent into whatever shape you wanted, thanks to macros. If you install luajit and run `make; make test`: $ time make test js: 525 passed, 0 failed lua: 525 passed, 0 failed real 0m0.153s user 0m0.119s sys 0m0.033s Lumen is wicked fast. Here's something cool: Our server is going to be running Lumen via luajit, yet it will serve a copy of itself compiled as javascript, which can execute in the browser. Same language, same syntax -- it just runs "in" two different languages at once! You'd think that it would be incredibly hard to do that well. Maybe it is, but they make it look easy.
- d0m 11y agoHere'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."