from Hacker News

Show HN: Bel

by pg on 10/12/19, 7:14 AM with 456 comments

  • by cousin_it on 10/12/19, 10:01 AM

    Whenever I see a new programming language, this list of questions by Frank Atanassow comes to mind:

        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

    > 5. (where x)

    > 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

    Reproduced from feedback that I gave pg on an earlier draft (omitting things he seems to have addressed):

    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

    A couple of things on my checklist for mathematical purity are (a) first-class macros and (b) hardcoded builtins. It looks like Bel does have first-class macros. As for (b)...

    > 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

    Welcome back PG!

    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

    I really like how type checking is implemented for parameter lists. I think there's a more generalized extension of this.

    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

    Short direct intro, link to guide for language, here is a link to code examples. This is for me are the things I look for when reading about some new computer language release upon here or anywhere and this just wins upon that first impression. It's kinda like the early days of quality usenet posts nostalgia in the direct and to the point aspect, and I love that.
  • by SkyMarshal on 10/12/19, 6:18 PM

    >Bel is an attempt to answer the question: what happens if, instead of switching from the formal to the implementation phase as soon as possible, you try to delay that switch for as long as possible? If you keep using the axiomatic approach till you have something close to a complete programming language, what axioms do you need, and what does the resulting language look like?

    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

    I've only read the first twenty pages approximately. I'd like to see a little more disentangling of characters and strings as inputs to automata from text as something people read. The narrow technical meaning is implied in the text, but the use of "string" as a synonym for "text" is common enough that it might be worth being a little more explicit or didactic or pedantic or whatever.

    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

    It's strange that the description of the language [0] starts using numbers without introducing them at first and then far later in the file says that they are implemented as literals. I didn't get to see the source code yet (I'm on mobile and have to randomly tap the text of the linked article to find links…), but I don't understand the point of this nor if it's just a semantic choice or actually implemented that way (I don't see how).

    [0] https://sep.yimg.com/ty/cdn/paulgraham/bellanguage.txt?t=157...

  • by stereolambda on 10/12/19, 6:29 PM

    I like the (English) syntax of the article. It seems to have the same concise feeling as the language itself. I like to think that's why pg chooses falsity over falsehood.

    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

    Genuine questions that probably most here want to put but seem to be afraid of:

    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

    Welcome back to Hacker News
  • by drcode on 10/12/19, 6:26 PM

    I think at the end of the day, the question is whether a compiler for this type of language could efficiently handle a function like distinct-sorted:

       > (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

    Is there a version of Bel written in some other language? If not, how do you get started without a bootstrap?
  • by PostOnce on 10/12/19, 8:33 AM

    It amuses and pleases me to see that pg will continue to play around with lisp presumably forever, regardless of how wealthy he becomes.

    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

    How does this relate to Arc?
  • by alfiedotwtf on 10/12/19, 9:38 AM

    I remember reading pg's article on Lisp and startups, and at the time questioned if it was just mere luck. Then having a cursory look at Lisp, I questioned its relevance to the modern world.

    ... 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

    This one seems backwards to me:

        (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

    If Bel doesn't have irrational numbers, how do I use pi? Define a function that returns an approximation to a given precision?
  • by pwpwp on 10/12/19, 7:07 PM

  • by mark_l_watson on 10/12/19, 2:27 PM

    I like the syntax for function chaining: (dedup:sort < "abracadabra")

    I assume that dedup and sort are separate functions.

  • by imdhmd on 10/12/19, 8:05 AM

    I am unable to understand the difference between (a b c) and (a b . c)
  • by applecrazy on 10/12/19, 7:40 AM

    I can't say I'm familiar with Lisp (or its dialects).

    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

    Welcome back Paul :) Great to hear from you again. I almost thought you were too busy for HN since you became less active here, it's really nice to see you again!
  • by ajju on 10/12/19, 8:01 AM

    It’s great to see a technical post from pg after a while!
  • by repolfx on 10/12/19, 9:26 AM

    There's a typecheck function in the standard library, but with no documentation in the Bel source anywhere it's hard to know what it does.

    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

    Open to sharing a bit about the name? No mention of it in the guide.
  • by yellowapple on 10/14/19, 10:28 PM

    At the risk of some bikeshedding:

        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

    Will someone please teach pg some APL? It seems to be the missing piece of what he is working towards.
  • by daoudc on 10/12/19, 7:52 AM

    I love the idea of trying to build a mathematically pure language. I wonder how far it is possible to use optimisation techniques to make Bel efficient. For example, can the representation of strings as pairs be automatically optimised to a sequence of characters?
  • by segmondy on 10/12/19, 12:59 PM

    Very nice for the depth and quality. This could pass for a very good grad school project. Pg, how much effort did it take to figure out the axiomatic approach for previous formal methods. How long and how much effort did it take to produce this?
  • by eggsyntax on 10/20/19, 12:48 AM

    There are two things I found confusing in the first part of the guide (ie the part up to "Reading the Source"). The first is 'where', which is addressed in another thread on this page. The second is this:

      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

    O GLORY DAY OUR PAUL HATH RETURNED! Also is Lisp just syntactic sugar over Lambda calculus? All the Lisp people (I.e., the authors of books I’ve skimmed on lisp) worship it, but it’s simply an encoding of a n-ary tree, no? I know you can do elegant things like define lisp in lisp and the whole homoiconicity[?] thing - but don’t these endless opportunities stem from n-ary trees? My point is that of course Lisp can do this and that if it’s simply a representation of a tree - trees capture as models like all the structures of information.
  • by orthoxerox on 10/12/19, 11:24 AM

    Why does apply evaluate to itself instead of (lit prim apply)?
  • by mrburton on 10/12/19, 8:06 AM

    PG is still alive and coding! :)
  • by vessenes on 10/12/19, 3:15 PM

    Paul, this is really nice - I’m glad to see you doing some research about stuff you clearly love.

    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

    I haven't had a chance to dig in yet, just wanted to say congrats on getting it out into the world!
  • by quickthrower2 on 10/12/19, 10:40 AM

    Seems a bit closer to the lambda calculus than most lisps. Building stuff up from such primitive types.
  • by gdubs on 10/13/19, 1:36 AM

    Aside: Nice to see you hear again, pg.
  • by iamwil on 10/12/19, 4:03 PM

    As for the name, I figured it has a couple connotations.

    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

    This seems like a DSL masking itself as a programming language. Will this axiomatic approach allow declaration of domain specific operators like credit/debit? Is this is an attempt to make application development axiomatic?
  • by est31 on 10/12/19, 12:01 PM

    The source is hosted on the yahoo CDN. Interesting.
  • by e12e on 10/13/19, 12:04 PM

    So, how does one bootstrap the interpreter?

    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

    Have you considered posting this on HN under some pseudonym (including original website etc) to make experiment more .. interesting?
  • by idm on 10/12/19, 10:01 PM

    Hi Paul - looks interesting!

    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

    > (dedup:sort < "abracadabra") "abcdr"

    I extremely like this format. I think clojure has something similar?

  • by jxub on 10/12/19, 2:56 PM

    Hyped to have you back in here pg :)
  • by machawinka on 10/13/19, 5:06 PM

    There is not mention of licensing anywhere. Is it freely distributable/modifiable?
  • by Liron on 10/12/19, 11:12 PM

    How'd you pick the name?
  • by z3phyr on 10/16/19, 5:07 PM

    I can't find the definition of id in bel.bel file. Did I miss it? @pg
  • by rayalez on 10/12/19, 8:23 AM

    Wow! So cool to see a new post from PG!

    Really curious to see what this project will become.

  • by varjag on 10/13/19, 5:06 PM

    Is 'sys' really necessary, when you already have streams?
  • by dfischer on 10/12/19, 7:36 AM

    Just when I was curious on learning some Lisp. I was also saddened how much it's dropping on https://www.tiobe.com/tiobe-index/
  • by SudoNhim on 10/12/19, 7:57 AM

    Exciting! This has a lot in common with Nock/Hoon
  • by georgeEsb on 10/12/19, 5:30 PM

    Being so simple reminds me of RISC
  • by machawinka on 10/12/19, 4:43 PM

    Wonder why `no` instead of `not`.
  • by netcan on 10/12/19, 10:18 AM

    Welcome back pg.

    I hope it was a pleasant return.

  • by codr7 on 10/12/19, 12:08 PM

    I just don't think yet another Lisp is going to do it, and I've written a few [0].

    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.

    [0] https://github.com/codr7/g-fu

  • by m0zg on 10/12/19, 7:55 AM

    Wish I could have Lisp without all the parentheses. Parentheses just sour the experience for me.
  • by robobro on 10/15/19, 5:33 PM

    How do I install this?
  • by vincent-toups on 10/12/19, 6:06 PM

    Seems goofy, but ok. I'll just use Scheme.
  • by intricatedetail on 10/12/19, 7:39 AM

    Bit Edgy Language? Nice work!
  • by dang on 10/12/19, 8:34 AM

    Some users are reporting that the links don't show up on some mobile browsers. Pending a fix, here they are. (Edit: fixed now.)

    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

    There’s no link styling, at least on mobile Safari, they’re kind of essential to understand the article.

    ...sorry to be that guy.

  • by lostmsu on 10/12/19, 8:07 AM

    On mobile Firefox links are indistinguishable from regular text.

    Workaround is to view full site (link at the bottom)

  • by joak on 10/12/19, 8:01 AM

    I do not see any text file...

    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'm shocked it's the first post of Paul since 2014

    I feel lucky now to be online ;)

  • by 1penny42cents on 10/12/19, 5:17 PM

    @pg: hyperlinks aren't visible on mobile web
  • by foobar_ on 10/12/19, 9:56 AM

    Almost every language has macros now. Lisp is pointless.
  • by whazor on 10/12/19, 7:39 AM

    Welcome back pg. You should check out Jetbrains MPS, they are doing cool stuff with projectional editing. Which could mean no more brackets. I read via Twitter that they recently announced MPS for Web in Amsterdam yesterday, unfortunately I missed the conference because of my home situation :). Luckily they filmed the presentations so I will be waiting for them on YouTube.
  • by wintorez on 10/12/19, 9:31 PM

    I have a hunch that this is going to become a big deal in the future. Not sure why.
  • by adreamingsoul on 10/12/19, 11:41 AM

    Instead of writing code on the weekend, I instead have been thinking about and visualizing the code that I would like to write. That way I can use my hands for other activities, like playing in the dirt.
  • by Geee on 10/12/19, 12:22 PM

    paulgraham.com isn't secured by HTTPS. The reason why sites like this should be secured is content manipulation attacks. Now I can't trust that the Bel source code that I see is actually written by pg.