4 ms·
Speaking of Lisp, I'm developing a programming language that is similar to other Lisps, but I noticed that we can sprinkle a lot of macros in the core library t
by behnamoh 2y ago
Speaking of Lisp, I'm developing a programming language that is similar to other Lisps, but I noticed that we can sprinkle a lot of macros in the core library to reduce the number of parentheses that we use in the language.
example: we could have a `case` that works as follows and adheres to Scheme/Lisp style (using parentheses to clearly specify blocks):
(case name
(is_string? (print name))
(#t (print "error - name must be a string"))
)
OR we could also have a "convention" and treat test-conseq pairs implicitly, and save a few parentheses:
(case name
is_string? (print name)
#t (print "error ...")
)
what do you think about this? obviously we can implement this as a macro, but I'm wondering why this style hasn't caught on in the Lisp community.
Notice that I'm not saying we should use indentation—that part is just cosmetics. in the code block above, we simply parse case as an expression with a scrutinee followed by an even number of expressions.
Alternatively, one might use a "do" notation to avoid using (do/begin/prog ...) blocks and use a couple more parentheses:
(for my_list i do
(logic)
(more logic)
(yet more logic)
)
again, we simply look for a "do" keyword (can even say it should be ":do") and run every expression after it sequentially.
- hencq 2y agoA bunch of lisps do that. Clojure for instance or arc use conventions like that to reduce the number of parentheses. See e.g. cond in clojure: https://clojuredocs.org/clojure.core/cond https://clojuredocs.org/clojure.core/cond
- diggan 2y ago> Clojure for instance or arc use conventions like that to reduce the number of parentheses Clojure also reduces parentheses by introducing more characters for various data-structures (good and bad, many would say), like [] for vectors, which are for example used for arguments when defining functions (def add-five [a] (+ a 5))
- shawn_w 2y agoYour for example is basically Common Lisp's `loop` (loop for i in my-list do (logic) (more logic) (yet more logic))
- deleted 2y ago[deleted]
- kgeist 2y agoIn an old programming language project of mine, I wanted to use something similar to S-expressions for most of the grammar because they are very universal and flexible, but I didn’t like having too many parentheses, so I extended the syntax by allowing semicolons as an alternative. So, in pseudocode: (print (+ 1 2)) (exit 1) becomes: print (1 + 2); // "+" is the 2nd place because it's a method call on "1" exit 1; Both variants are valid; semicolons are just syntactic sugar to reduce the number of parentheses. In the AST, they represent the exact same expressions. For function bodies, I also introduced an extension to make lambdas stand out more from the rest of the code by using curly braces: (0 to 10) loop ^(i) { print i; // Internally transformed to (print i) } // clarification: // 1. The "to" method of the 0 object creates a Range object, which has a "loop" method that accepts a lambda. // 2. The ^ symbol is just a shorthand for "lambda". As you can see, this wasn't a Lisp dialect (and I'm no expert at Lisps), but I liked the idea of having a universal expression structure in the AST, however I eventually ended up extending it with two additional modifications that made it more readable (at least for me)
- tmtvl 2y agoImagine if we had a Lisp with proper types, we could do something like... (typecase name (String (print name)) (otherwise (print "error: name must be a string!"))) And if that Lisp had some kind of Object System, we may even go further and have stuff like... (defmethod namecall ((name String)) (print name)) (defmethod namecall ((name Number)) (print "I am not a number, I am a free man!"))
- codr7 2y agoWild!
- behnamoh 2y agoclojure's multi-arity addresses this to some extent but pattern matching like we know it in Haskell is very weak in Lisps...
- p_l 2y agoIn case the sarcasm was missed, the latter code was actual common lisp code to pattern match a generic function, and the former is nearly-there when it comes to common lisp code
- klibertp 2y agoWhy "nearly"? Given how symbols are uppercased upon read in CL, 'string and 'String are actually the same symbol. I just checked: `(typecase "" (String 2) (otherwise 3))` returns 2, as expected. I'm less sure about the `defmethod`s, but I think they'll also work. Plus, the capitalized type name reminded me of Coalton[1], which is an internal DSL for CL that implements ML-style type system. There, the dispatch on a type (conventionally named by a capitalized symbol) happens statically. [1] https://github.com/coalton-lang/coalton https://github.com/coalton-lang/coalton
- p_l 2y agoBecause on the phone with one hand I couldn't check if I didn't forget some detail in typecase which I use way less often than defmethod :)
- bradrn 2y agoActually, this reminds me very strongly of Rebol [0] and related languages (e.g. Red [1]). They work as you describe at the end: whenever a function is encountered, the interpreter inspects the following arguments, without any need for parentheses. Since these languages are homoiconic like Lisp, it’s possible to use functions as if they were macros (achieving it at runtime using a rather strange ‘binding’ system). [0] https://en.wikipedia.org/wiki/Rebol https://en.wikipedia.org/wiki/Rebol [1] https://www.red-lang.org/ https://www.red-lang.org/
- to4534o5345 2y agoIt's just a bunch of macros to this, no ? There are a lot more hairy/pressing issues given how old the CL spec is (the type-system esp. comes to mind).
- anonzzzies 2y agoYou can do a lot with creating your dsl/tooling and something like Coalton really. More than enough imho.
- attila-lendvai 2y agoif you think that there are too many parens in lisp then you should fix your editor. the parens are just a textual representation of a tree. once you have a proper editor, then the eliminated parens actually become an obstacle.
- anonzzzies 2y agoJust install an editor plugin (parinfer I like now) to fix that easily. It's a pleasure. It's not hard to make your own really; it's, like you say, only cosmetic. You can format your code for reading in the same way with a trivial plugin; it is a really nice thing that you can very rapidly make something nicer tailored for you while still benefitting from the performance / debugging / etc in sbcl. For my dayjob, I work a lot with Typescript parsing and rewriting and, while the ts (and ts-morph and so on) are pretty nice, it's really a quite horrible experience vs what we have in lisp/scheme.