Fork me on GitHub
#off-topic
<
2024-02-24
>
teodorlu10:02:49

I believe there’s a quote that goes something like > In Lisp, the goal is to split your code into an implementation of a DSL that lets you talk effectively about the problems you are trying to solve, and usage of that low-level DSL. > I’m trying to search for it, but I can’t find it. Does this sound familiar to anyone?

flowthing11:02:15

I don’t know that quote specifically so I don’t know whether this is helpful, but it sounds like Paul Graham talking about bottom-up programming (in “On Lisp”).

👍 1
2
teodorlu11:02:21

Reading https://sep.turbifycdn.com/ty/cdn/paulgraham/onlisp.pdf, section 1.2 Programming Bottom-Up right now, this is really interesting.

teodorlu11:02:58

Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design—changing the language to suit the problem. In Lisp, you don’t just write your program down toward the language, you also build the language up toward your program. As you’re writing a program you may think “I wish Lisp had such- and-such an operator.” So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together. Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem. In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient.🎯 💯 Thanks! 🙏

👍 2
Jacob O'Bryant11:02:47

I've often wondered about bottom-up programming since I don't think I've ever done it in clojure or even have much of an idea what it would look like. is it more of a common lisp/not clojure thing? Hiccup and core.async come to mind, but it sounds like PG is talking about writing DSLs that are more specific to a particular application.

1
teodorlu11:02:03

Hiccup and core.async come to mind, but it sounds like PG is talking about writing DSLs that are more specific to a particular application.In Clojure, I don’t think I’d put too much emphasis on macros / data abstraction — but rather look for a namespace with operations on some domain abstraction, which is possibly just data. I’d say you’re doing bottom-up programming if you’re starting out in a REPL trying to get things working before you make an HTTP handler that returns hiccup.

2
teodorlu11:02:48

“we CAN implement a DSL with macros, but we don’t necessarily HAVE to if we can solve our problem with functions and data”

1
Martynas Maciulevičius11:02:20

I think that one way of dealing with a problem is not by influencing the host language (Clojure or other) but parsing and interpreting the DSL yourself. This way you deal with a sub-problem and you can abstract on top of it later. i.e. bottom-up design shouldn't mean "I'll write a macro here and it will be abstracted away". > “we CAN implement a DSL with macros, but we don’t necessarily HAVE to if we can solve our problem with functions and data” Exactly.

👍 1
phill12:02:07

Hanson & Sussman, in "Software Design for Flexibility: How to Avoid Programming Yourself into a Corner", refer to a division between "served spaces" and "servant spaces".

👀 1
👍 1
Ben Sless15:02:39

@U3X7174KS in Clojure you often find data DSLs, hiccup, malli, aws API

👍 3
teodorlu15:02:16

> Hanson & Sussman, in “Software Design for Flexibility: How to Avoid Programming Yourself into a Corner”, refer to a division between “served spaces” and “servant spaces”. Huh, great point. I have a copy of that book, but I didn’t think of looking for references to this question.

respatialized16:02:09

Matthew Butterick has a related essay https://beautifulracket.com/appendix/why-lop-why-racket.htmlhttps://beautifulracket.com/appendix/why-lop-why-racket.htmlhttps://beautifulracket.com/appendix/why-lop-why-racket.html that also addresses this topic. > Above, I described a program­ming language as a “medium of exchange” between humans and computers. In that way, languages fit among the broader cate­gory of things we call inter­faces. > This brings me to my second major claim (of three): that language-oriented program­ming is funda­men­tally an inter­face-design tech­nique. If you like thinking about inter­faces, you’ll love LOP. If you don’t, you may still love LOP, because it enables certain inter­faces that are other­wise unat­tain­able.

💯 2
🙏 1
👍 1
crkoehnen17:02:05

Norvig weaves DSL's throughout Paradigms of Artificial Intelligence: Case Studies in Common Lisp but I don't see anything as strongly phrased as @U3X7174KS’s quote above. Norvig does have a nice way of describing the tradeoffs:

The two versions of the preceding program represent two alternate approaches that come up time and time again in developing programs: (1) Use the most straightforward mapping of the problem description directly into Lisp code. (2) Use the most natural notation available to solve the problem, and then worry about writing an interpreter for that notation.

Approach (2) involves an extra step, and thus is more work for small problems. However, programs that use this approach are often easier to modify and expand. This is especially true in a domain where there is a lot of data to account for. The grammar of natural language is one such domain-in fact, most AI problems fit this description. The idea behind approach (2) is to work with the problem as much as possible in its own terms, and to minimize the part of the solution that is written directly in Lisp.

Fortunately, it is very easy in Lisp to design new notations-in effect, new programming languages. Thus, Lisp encourages the construction of more robust programs. Throughout this book, we will be aware of the two approaches. The reader may notice that in most cases, we choose the second.
https://github.com/norvig/paip-lisp/blob/main/docs/chapter2.md

👍 2
kennytilton19:02:42

Note that Graham does not mention macros. What he said could conceivably involve nothing but writing functions to implement the DSL. But! Common Lisp is a lisp-2, so if we want our coding to feel like the DSL is a seamless part of the host, we will be writing a bunch of macros. With Clojure, a lisp-1, I almost never write macros, except in libraries where necessary boilerplate can be hidden.

👍 1
teodorlu16:03:08

16 days later, Big thanks for all the replies. You turned my Saturday into a quite enjoyable exploration into a variety of interesting sources. I continue to be impressed by the wisdom and knowledge of the people hanging around here.

👍 1