by pg on 10/12/19, 7:14 AM with 456 comments
by cousin_it on 10/12/19, 10:01 AM
1. What problem does this language solve? How can I make it precise?
2. How can I show it solves this problem? How can I make it precise?
3. Is there another solution? Do other languages solve this problem? How?
What are the advantages of my solution? of their solution?
What are the disadvantages of my solution? of their solution?
4. How can I show that my solution cannot be expressed in some other language?
That is, what is the unique property of my language which is lacking in
others which enables a solution?
5. What parts of my language are essential to that unique property?
Do read the whole post (http://lambda-the-ultimate.org/node/687#comment-18074), it has lots of elaboration on these questions.From a skim of the Bel materials, I couldn't answer these questions. Maybe PG or someone else can take a stab at the answer?
by rntz on 10/12/19, 8:40 AM
> Evaluates x. If its value comes from a pair, returns a list of that pair and either a or d depending on whether the value is stored in the car or cdr. Signals an error if the value of x doesn't come from a pair.
> For example, if x is (a b c), > > > (where (cdr x)) > ((a b c) d)
That is one zany form.
1. How is this implemented?
2. What is the use of this?
3. What does (where x) do if x is both the car of one pair and the cdr of another, eg. let a be 'foo, define x to be (join a 'bar), let y be (join 'baz a), and run (where a).
by dfranke on 10/12/19, 2:06 PM
When you say,
> But I also believe it will be possible to write efficient implementations based on Bel, by adding restrictions.
I'm having trouble picturing what such restrictions would look like. The difficulty here is that, although you speak of axioms, this is not really an axiomatic specification; it's an operational one, and you've provided primitives that permit a great deal of introspection into that operation. For example, you've defined closures as lists with a particular form, and from your definition of the basic operations on lists it follows that the programmer can introspect into them as such, even at runtime. You can't provide any implementation of closures more efficient than the one you've given without violating your spec, because doing so would change the result of calling car and cdr on closure objects. To change this would not be a mere matter of "adding restrictions"; it would be taking a sledgehammer to a substantial piece of your edifice and replacing it with something new. If closures were their own kind of object and had their own functions for introspection, then a restriction could be that those functions are unavailable at runtime and can be only be used from macros. But there's no sane way to restrict cdr.
A true axiomatic specification would deliberately leave such internals undefined. Closures aren't necessarily lists, they're just values that can be applied to other values and behave the same as any other closure that's equivalent up to alpha, beta, and eta conversion. Natural numbers aren't necessarily lists, they're just values that obey the Peano axioms. The axioms are silent on what happens if you try to take the cdr of one, so that's left to the implementation to pick something that can be implemented efficiently.
Another benefit of specifying things in this style is that you get much greater concision than any executable specification can possible give you, without any loss of rigor. Suppose you want to include matrix operations in your standard library. Instead of having to put an implementation of matrix inversion into your spec, you could just write that for all x,
(or
(not (is-square-matrix x))
(singular x)
(= (* x (inv x))
(id-matrix (dim x))))
Which presuming you've already specified the constituent functions is every bit as rigorous as giving an implementation. And although you can't automate turning this into something executable (you can straightforwardly specify a halting oracle this way), you can automate turning this into an executable fuzz test that generates
a bunch of random matrices and ensures that the specification holds.If you do stick with an operational spec, it would help to actually give a formal small-step semantics, because without a running implementation to try, some of the prose concerning the primitives and special forms leaves your intent unclear. I'm specifically puzzling over the `where` form, because you haven't explained what you mean by what pair a value comes from or why that pair or its location within it should be unique. What should
(where '#1(#1 . #1))
evaluate to? Without understanding this I don't really understand the macro system.by waterhouse on 10/12/19, 11:05 AM
> Some atoms evaluate to themselves. All characters and streams do, along with the symbols nil, t, o, and apply. All other symbols are variable names
The definitions of "ev" and "literal" establish that nil, t, o, and apply are in fact hardcoded and unchangeable. Did you consider having them be variables too, which just happen to be self-bound (or bound to distinctive objects)? nil is a bit of a special case because it's also the end of a list, and "(let nil 3 5)" implicitly ends with " . nil"; o might be an issue too (said Tom arguably); but apply and t seem like they could be plain variables.
P.S. It looks like you did in fact implement a full numerical tower—complex numbers, made of two signed rational numbers, each made of a sign and a nonnegative rational number, each made of two nonnegative integers, each of which is a list of zero or more t's. Nicely done.
by lewisjoe on 10/12/19, 8:21 AM
HN: How do you get an intuitionistic understanding of computation itself? While Turing Machines kind of make sense in the context of algorithms, can I really intuitively understand how lambda calculus is equivalent to Turing machines. Or how Lambda Calculus can solve algorithms? What resources helped understanding these concepts?
I'm currently following http://index-of.co.uk/Theory-of-Computation/Charles_Petzold-... and a bunch of other resources in the hope I'll "get" them eventually.
by alexkcd on 10/12/19, 10:33 PM
Specifically, I think that there exists a lisp with a set of axioms that split program execution into "compile-time" execution (facts known about the program that are invariant to input) and a second "runtime" execution pass (facts that depend on dynamic input).
For example, multiplying a 2d array that's defined to be MxN by an array that's defined to be NxO should yield a type that's known to be MxO (even if the values of the array are not yet known). Or if the first parameter is known to be an upper-triangular matrix, then we can optimize the multiplication operation by culling the multiplication AST at "compile-time". This compile-time optimized AST could then be lowered to machine code and executed by inputting "runtime" known facts.
I think that this is what's needed to create the most optimally efficient "compiled" language. Type systems in e.g. Haskell and Rust help with optimization when spitting out machine code, but they're often incomplete (e.g., we know more at compile time than what's often captured in the type system).
I've put "compilation" in quotes, because compilation here just means program execution with run-time invariant values in order to build an AST that can then be executed with run-time dependent values. Is anyone aware of a language that takes this approach?
by Zenst on 10/12/19, 1:41 PM
by SkyMarshal on 10/12/19, 6:18 PM
I really like this approach and have wondered in recent years what a programming language designed with this approach would look like. There are a few that come close, probably including Haskell and some of the more obscure functional languages and theorem prover languages. Will be really interesting to see a Lisp developed under this objective.
>But I also believe that it will be possible to write efficient implementations based on Bel, by adding restrictions. If you want a language with expressive power, clarity, and efficiency, it may work better to start with expressive power and clarity, and then add restrictions, than to approach from another direction.
I also think this notion of restrictions, or constraint-driven development (CDD), is an important concept. PG outlines two types of restrictions above. The first is simply choosing power and clarity over efficiency in the formative stages of the language and all the tradeoffs that go with that. The second is adding additional restrictions later once it's more clear how the language should be structured and should function, and then restricting some of that functionality in order to achieve efficiency.
Reminds of the essay "Out of the Tarpit" [1] and controlling complexity in software systems. I believe a constraints-based approach at the language level is one of the most effective ways of managing software complexity.
[1]:https://github.com/papers-we-love/papers-we-love/blob/master...
by TekMol on 10/12/19, 3:24 PM
Bel has four fundamental data types:
symbols, pairs, characters, and streams.
No numbers?Then a bit further down it says:
(+ 1 2) returns 3
Now suddenly there are numbers.What am I missing?
by brudgers on 10/12/19, 6:14 PM
The second thought is that lists smell like a type of stream. Successive calls to `next` on `rest` don't necessarily discern between lists and streams. The difference seems to be a compile time assertion that a list is a finite stream. Or in other words, a sufficiently long list is indistinguishable from an infinite stream (or generator).
I'm not sure you can have a lisp without lists, but they seem more like objects of type stream that are particularly useful when representing computer programs than a fundamental type. Whether there are really two fundamental types of sequences, depends on how platonic really really is.
All with the caveat, that I'm not smart enough to know if the halting problem makes a terminating type fundamental.
by p4bl0 on 10/12/19, 8:12 AM
[0] https://sep.yimg.com/ty/cdn/paulgraham/bellanguage.txt?t=157...
by stereolambda on 10/12/19, 6:29 PM
It's a little strange to have (id 'a) return nil. Also having car and cdr as historical holdouts when most of the naming seems to aim at an ahistorical stylistic.
Not very deep remarks, since I would need more time to digest.
by galfarragem on 10/12/19, 9:25 AM
Why Bel? What are the problems that Bel wants to solve? Is this an hobby project or something more serious?
by dangrossman on 10/12/19, 7:31 AM
by drcode on 10/12/19, 6:26 PM
> (distinct-sorted '(foo bar foo baz))
(bar baz foo)
This is a function that usually requires efficient hash tables and arrays to be performant, a hash table for detecting the duplicates, an array for efficient sorting. However, both the hash map and array could theoretically be "optimized away", since they are not exposed as part of the output.A language like Bel that does not have native hash maps or arrays and instead uses association lists would have to rely entirely on the compiler to find and perform these optimizations to be considered a usable tool.
by cperciva on 10/12/19, 7:35 AM
by PostOnce on 10/12/19, 8:33 AM
I hope I'll never stop coding passion projects myself.
John Carmack talked about this on Joe Rogan's show recently, about how he still codes and how Elon Musk would like to do more engineering but hasn't much time.
I wonder if Bill Gates ever codes anything anymore, I emailed to him ask once but never got a reply.
Tim Sweeney is a billionaire and still knee deep in code.
It's Saturday night here, and I'm going to go write some code. Unproductive, unprofitable, beautiful game engine code.
Hope all you other hackers get up to something interesting this weekend.
by arketyp on 10/12/19, 7:49 AM
by alfiedotwtf on 10/12/19, 9:38 AM
... fast forward a decade later and I'm reading books on functional and logical languages for work. After the first chapter of The Little Schemer, I was at first blown away with the content, but then sad after I realised I had put off reading it late in my life.
If you're reading this comment and thinking Lisp and what's the point? Take a deep dive. It you're still questioning why, I highly encourage you to read The Little Schemer (and then all the others in the series). Scheme, Lisp, and now Bel, are a super power... pg's article was spot on.
by excessive on 10/12/19, 9:52 PM
(2 '(a b c))
In addition to being data structures, I like to think of lists/arrays as functions which map integers to the contents. This nicely generalizes to hash tables / associative arrays, and then further to actual functions. If that's all reasonable, then ('(a b c) 2)
is the right order for application.However, maybe pg is just thinking of 2 as a shorthand for cadr or similar.
by shpx on 10/12/19, 8:07 AM
by pwpwp on 10/12/19, 7:07 PM
by mark_l_watson on 10/12/19, 2:27 PM
I assume that dedup and sort are separate functions.
by imdhmd on 10/12/19, 8:05 AM
by applecrazy on 10/12/19, 7:40 AM
How does one get started learning a Lisp variant (in terms of learning resources/guides), and why use Lisp over other languages?
by neya on 10/12/19, 8:25 AM
by ajju on 10/12/19, 8:01 AM
by repolfx on 10/12/19, 9:26 AM
For people like me who want static typing and a powerful type system to catch errors, does lisp have anything to offer? My understanding is that it predates decent type systems and lisps will always be genealogically much closer to Python than, say, a Haskell or even a Kotlin.
by jmccarthy on 10/12/19, 7:33 AM
by yellowapple on 10/14/19, 10:28 PM
The name "car" is McCarthy's. It's a reference to the architecture of
the first computer Lisp ran on. But though the name is a historical
accident, it works so well in practice that there's no reason to
change it.
While I understand the rationale here, would this not have been a good opportunity to encourage something a bit less vestigial than "car" and "cdr"? Say, "head" and "tail"? Or "left" and "right"? A lot of things come to mind when seeing a bunch of cars and cdrs and such everywhere in Lisp code, and "works so well in practice" ain't exactly one of them, IMO.by shrubble on 10/12/19, 2:36 PM
by daoudc on 10/12/19, 7:52 AM
by segmondy on 10/12/19, 12:59 PM
by eggsyntax on 10/20/19, 12:48 AM
This is a proper list:
(a b c)
and this is not:
(a b . c)
Could someone clarify how to interpret '(a b . c)'? How would it be represented in the non-abbreviated dot notation for pairs? It's not '(a . (b . (c . nil))' -- is it '((a . b) . c)'? The only Lisp I'm fluent in is Clojure, so I'm not used to the dot notation; otherwise this might be obvious.by kizer on 10/13/19, 2:45 AM
by orthoxerox on 10/12/19, 11:24 AM
by mrburton on 10/12/19, 8:06 AM
by vessenes on 10/12/19, 3:15 PM
Other than because you want to, do you have any sort of longer form apology for bel worked out that you want to share?
I ask because I’m curious how you’re thinking about play, work and legacy at this point in your career.
by ericd on 10/12/19, 9:43 PM
by quickthrower2 on 10/12/19, 10:40 AM
by gdubs on 10/13/19, 1:36 AM
by iamwil on 10/12/19, 4:03 PM
AT&T's Bell labs.
Belle is French for Beautiful
Bel is the 7th ASCII character and it use to ring an electro mechanical bell in computers, before they had speakers or sound cards.
B is the second letter after A, with which Arc, his first Lisp variant was named.
And both have three letters.
by QueensGambit on 10/12/19, 6:43 PM
by est31 on 10/12/19, 12:01 PM
by e12e on 10/13/19, 12:04 PM
Is it available as a Racket "language" or is it compatible with most/some lisps/schemes?
by juskrey on 10/12/19, 9:37 PM
by idm on 10/12/19, 10:01 PM
What is the license? My presumption is that you intentionally did not embed a license within either of the documents.
by fao_ on 10/12/19, 8:50 PM
I extremely like this format. I think clojure has something similar?
by jxub on 10/12/19, 2:56 PM
by machawinka on 10/13/19, 5:06 PM
by Liron on 10/12/19, 11:12 PM
by z3phyr on 10/16/19, 5:07 PM
by rayalez on 10/12/19, 8:23 AM
Really curious to see what this project will become.
by varjag on 10/13/19, 5:06 PM
by dfischer on 10/12/19, 7:36 AM
by SudoNhim on 10/12/19, 7:57 AM
by georgeEsb on 10/12/19, 5:30 PM
by machawinka on 10/12/19, 4:43 PM
by netcan on 10/12/19, 10:18 AM
I hope it was a pleasant return.
by codr7 on 10/12/19, 12:08 PM
Lisp is fine for what it is, one extreme of the spectrum and a child of its time; but far from the final answer to anything.
We would be better off triangulating new ideas than polishing our crufty icons. Lisp was a giant leap, hopefully not the last.
by m0zg on 10/12/19, 7:55 AM
by robobro on 10/15/19, 5:33 PM
by vincent-toups on 10/12/19, 6:06 PM
by intricatedetail on 10/12/19, 7:39 AM
by dang on 10/12/19, 8:34 AM
The way Lisp began http://paulgraham.com/rootsoflisp.html
A guide to the Bel language https://sep.yimg.com/ty/cdn/paulgraham/bellanguage.txt?t=157...
The Bel source https://sep.yimg.com/ty/cdn/paulgraham/bel.bel?t=1570864329&
Some code examples https://sep.yimg.com/ty/cdn/paulgraham/belexamples.txt?t=157...
by markhowe on 10/12/19, 7:45 AM
...sorry to be that guy.
by lostmsu on 10/12/19, 8:07 AM
Workaround is to view full site (link at the bottom)
by joak on 10/12/19, 8:01 AM
Must be hidden somewhere or not showing in my browser (firefox android with ad blockers)
by kingofpee on 10/13/19, 10:37 AM
I feel lucky now to be online ;)
by 1penny42cents on 10/12/19, 5:17 PM
by foobar_ on 10/12/19, 9:56 AM
by whazor on 10/12/19, 7:39 AM
by wintorez on 10/12/19, 9:31 PM
by adreamingsoul on 10/12/19, 11:41 AM
by Geee on 10/12/19, 12:22 PM