10 ms·
Robpike/Lisp: Toy Lisp 1.5 interpreter in Go
- mseepgood 6y agoHe also implemented an APL-like interpreter in Go: https://github.com/robpike/ivy https://github.com/robpike/ivy
- smabie 6y agoPersonally, I find that one much more interesting. Before I was familiar with array languages, I hoped that functional programming and lisp would become the new zeitgeist of software development. Now, I think that array languages have the most promise in revolutionizing the discipline. While it probably wont happen, I wouldn't complain if array languages became the defacto norm for most new applications.
- G4BB3R 6y agoIs it a deeper rabbit hole than FP? Could you give some links or good array language names?
- 4ad 6y agoAPL, K, J. Game of life in APL: https://www.youtube.com/watch?v=a9xAKttWgP4 https://www.youtube.com/watch?v=a9xAKttWgP4
- zerr 6y agoHow about some CRUD app examples? :)
- grovehaw 6y agoDyalog is an APL vendor, they also offer a non-commercial license and high quality documentation. They have a case study of a school management system that is a record keeping system [0]. [0] https://www.dyalog.com/case-studies/education.htm https://www.dyalog.com/case-studies/education.htm
- zerr 6y agoThanks! Btw, what would be the open source alternative (of APL) that is popular and used in production?
- yumaikas 6y agoProbably J, if I had to guess. I'm unaware of how much production use it has.
- jetti 6y agoThere is a GNU implementation of APL (https://www.gnu.org/software/apl/ https://www.gnu.org/software/apl/). Not sure if it is used in commercial applications or not. I would imagine that if you are doing commercial work with APL you are going to be paying for Dyalog.
- zerr 6y ago> you are going to be paying for Dyalog Not really. As I see APL is ISO standardized and there are many implementations.
- jetti 6y agoThere are many implementations but not as many that are active (here is a brief list https://en.wikipedia.org/wiki/APL_(programming_language)#Modern_implementations https://en.wikipedia.org/wiki/APL_(programming_language)#Mod...). Dyalog provides more than just a interpreter/compiler but an entire development environment.
- tosh 6y agorabbit hole k: https://web.archive.org/web/20131006150020/http://www.kuro5hin.org/story/2002/11/14/22741/791 https://web.archive.org/web/20131006150020/http://www.kuro5h... https://queue.acm.org/detail.cfm?id=1531242 https://queue.acm.org/detail.cfm?id=1531242 https://shakti.com/ https://shakti.com/
- mseepgood 6y agoWolfram Language / Mathematica, MATLAB, R
- smabie 6y agoNo, not really, None of these are what I'm talking about when referring to "array languages". I'm talking about APL and its descendants, j, kdb+/q, k, etc.
- dnautics 6y agoIf you want something in between, i'd suggest Julia, which has taken a lot of array programming concepts and ported them into a functional language, so you can get the ideas without going so far down the rabbit hole that everything is an array. The problem though might be that those ideas (like Julia's broadcast) are so seamlessly integrated into it's functional paradigm that you won't "really" know which parts are parts where you've been tricked into doing array programming.
- the_optimist 6y agojsoftware.com - GPL license - Extremely well-documented - General purpose - Runs on any platform - 64-bit - C-like performance for many operators - Interpreted, interactive development environment - Package manager - Near-zero boilerplate https://www.jsoftware.com/books/pdf/easyj.pdf https://www.jsoftware.com/books/pdf/easyj.pdf "Array language" describes a pretty generic syntax format wherein an operator acts on multiple inputs. Functional programming is a style that nests nicely with arrange languages. If you know "R," just think of lapply. It's like lapply everywhere, but without the lapply syntax. Every function is vectorized. People who aren't formally trained on loops or object-oriented programming tend to pick this up more easily. That said, you can do OOP and loops in J if you want to.
- MichaelMoser123 6y agowhat would you add to awk so that it would make a big difference?
- yiyus 6y agoI would not call awk an array language. Arrays are essential in awk, but it lacks array operations. For example, in an array language, you add two arrays a and b, element by element, with a+b, while in awk you need a loop. Moreover, you do not have direct map and reduce operations, and again you need loops. As a fan of both awk and array languages, I think that an nsl-awk would be a really interesting project.
- jnxx 6y agoI think a lot of these ideas have gone into Python's Numpy, for example. But I believe these are useful for the domain of signal processing and numerical computation, and not that well suited for general problems. (You might be interested in Racket which is a Scheme relative that has very good support for both domains.)
- ashtonkem 6y agoI always get the feeling that a lot of languages would be well served by having an APL or prolog implementation added as a library or macro; this would let teams leverage these tools down in the core of their application without having to compromise on how they create APIs. Closest I’ve seen to this was core.logic in the Clojure community, but it appears to be dead.
- trevyn 6y agoRust is working on chalk, which claims to be “Prolog-ish”: https://github.com/rust-lang/chalk/blob/master/README.md https://github.com/rust-lang/chalk/blob/master/README.md It’s being used in rust-analyzer (the leading language server) today, and is likely to be used in the compiler in the future. Not really intended to be general-purpose, but an interesting datapoint. And could evolve to be more general, knowing the Rust community.
- dunefox 6y agoSomething like this? http://shenlanguage.org/ http://shenlanguage.org/ The idea seems pretty damn intriguing.
- fulafel 6y agoDatalog is very much alive in Clojure, there are many implementations and you pick between in-memory and disk based ones.
- fishbacon 6y agoThe presentation he gave on it is lovely. https://www.youtube.com/watch?v=PXoG0WX0r_E https://www.youtube.com/watch?v=PXoG0WX0r_E
- chewxy 6y agoI hope one day when I grow old I get to engage in fun pasttimes like what Rob did.
- melling 6y agoBalance is important too. He won a Silver Medal for archery in the Olympics.
- dchest 6y ago...using Lisp's parentheses as a bow. (Hint: look up 1980 Olympics)
- newswasboring 6y agoI hated you for doing this and myself more for actually falling down that rabbit hole. The explanation is here[1]. tldr: he is canadian and 1980 summer Olympics was boycotted by both canada and america. [1] https://wiki.c2.com/?RobPike https://wiki.c2.com/?RobPike
- kazinator 6y agoMy only memory is of the closing ceremony: a fleeting image of a bear mascot being carried across the stadium by balloons. I watched that on TV as a nine-year-old boy in Slovakia..
- libria 6y agoI was impressed at first, but then I saw the David Letterman bit. An olympic medal is far more believable than a talk show host interested in a computer scientist.
- deleted 6y ago[deleted]
- kgwxd 6y agoA few weeks ago, I went through "Make a Lisp" [1] using C#. It only took a few days to get to a pretty useful implementation. I "cheated" quite a bit using the existing C# implementation from the repo as a reference, but my end result looks pretty different. Learned a TON. Highly recommended. [1] https://github.com/kanaka/mal https://github.com/kanaka/mal
- alrs 6y agoGOMODULE111, who needs it? :)
- kitd 6y agoIt is a pedagogical experiment to see just how well the interpreter (actually EVALQOUTE/APPLY) defined on page 13 of that book really works. The answer is: perfectly, of course. Well timed! I've just been trying this out myself after reading Maxwell's Equations of Software [1]. It's fun realising that the "base" functions you're doing in Go can be reduced to even more fundamental forms using the Lisp you're implementing. [1] http://www.righto.com/2008/07/maxwells-equations-of-software-examined.html http://www.righto.com/2008/07/maxwells-equations-of-software...
- kazinator 6y agoWell-timed for you, but Pike could have benefited from doing this experimentation forty years earlier. Who knows where he would be now?
- nsajko 6y agoIt's not like this is Pike's first contact with Lisp, he wrote an APL interpreter in it: https://www.youtube.com/watch?v=PXoG0WX0r_E https://www.youtube.com/watch?v=PXoG0WX0r_E Note, that's not the topic of the talk, it's just mentioned in it.
- rsc 6y agoI spoke to Rob shortly after he wrote this code (a few weeks ago). He said he had been wanting to do some coding over the weekend and pulled his copy of the LISP 1.5 Programmer's Manual - which he bought long ago, in grad school I think he said - off his shelf, and this code was the result. He also talked about how reading that book back when he bought it was incredibly eye-opening at the time and had such a significant influence on almost everything he's done in his career. When I look through what Rob has done, I see a few patterns clearly traced to LISP, including a strong emphasis on recursive approaches and simplification by relying on functional (immutable) semantics. Look at the bitmap layers work, Newsqueak, Sawzall. There is of course also a heavy dose of pragmatism, which seems to be what you are criticizing. Your question is therefore answerable: since he was in fact exposed to all that material forty years ago, he would be exactly where he ended up. Not that there's much type theory in that book, but I'll note that Rob has also worked with type theorists in the past as well, notably Luca Cardelli on Squeak. And he was the one who suggested we approach Phil Wadler to help us work on the semantics of generics in Go. So again the ignorance about programming languages that your comment implies simply isn't accurate. This pattern of assuming what other people know about is endemic on HN (and the internet more broadly, but especially so here), and it is harmful to productive discussion.
- wejick 6y agoHe wrote unit test +1000
- jeffrallen 6y agoWell actually, he should have just done it in Rust...
- mseepgood 6y agoHe mentions "pedagogical" and "teaching tool". Who is he teaching? I would love to be his student.
- jascii 6y agoI read that more in a context of "teaching oneself". However, I think he's at google atm: http://herpolhode.com/rob/ http://herpolhode.com/rob/
- klodolph 6y agoInteresting: https://github.com/robpike/lisp/blob/master/lisp1_5/parse.go#L24 https://github.com/robpike/lisp/blob/master/lisp1_5/parse.go... // Expr represents an arbitrary expression. type Expr struct { // An Expr is either an atom, with atom set, or a list, with car and cdr set. // Car and cdr can be nil (empty) even if atom is nil. car *Expr atom *token cdr *Expr } Instead of using interface types for expressions, there is a simple expression structure type with fields that may or may not be set depending on what type of value it is. I probably never would have done it that way, I would probably use an interface type instead. This way actually saves space in cons objects… in the above version, a cons is 24 bytes, and below it would be 32: type Expr interface { } type Cons struct { car, cdr Expr } Not efficient compared to modern Lisp interpretations, but an interesting choice.
- morelisp 6y agoSee also: Nearly every time I see someone trying to use `oneof` in protobuf...
- kodablah 6y ago> I probably never would have done it that way, I would probably use an interface type instead I think when you're all in the same package and accessing unexported fields you know about, this is much clearer than an interface. I often add unexported mutually exclusive fields that local code has advanced knowledge about to prevent unnecessary over-abstraction.
- kccqzy 6y agoAnd yeah, and then a new team member doesn't know certain fields are mutually exclusive, and neither does the compiler because of the lack of sum types.
- brandonbloom 6y agoI find this a fascinating topic, so forgive me for this reply which has turned in to a mini blog post of sorts... Go embraces the common insight that you can encode a sum as a dependent product. That is, here, you have a discriminated union of atoms and cons cells, but the discriminant is not a specific tag value, as it would be in Haskell or ML or similar, but rather the nil/non-nil state of these fields. Of course, there is no static enforcement of this property, as there would be in contemporary languages with sum types, including Rust's enums. The quintessential example of this in Go is result/error multi-value returns. The result is valid if the error is nil. If your goal is to save bits (which is rarely the case for Go programs), as you note, avoiding an explicit discriminant (such as an interface pointer) means that you're encoding the discriminant's information in to less space, utilizing the specific domain knowledge of mutual exclusion. Stepping further from Go, this same principle is at play in Clojure, which favors open maps for information. In Clojure, multimethods can dispatch on arbitrary functions of values. This means that any field can easily be used as a discriminant. Now, saving bytes is certainly not the purpose of this in Clojure, but it's interesting to think about. Forcing dispatch in to a privileged discriminant tag means that data needs to be transformed/parsed in order to re-arrange information in to the tag for dispatch. Alexis King wrote an excellent article about this sort of transformation: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... As excellent as that article is, I think the truth lies in some balance. Both parsing and validation are useful techniques. Contemporary typed languages tend to push you down a path towards parsing instead of validation, which is probably the way the pendulum should swing for many use cases. However, there is one language that stands in stark contrast: TypeScript. Because it needs to support existing JavaScript idioms, it has grown a type system powerful enough to enable reasonable type safety with a validation based approach. Tools like control-flow sensitive type checking, literal types, and type-guards make that possible. You can use an arbitrary key in some JS object with a literal type value as a discriminant and the type system will do the right thing with union types. There is one other area where Go is interesting here: zero values. Go zero-initializes all freshly allocated memory and encourages a style that embraces that. These freshly allocated objects are called "zero values" and often they are useful right out of the gate. You're encouraged to make code no-op safely with zero values, or apply some sane defaults. This makes an important distinction between `EnableFoo bool` and `DisableFoo bool`. Looping zero times is a perfectly valid thing to do. Silently skipping nil values is a perfectly valid thing to do in some cases. Etc. Clojure is similar with nil punning. While not without it's downsides, this is an interesting point in the design space that seems totally ignored by theoreticians and totally under-appreciated by working programmers, even those who work with Go and Clojure regularly. I'd really like to see that change, as I've found my programs have generally improved as I make judicious use of these techniques.
- moron4hire 6y agoI read the title as "Robopike/Lisp" at first and suddenly imagined this was some operating system slashfic set in Paul Verhoven film universe.