[HN Gopher] The world's loudest Lisp program to the rescue
       ___________________________________________________________________
        
       The world's loudest Lisp program to the rescue
        
       Author : kryptiskt
       Score  : 251 points
       Date   : 2024-05-02 07:50 UTC (2 days ago)
        
 (HTM) web link (blog.funcall.org)
 (TXT) w3m dump (blog.funcall.org)
        
       | nemoniac wrote:
       | Is it really established wisdom that multiple inheritance might
       | be an anti-pattern? Anyone care to elaborate?
        
         | nvy wrote:
         | Isn't it the ambiguity of the Diamond Problem? Suppose B and C
         | are both children of A, and D is a child of both B and C.
         | 
         | If B and C both have methods foo(), which gets called when you
         | do d.foo()?
         | 
         | Seems like a real footgun requiring extra effort to avoid.
        
           | phoe-krk wrote:
           | In CL's solution, the order of superclasses matter to avoid
           | ambiguity. If D is defined like (defclass d (b c) ...) then a
           | method specialized on B is called; if like (defclass d (c b)
           | ...) then it's otherwise.
        
             | pfdietz wrote:
             | And sometimes more than one method is invoked, using a
             | sophisticated method combination infrastructure.
        
               | phoe-krk wrote:
               | Right, I assumed the default method combination, and also
               | the simplest case of it with no around/before/after
               | methods being defined... Golly, CL object system is
               | complicated, now that I look at it from this perspective.
        
               | tmtvl wrote:
               | It's simple when you want it, and powerful when you need
               | it.
        
             | jerf wrote:
             | In this case the problem becomes that while one can define
             | a 100% consistent, coherent order for the compiler to use,
             | the _human 's_ ability to understand what will happen when
             | they call a method of a particular name, and also what that
             | resolution method will do as the code is refactored and
             | changed over time, exceeds anything a human can be
             | reasonably expected to have.
             | 
             | Really, all the problems with multiple inheritance are that
             | the humans can't handle the complexity that results. The
             | compilers can be made to do "something" that is arguably
             | sensible.
        
               | Jach wrote:
               | Fortunately in Lisp the compiler is available at runtime!
               | 
               | I mean, it's just not that bad. I believe the commercial
               | Lisp IDEs will just show you relevant info much like,
               | say, Java IDEs, but even with a free Lisp you can still
               | ask for it so you don't actually need to wonder what will
               | happen as you're looking at a line. You just ask. The
               | worst part of Lisp vs. C++ on multiple inheritance, I
               | think, where it can be more confusing for Lisp is that
               | Lisp will just overwrite slots (fields) sharing the same
               | name, whereas C++ will shadow them. On the other hand
               | methods aren't owned by individual classes in Lisp, so
               | you get multiple dispatch by default. Lastly the presence
               | of :before / :after / :around methods, combined with
               | multiple dispatch, make it pretty straightforward to
               | achieve behaviors through mixins that require pretty
               | complex contortions otherwise in C++. (Or Java.) The
               | behavior of those "auxiliary methods" is straightforward
               | to reason about. _All_ :before methods run before the
               | most specific primary method, in most-specific-first
               | order, and _all_ :after methods run after the least
               | specific primary method, in least-specific-first order.
               | 
               | I'm probably going to convince some people otherwise by
               | giving some more specifics, but as a minor example,
               | consider a silly "game object" style class. I can always
               | ask any class (e.g. an asteroid), hey, what's your class
               | precedence list? (closer-mop:class-precedence-list (find-
               | class 'asteroid)) returns a list of class objects:
               | asteroid, game-object, sprite, add-groups-mixin, cleaned-
               | on-kill-mixin, standard-object, slot-object, and T. From
               | the source code where the defclass is, only game-object
               | is shown. If you look at game-object, only sprite and the
               | two mixins are shown as an example of multiple
               | inheritance.
               | 
               | I don't need to call that function to get the info
               | either, it's readily available by calling 'describe on
               | the class. (I think even free editors like Lem or emacs
               | can be configured to automatically show the description
               | of things if you hover over them, I just type ,s in vim.)
               | The description includes the same class precedence list
               | info, tells me the direct superclasses, any subclasses,
               | direct slots (fields directly defined on the class),
               | inherited slots...
               | 
               | If I'm wondering what could happen if I call #'kill on an
               | asteroid before I actually call it, I can ask with the
               | built-in 'compute-applicable-methods function or 'closer-
               | mop:compute-applicable-methods-using-classes, and it will
               | show me the applicable methods are firstly the primary
               | defined method, then an :after method due to the mixin.
               | 
               | I can also compute the actual effective method that will
               | be called with 'closer-mop:compute-effective-method. For
               | something like #'kill, it shows what happens first is the
               | primary #'kill method, then the :after method. For
               | something like #'draw, let's say I overwrote the base
               | implementation, now it shows there's just one method
               | call, with the potential for the next base class method
               | if the specialized method happens to use 'call-next-
               | method.
               | 
               | So in summary, the tools exist in various forms to
               | wrestle the complexity and make it amenable to human
               | understanding. Just like with tools such as cross-
               | referencing, they help understand and create bigger
               | systems, we don't have to limit ourselves to what can
               | easily be done with physical code printouts and hand-made
               | indexes.
        
         | mark_undoio wrote:
         | I think the implementation in C++ put it out of fashion, as
         | later languages (e.g. Java) deliberately restricted it to avoid
         | the complexity. The main criticism I saw was the potential for
         | (variants of) the "diamond" where A is subclassed by B and C,
         | then both of those are subclassed by D. Does D get two copies
         | of A's state? It's hard to come up with an intuitive behaviour.
         | 
         | More recently, the move seems to be away from class based
         | object orientation (including inheritance) entirely.
         | 
         | On the other side of things, I've never heard people talk about
         | Python's multiple inheritance with the same tone used for C++ -
         | but then there are cultural differences in the language
         | communities too.
        
           | fiddlerwoaroof wrote:
           | Something I've found interesting is that most widely-used
           | class-based inheritance languages eventually added multiple
           | inheritance of implementations back in: PHP added traits that
           | can contain method implementations; Java added default
           | implementations on interfaces; etc.
        
             | lmm wrote:
             | The famous "super considered harmful" post (
             | https://fuhm.net/super-harmful/ ) pointed out the key
             | problem with diamonds, and it's mainly a problem with
             | constructors. Allowing mixins that can have method
             | implementations but only allowing one class parent with a
             | constructor is a pretty good spot in the design space, and
             | is what a lot of languages have converged on.
        
               | fiddlerwoaroof wrote:
               | I like CL's solution to constructors which is basically
               | "specialize this generic function (SHARED-INITIALIZE or
               | INITIALIZE-INSTANCE) with an :AFTER method". You reliably
               | run all the initialization code for each class involved
               | and you don't have to remember to call CALL-NEXT-METHOD
               | (CL's spelling of super)
               | 
               | Edit: I see that post refers to Dylan, which is more like
               | CL than python in the important ways. IMO, sleeping on
               | CL's object system CLOS was a huge mistake of the
               | "Java/C++ era" of our industry.
        
           | bitwize wrote:
           | > Does D get two copies of A's state? It's hard to come up
           | with an intuitive behaviour.
           | 
           | C++ gonna C++, which means the language covers _all_ the
           | bases because some programmer might get mad if their use case
           | wasn 't accounted for.
           | 
           | C++ has something called virtual inheritance, wherein if
           | subclasses B and C inherit _virtually_ from A, any subclasses
           | of both B and C will get one copy of A 's state. Otherwise,
           | they will get two copies: one from B and one from C.
           | 
           | This solves the problem of addressing concerns of all
           | programmers w.r.t. the diamond inheritance problem, but makes
           | the language more complex (and triggers my CPPPTSD).
           | 
           | https://en.wikipedia.org/wiki/Virtual_inheritance
        
             | pfdietz wrote:
             | In this vein, note that Common Lisp's inheritance would
             | always be virtual.
        
         | pfdietz wrote:
         | A nice pattern from Common Lisp is to inherit the parts of an
         | object from different superclasses. Method combination means
         | one can write methods for those superclasses and then have them
         | automatically combined in a subclass.
         | 
         | Example: if one has tree nodes with various slots that
         | represent children and you want to write a tree traversal
         | function, you put each slot in a superclass, inherit from those
         | superclasses in the correct order, and then write a method for
         | each superclass that calls the child at that slot. The methods
         | are combined in the right order automatically in a PROGN method
         | combination.
        
         | jolt42 wrote:
         | Meh. Probably a reaction to getting "burned" by it. But show me
         | something you can't get burned by.
        
         | copx wrote:
         | 90s-style Java OOP showed everyone that heavy use of multiple
         | inheritance is the worst thing since 80s-style BASIC where ever
         | third line was a GOTO.
         | 
         | Imagine one class inheriting from 50 other classes through
         | multiple inheritance..
         | 
         | People really used to construct classes like:
         | 
         | "Iron Sword inherits from Iron which inherits from Metal which
         | inherits from Meltable (which inherits from Temperature) and
         | Material. But of course it also inherits from Sword which
         | inherits from Weapon and Edged. Meanwhile Weapon inherits from
         | Equipment which inherits from Ownable and Item which.." and so
         | on.
         | 
         | Basically you make every aspect and attribute of an entity a
         | class and then create your entity's class by mushing together
         | all those classes through multiple inheritance. The results
         | are..not pretty.
         | 
         | Such code quickly becomes very hard to comprehend and maintain.
        
           | mikepurvis wrote:
           | Yup. No amount of generated documentation or static analysis
           | can make up for the cognitive load required to reason about
           | where a particular method is actually being dispatched to
           | under those conditions.
        
           | Jtsummers wrote:
           | 90s Java did not have multiple inheritance (nor does today's
           | Java). It did have multiple interfaces, but they only carried
           | a spec of the interface and no implementation details beyond
           | that. C++ was the one with multiple inheritance, if you are
           | trying to reference a popular 90s OO language.
        
           | anthk wrote:
           | OOP would work fine for a text adventure, such as Inform6
           | against the Z-Machine, which pretty much the gameplay
           | rooms->objects it's perfect for this. For everything else...
           | well... maybe just CLOS it's usable enough.
        
             | cess11 wrote:
             | The MUD-family of games are usually built in a C-like OOP-
             | language, LPC. I think it's rather nice.
        
               | anthk wrote:
               | Under Inform6 the inheritance and OOP features are
               | literally that, objects have attributes and you can
               | create in-game objects (rooms are objects too) which are
               | instances of defined ones. Such as always 'lighted'
               | rooms, a furniture class by defining as object as
               | 'scenery' (you can't take it).
               | 
               | That's an elegant example on coding Inform6 which
               | transpiles against the Z Machine, but overall I won't use
               | OOP outside gaming.
        
               | cess11 wrote:
               | Rather similar, then.
               | 
               | I've come across GUI and a database where I thought
               | object orientation was nice, and I'm also fond of
               | contemporary Smalltalk-like languages. I've made peace
               | with Java, but if I have a choice I'll be in something
               | Lisp-like or logic programming. Racket, Elixir, Scryer,
               | that sort of thing.
        
               | anthk wrote:
               | Indeed, yes. You can create a text adventure with very
               | little logic in place, by setting the winning flag when
               | very few conditions match. Everything else it's
               | predefined with objects with attributes. But, OFC, some
               | small logic it's done to add realism to the game. Such as
               | a TV showing messages upon entering a room, and so on.
               | But compared to any other language, Inform6 makes that
               | almost like editing a config file.
        
           | bitwize wrote:
           | 90s Java didn't do that because Java doesn't support multiple
           | class inheritance.
           | 
           | 90s C++, however, did.
           | 
           | Funny you should cite a game example. I once read about how
           | the developers of StarCraft[0] ran into the same Goddamn
           | inheritance problems I did when trying to build a custom game
           | engine and a game with that engine. Adding behaviors via
           | inheritance _seemed_ like a good idea _at the time_ (mid-late
           | 90s), especially given all the propaganda we read from our
           | C++ compiler manuals and such. But it turned into a situation
           | where you either accepted multiple inheritance with all of
           | its complexity and suck, including  "which of the multiple
           | base classes that implement 'foo' do I want when I call
           | derived::foo()?" -- or resorting to delegates or other
           | methods of composing behavior.
           | 
           | Me, for gaming, I became an ECS convert and haven't looked
           | back. There are some pain points when writing a game in ECS
           | style... but the advantages pay for the relatively minor pain
           | many times over.
           | 
           | [0] https://www.codeofhonor.com/blog/tough-times-on-the-road-
           | to-...
           | 
           | CFlingy is a particle spawner. Why does that have to be in
           | the inheritance chain, instead of a trait you _add_ to an
           | object?
        
             | hprotagonist wrote:
             | the canonical blog post
             | series:https://ericlippert.com/2015/04/27/wizards-and-
             | warriors-part...
        
               | lll-o-lll wrote:
               | Why "canonical"? From what I can see, Entity-Component-
               | System (ECS), long pre-date this blog series by Eric, and
               | he doesn't even reference the term.
               | 
               | I did enjoy the read however! My own programming has
               | evolved towards data oriented design over the years.
        
               | fargle wrote:
               | wow! that is a great reference.
               | 
               | i've only found it summited a few times and only with
               | comments here:
               | https://news.ycombinator.com/item?id=10567360.
               | 
               | not a lot of comments and i suspect somewhat missing the
               | point because this submission started with part 5, which
               | intentionally is only part of the series exposing the
               | pros/cons, limitations, etc. of various approaches.
        
       | mark_l_watson wrote:
       | Great writeup! I am a long time user and fan of Common Lisp, and
       | this is one of the more interesting use cases I have seen!
        
         | varjag wrote:
         | Thank you Mark! There are blessed and cursed projects out
         | there, and this one has definitely been the former.
        
         | emptybits wrote:
         | "Long time user and fan" is an understatement. Thank you,
         | again, Mark. I was re-reading your Loving Common Lisp book just
         | an hour ago!
         | 
         | I read elsewhere that you're also a Racket user. I'm curious
         | ... aside from CL legacy code requirements, do you view Racket
         | (the language and/or ecosystem) as a smart long term choice
         | going forward with lisp projects?
        
           | mark_l_watson wrote:
           | Thank you for the kind words!
           | 
           | I would choose one or the other for most of your Lisp dev. I
           | have been just an occasional user of Racket forever, but in
           | the last few years I have really been enjoying the language
           | and the minimal tools I use for Racket dev. I also feel happy
           | using Common Lisp, so it is difficult for me to make a
           | definitive statement on preference.
           | 
           | Racket and LispWorks Pro have portable UI libraries which is
           | nice. I evaluated both Racket and LispWorks Pro for making
           | standalone apps and they are both pretty good.
        
       | varjag wrote:
       | Author here, if you have any questions.
        
         | mtreis86 wrote:
         | How was working with posix threads? I've only dug into SBCL's
         | various thread tools
        
           | varjag wrote:
           | Fortunately it was uneventful, as the idiom is the same as in
           | any other programming language that support them. We used
           | bordeaux-threads package for portability across the
           | implementations.
        
         | db48x wrote:
         | What does the evacuation alarm actually sound like? Does it
         | reuse any of the sounds mentioned in the Tronstad study, or did
         | you come up with your own?
        
           | KennyBlanken wrote:
           | A ringing bell:
           | 
           | https://youtu.be/MmrihxFhWJw?t=57
        
             | db48x wrote:
             | I might have guessed that there would be a youtube video!
             | Thanks :)
        
           | varjag wrote:
           | It is a bell sound as the sister comment points out. We found
           | that a multitude of sounds work with negligible difference in
           | perception. The bell however was consistently voted the most
           | comfortable in post trial questionnaire.
        
         | guenthert wrote:
         | Given that this is a safety-critical application, are
         | condition/restarts being used? If so, what is your take on the
         | value of those and can an example of restarts be listed? If
         | not, have they been considered and if, can you share the reason
         | not to use them?
        
           | varjag wrote:
           | We certainly do use both. For example in communication we
           | process socket layer conditions and remote operation results
           | together to synthesize Evacsound's own nomenclature of
           | conditions in distributed operation terms. They are then re-
           | signaled and can be handled by a small set of our wrapper
           | macros and constructs.
           | 
           | Our process/tasks abstraction naturally also uses conditions
           | to handle the lifecycle.
           | 
           | As for restarts you can see their invocations in the last
           | code snippet in the article.
        
         | fellerts wrote:
         | What are the tunnels strung with (physical layer) that allows a
         | 10 km+ network to work reliably?
        
           | varjag wrote:
           | Lots of single mode fiber in redundant loops. In longer
           | tunnels you'd have several technical rooms along that hold
           | the loop ends into L3 switches. Within the loop you have
           | emergency cabinets spaced 125m. Apart from fire extinguishers
           | and emergency phones (often also our products!) they contain
           | some PLCs and L2 switches that distribute signal and PoE to
           | end point devices such as Evacsound or traffic cameras.
        
         | cies wrote:
         | Seems to be down, any mirrors?
         | 
         | https://blog.funcall.org//lisp%20psychoacoustics/2024/05/01/...
         | -> 404
        
           | varjag wrote:
           | Sorry about that, should be up again!
        
         | darnthenuggets wrote:
         | Were any other languages in contention here, or was it a "use
         | what you know" kind of situation? As much as I would also like
         | to be paid to write lisp, I couldn't help but notice that a lot
         | of the scarier problems solved were reasons others had
         | chosen/built erlang.
         | 
         | Great post, cool system!
        
           | varjag wrote:
           | Yes it was some of that certainly. I could gauge roughly what
           | kind of effort the problem would take, what kind of
           | constraints it would have to run with and select among the
           | tools I am comfortable with. I read about Erlang but never
           | did anything with it. From what I know though it would not
           | necessarily be better at this job than CL and learning
           | another language on the go was not in the plans.
           | 
           | But isn't it the deal with all programming language choices?
           | Ultimately the only true programming language is machine
           | code, the rest are just abstractions for our wetware's
           | benefit.
        
       | anthk wrote:
       | On Common Lisp, I loaded a nearly 30 yo eliza Chatbot written in
       | CL, it ran almost straight under SBCL with just omitting an
       | error:
       | 
       | https://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/areas...
       | sbcl --load eliza.lsp            (top-level)            (hello
       | how are you)
       | 
       | Do not use punctuation. Use (goodbye) to exit.
       | 
       | From a Unix user like me, SBCL/CL looks a bit bloaty and non-
       | Unix, but I have to acknowledge that CL and Emacs' Elisp had a
       | great history on compatibility and easyness due to the
       | homoiconicity. In plain English: everything it's handled in the
       | same way everywhere. The syntax will be the same on every
       | function.
        
       | troad wrote:
       | This is a really cool story!
       | 
       | Perhaps a slight segue, but I recently tried to learn CL for the
       | first time and I was genuinely surprised by all the decades of
       | accumulated cruft (mainly masses of semi-redundant and soft-
       | depreciated standard library functions, with bizarre names). The
       | way people talk about Lisp, I'd expected something more elegant.
       | I suppose I should try something like Scheme or Racket, but it's
       | hard to find an introduction to those that isn't bone dry.
       | (Recommendations welcome!)
       | 
       | I've also heard people say reading Lisp functions, inside out,
       | ensconced (heya) in their parentheses, is somehow more
       | comprehensible than sequential C style, but this state of
       | enlightenment thus far eludes me. I can only speak for myself,
       | but I definitely reason about code outside in rather than inside
       | out.
        
         | db48x wrote:
         | The funny names all have history. They had history even at the
         | time when Common Lisp was standardized.
        
           | troad wrote:
           | No doubt! I look forward to learning it in due course, but
           | it's not exactly penetrable for a newcomer, particularly
           | amidst a sea of parentheses.
        
         | hickelpickle wrote:
         | Little schemer is good, some people hate it some people love
         | it. But it is a fairly light read the slowly teaches some
         | syntax at a time, questions you about assumptions then revels
         | the information as it goes on. It would be the least dry read.
         | There is also sketchy scheme for a more thorough text, or even
         | the rs7s standard, which are both pretty dry but short.
         | 
         | What made me appreciate scheme was watching some of the SICP
         | lectures (https://www.youtube.com/watch?v=2Op3QLzMgSY&list=PL8F
         | E88AA54...) and the little schemer to learn more. I also read
         | some of the SICP along with it, though I put it down due to not
         | having the time to work through it.
         | 
         | Scheme is interesting and toying with recursion is fun, but the
         | path a mentioned above is only really enjoyable if you are
         | looking to toy around with CS concepts and recursion. You can
         | do a lot more in modern scheme as well, and you can build
         | anything out of CL. But learning the basics of scheme/lisp is
         | can be pretty dry if you are just looking to build something
         | right away like you already can in a traditional imperative
         | language. But it is interesting if you are interested in a
         | different perspective. But even RS7S scheme is still far from
         | the batteries included you get with CL.
         | 
         | I personal found the most enjoyment using Kawa scheme, which is
         | jvm based and using it for scripting with java programs as it
         | has great interop. I used it some for a game back end in the
         | event system to be able to emit events while developing and
         | script behaviors, I've also used it for configurations as well
         | with a graphical terminal app, I used hooks into the ascii
         | display/table libraries then kawa to configure the
         | tables/outputs and how to format the data.
        
           | troad wrote:
           | Interesting, thank you!
           | 
           | I suppose what draws me to Lisp is that insight people say it
           | gives them on programming. I already do much of my
           | programming in functional style, so I'm trying to discover
           | what it is about Lisp that's so beloved above and beyond that
           | - I'm gathering it's a mix of recursion and the pleasantness
           | of being able to get 'inside' the program, so to speak, with
           | a REPL?
           | 
           | I must also admit that I tend to run into a bit of a
           | roadblock over Lisp's apparent view that programming is, or
           | should be, or should look like, maths. I cut my teeth on
           | assembly, so for me programming isn't maths, but giving
           | instructions to silicon, where that silicon is only somewhat
           | loosely based on maths. It tends to make me bounce off Lisp
           | resources which by Chapter 2 are trying to show the
           | advantages of Lisp by implementing some arcane algorithm with
           | tail-end recursion.* But I'm very open to being persuaded I'm
           | missing the bigger picture here, hence my ongoing effort to
           | grok Lisp.
           | 
           | (*Isn't tail-end recursion just an obfuscated goto?)
        
             | Tevo wrote:
             | >recursion
             | 
             | I think one of the reasons recursion is often emphasized in
             | relation to Lisp is because one of Lisp's core data
             | structures, the linked list, can be defined inductively,
             | and thus lends itself well to transformations expressed
             | recursively (since they follow the structure of the data to
             | the letter). But recursion in itself isn't something
             | particularly special. Though it is more general than loops,
             | and so it is nice to have some grasp on it, and how looping
             | and iteration relate to each other, and it is often easier
             | to reason about a problem in terms of a base case and a
             | recursive case rather than a loop, at a higher level you
             | will usually come to find bare recursion mostly
             | counterproductive. You want to abstract it out, such that
             | you can then compose your data transformations out of
             | higher level operations which you can pick and match at
             | will, APL-style. Think reductions, onto which you build
             | mappings and filters and groupings and scans and whichever
             | odd transformations one could devise, at which point
             | recursion isn't much more than an implementation detail.
             | This is about collections, but anything inductive would
             | follow a similar pattern. Most functional languages will
             | edge you towards the latter, and I find Lisp won't
             | particularly, unless you actively seek it out (though
             | Clojure encourages it most explicitly, if you consider that
             | a Lisp).
             | 
             | >the pleasantness of being able to get 'inside' the program
             | 
             | Indeed, that's one of the things makes Common Lisp in
             | specific particularly great (and it is something other
             | contemporary dialects seem to miss, to varying degrees). It
             | lets you sit within your program and sculpt it from the
             | inside, in a Smalltalk sort of way, and the whole language
             | is designed towards that. Pervasive late-binding means
             | redefining mostly anything takes effect pretty much
             | immediately, not having to bother recompiling or reloading
             | anything else depending on it. The object system specifies
             | things such as class redefinitions and instance morphing
             | and dependencies and so on, such that you can start with a
             | simple class definition, then go on to to interactively add
             | or remove slots, or play with the inheritance chain, and
             | have all of the existing instances just do the right thing,
             | most of the time. Many provided functions that let you poke
             | and prod the state of your image don't make much sense
             | outside of an interactive environment.
             | 
             | There is a point to be made about abstraction, maths, and
             | giving instructions to silicon (and metaprogramming!), but
             | I'll have to pass for now. I apologize if this is too
             | rambly, I tend to get verbose when tired.
        
               | troad wrote:
               | Not at all too rambly, very interesting, thank you. Your
               | answer makes intuitive sense to me; I'll ponder over it.
        
               | lispm wrote:
               | > I think one of the reasons recursion is often
               | emphasized in relation to Lisp is because one of Lisp's
               | core data structures, the linked list, can be defined
               | inductively
               | 
               | Lisp was used in computer science education to teach
               | "recursion". We are not talking about software
               | engineering, but learning new ways to think about
               | programming. That can be seen in SICP, which is not a
               | Lisp/Scheme text, but a computer science education book,
               | teaching students ways to think, from the basics upwards.
               | 
               | Personally I would not use recursion in programs
               | everywhaere, unless the recursive solution is somewhat
               | easier to think about. Typically I would use a higher
               | order function or some extended loop construct.
        
             | cess11 wrote:
             | You might already be aware, but there is a DISASSEMBLE
             | function in the CL spec:
             | http://clhs.lisp.se/Body/f_disass.htm
             | 
             | The details are implementation and platform dependent, but
             | on e.g. SBCL someone who understands assembly could use
             | this to dig into what the compiler does and tune their
             | functions.
             | 
             | I was also drawn in on the promise of insight, but I'm not
             | so sure that's what I got out of it. What keeps me hooked
             | is more the ease with which I can study somewhat advanced
             | programming and computer science topics. There has been
             | aha-moments for sure, like when many moons ago it clicked
             | how object and closure can be considered very, very similar
             | and serve pretty much the same purpose in an application.
             | But it's the unhinged amount of power and flexiblity that
             | keeps me interested.
             | 
             | Give me three days and I would most likely fail horribly at
             | inventing a concurrency library in Java even though it's
             | one of the languages that pays my bills, but with Common
             | Lisp or Racket I would probably have something to show. As
             | someone who hasn't spent any time studying these things at
             | uni (my subjects were theology and law) I find these
             | languages and the tooling they provide awesome. It's not
             | uncommon that I prototype in them and then transfer parts
             | of it back to the algolians, which these days usually have
             | somewhat primitive or clumsy implementations of parts of
             | the functional languages.
             | 
             | I think the reason why tail call optimisation crops up in
             | introductory material is because it makes succinct
             | recursive functions viable in practice. Without it the
             | application would explode on sufficiently large inputs,
             | while TCO allows streaming data of unknown, theoretically
             | unlimited, size. Things like while and for are kind of
             | special, somewhat limited, cases of recursion, and getting
             | fluent with recursive functions means you can craft your
             | own looping structures that fit the problem precisely.
             | Though in CL you also have the LOOP macro, which is a small
             | programming language in itself.
        
               | sourcepluck wrote:
               | "Algolian" is a lovely word. Does it come from somewhere,
               | or was it yourself off the cuff?
        
               | cess11 wrote:
               | 'C-like language' has irked me for decades, since C was
               | one of the first languages I learned and most languages
               | that expression refers to are nothing like C, so when I
               | came across lispers referring to Algol-like or Algol-
               | descendants I took it a step further.
               | 
               | A web search tells me it's already in use in Star Trek.
        
             | lispm wrote:
             | There are a bunch of things to learn from Lisp:
             | 
             | * list processing -> model data as lists and process those
             | 
             | * list processing applied to Lisp -> model programs as
             | lists and process those -> EVAL and COMPILE
             | 
             | * EVAL, the interpreter as a Lisp program
             | 
             | * write programs to process programs -> code generators,
             | macros, ...
             | 
             | * write programs in a more declarative way -> a code
             | generator transforms the description into working code ->
             | embedded domain specific language
             | 
             | * interactive software development -> bottom up
             | programming, prototyping, interactive error handling,
             | evolving programs, ...
             | 
             | and so on...
             | 
             | The pioneering things of Lisp from the end 50s / early 60s:
             | list processing, automatic memory management (garbage
             | collection), symbol expressions, programming with recursive
             | procedures, higher order procedures, interactive
             | development with a Read Eval Print Loop, the EVAL
             | interpreter for Lisp in Lisp, the compiler for Lisp in
             | Lisp, native code generation and code loading,
             | saving/starting program state (the "image"), macros for
             | code transformations, embedded languages, ...
             | 
             | That's was a lot of stuff, which has found its way into
             | many languages and is now a part of what many people use.
             | Example: Garbage Collection now is naturally a part of
             | infrastructure, like .net or languages like Java and
             | JavaScript. It had its roots in Lisp, because the need
             | arose to process dynamic lists in complex programs, getting
             | rid of the burden of manual memory management. Lisp got a
             | mark & sweep garbage collector. That's why we say Lisp is
             | not invented but discovered.
             | 
             | Similar the first Lisp source interpreter. John McCarthy
             | came up with the idea of EVAL, but thought it only to be a
             | mathematical idea. His team picked up the idea and
             | implemented it. The result was the first Lisp source
             | interpreter. Alan Kay said about this: "Yes, that was the
             | big revelation to me when I was in graduate school--when I
             | finally understood that the half page of code on the bottom
             | of page 13 of the Lisp 1.5 manual was Lisp in itself. These
             | were "Maxwell's Equations of Software!. EVAL is the E in
             | REPL.
             | 
             | Then Lisp had s-expressions (symbol expressions -> nested
             | lists of "atoms"), which could be read (R) and printed.
             | 
             | This is the "REP" part of the REPL. Looping it was easy,
             | then.
             | 
             | People then hooked up Lisp to early terminals. In 1963 an
             | 17 year old kid (
             | https://de.wikipedia.org/wiki/L_Peter_Deutsch ) wrote a
             | Lisp interpreter and attached it to a terminal: the
             | interactive REPL.
             | 
             | A really good, but large, book to teach the larger picture
             | of Lisp programming is PAIP, Paradigms of Artificial
             | Intelligence Programming, Case Studies in Common Lisp by
             | Peter Norvig ( -> https://github.com/norvig/paip-lisp ).
             | 
             | A beginner/mid-level book, for people with some programming
             | experience, on the practical side is: PCL, Practical Common
             | Lisp by Peter Seibel ( -> https://gigamonkeys.com/book/ )
             | 
             | Both are available online at no cost.
        
             | MarceColl wrote:
             | Common Lisp is not a functional programming language in
             | most current definition of the word. It's as procedural as
             | they come, then libraries on top build other paradigms.
             | 
             | Scheme tends to approach things more math-like. While
             | common lisp is less academic and more practical.
        
             | pfdietz wrote:
             | It's important to distinguish between Common Lisp and
             | Scheme. The two approaches have diverged considerably, with
             | different emphasis. The aspects you describe in your third
             | paragraph there are more Scheme than Common Lisp.
        
         | adonovan wrote:
         | > I'd expected something more elegant.
         | 
         | Common Lisp is sort of the union of all dialects of Lisp, and
         | some might say of all possible programming language paradigms.
         | Scheme is more like the intersection of dialects, and is thus
         | closer to the platonic ideal of Lisp. If you've never seen any
         | dialect of Lisp before, Scheme may be a better introduction to
         | the flavor as it's much easier to learn.
        
         | kazinator wrote:
         | How do you know the functions are "semi-redundant" and "soft-
         | depreciated", if you've not worked in this before?
        
           | troad wrote:
           | Clever question, but a boring answer - the learning resource
           | I was using simply said so (in fact, several did!). It seems
           | common for learning resources to somewhat apologetically
           | explain that Common Lisp has many functions with similar
           | names but subtly different behaviours (e.g. (=) v (eq) v
           | (eql) v (equal) v (equalp) v (string-equal)), before telling
           | you which ones are in vogue.
        
             | kazinator wrote:
             | There is no "vogue" about it. Those functions test for
             | different equalities. It's not the case that any of them
             | are new versions of the others.
             | 
             | (eq x y) tests whether x and y are the same object. It is
             | very fast because typically all it has to do is do a
             | machine word comparison, and that comparison is conclusive.
             | (When it is false, there is no more work to do to rule out
             | sameness.)
             | 
             | If x and y are the same number, of the same type, it is not
             | required to report true. Even if they are the the same
             | number that you might think fits into a machine word,
             | though on most implementations that situation will be _eq_.
             | ANSI Lisp allows for implementations in which small,
             | identical integer values like 7 are not necessarily _eq_. A
             | Lisp implementation in which all numbers are  "boxed"
             | quantities on the heap could be conforming to ANSI.
             | 
             | The _eql_ function is like _eq_ , but the same characters
             | and same numbers of the same type are required to be equal
             | under _eql_. For all other objects it is like _eq_. _eql_
             | might be implemented in terms of doing an _eq_ comparison,
             | and then when that is false, doing more work to rule out
             | sameness of numbers and characters.
             | 
             | Common Lisp's hash tables can use different equalities;
             | that is where it can make a bigger difference. Objects in
             | an _eq_ hash table can use a very simple, fast hashing
             | function. Whereas objects in an _eql_ hash table have to be
             | hashed in such a way that equal integer or floating-point
             | values have the same hash. A value that is a pointer to a
             | boxed bignum integer has to be dereferenced to access some
             | of the value bits of that object.
             | 
             | There are some exotic functions in Lisp that you might
             | never end up using, particularly in the list processing
             | area like _pairlis_ or _revappend_ and whatnot.
        
               | troad wrote:
               | Yeah, I am aware of the differences. I equivocated about
               | specifying examples, because I worried someone would try
               | to explain them, rather than engage with my overall
               | point.
               | 
               | My overall point is two-fold. (1) There is nothing in the
               | function name that would indicate the difference between,
               | say, (eq) and (eql) and (equal), any more than you could
               | guess what the difference between (colorise), (clrise)
               | and (clrs) would be on sight. Lisp seems to love doing
               | this. To me, it just seems like an obvious source of very
               | painful bugs (works as expected 99% of the time and then
               | it doesn't).
               | 
               | (2) In many (most?) day-to-day cases, the distinction
               | isn't material, and for those the ecosystem is going to
               | end up preferring one more than the others (which may
               | change over time - hence, 'in vogue'). The references
               | I've seen tend to suggest sticking to (eq) and (equal),
               | for instance, and avoiding (eql) unless you have specific
               | need of it.
               | 
               | For a language that is reputed to be elegant and
               | beautiful, this - well, isn't that. Hence my initial
               | surprise.
        
               | kgwgk wrote:
               | > (1) There is nothing in the function name that would
               | indicate the difference between, say, (eq) and (eql) and
               | (equal), any more than you could guess what the
               | difference between (colorise), (clrise) and (clrs) would
               | be on sight. Lisp seems to love doing this. To me, it
               | just seems like an obvious source of subtle bugs.
               | 
               | What alternative would you suggest?
               | 
               | Giving paragraph-length names to the functions? Common
               | Lisp already has some of the more descriptive function
               | names around and they can be inconvenient if the function
               | is used often. (By the way, there is something that helps
               | to remember what those functions do: shorter names are
               | correlated with more primitive and restrictive checks.)
               | 
               | Having a single function that performs different checks
               | depending on a parameter? If you don't know which
               | function to use you don't know which parameter to use
               | either.
               | 
               | Removing the ability to perform different kinds of checks
               | entirely?
        
               | doctor_eval wrote:
               | I think troad is trying to explain how they feel about
               | learning CL and what they've discovered. They aren't
               | criticising CL. Of course naming things over a long
               | period of time is a complex problem, that's why they
               | acknowledged that there is a lot of cruft from the 60s.
               | 
               | I've found their comments, and the constructive responses
               | to them, interesting because I am interested in Lisp but
               | have never learned it.
               | 
               | What I don't find interesting is seeing troad's
               | observations strongly challenged, as you are doing, as if
               | somehow by sharing their observations, they now owe us
               | detailed solutions as well.
               | 
               | It's not cool.
        
               | kgwgk wrote:
               | Fair enough. In fact I agree with the broad point that
               | having functions that do things is a source of bugs and
               | CL is a huge language with less than perfect names. My
               | point is that having less functions that do less things
               | does not obviously reduce the number of bugs in the end
               | if those things still need to be done. Anyway. I see how
               | a logical argument may be out of place if the thread is
               | understood about sharing feelings and not about
               | challenging claims.
        
               | pfdietz wrote:
               | I'd suggest changing the name from SORT to NSORT, just
               | for consistency and bug avoidance. :) But it's water
               | under the bridge and one can patch this (or, really, any
               | gripe about function names) by suitable package fu, at
               | the cost of making your code less readable to others.
        
               | kazinator wrote:
               | I did exactly that in TXR Lisp, after initially following
               | the Common Lisp naming. In the same change, I also made a
               | function called _shuffle_ nondestructive, and introduced
               | _nshuffle_.
               | 
               | It's a backwards compat breakage, but there is a
               | mechanism in the language which helps with such
               | situations.                 txr -C 237
               | 
               | or setting the TXR_COMPAT environment variable to 237 or
               | lower will restore the destructive behavior of sort and
               | shuffle. People who don't want to fix their code can
               | deploy that way.
               | 
               | I hate compatibility breaking changes, but it was a real
               | thorn in my side how sort is destructive without any
               | indication in its name, in a language where destructive
               | versions of functions should be separately named.
               | 
               | Now the thing is that sort is not _required_ to be
               | destructive. It is _allowed_ to be. Therefore code
               | written to the language spec will not break if sort
               | becomes pure. But we have to worry about breaking all
               | programs though, not just programs written to the spec.
               | (Unless we are GCC maintainers; different rules apply.)
               | You can 't just say, "Oh, programs that call sort on a
               | vector and ignore the return value, expecting the vector
               | to be sorted, are just nonportable junk; let them break."
        
               | pfdietz wrote:
               | In general, the "N" versions of functions in the standard
               | say they "maybe" or "might" modify arguments. SORT and
               | NSORT should have been like this, but IIRC SORT was taken
               | from Interlisp, where it was destructive.
        
               | kgwgk wrote:
               | I agree that there are some inconsistencies in the naming
               | of functions and parameters like destructive/non-
               | destructive variants and predicates among other things.
               | Also strange names like car and cdr (which on the other
               | hand allow for cadr et al.). However, even though they
               | can be confusing, I wouldn't put the equality functions
               | in the same bag.
        
               | kgwgk wrote:
               | > (2) In many (most?) day-to-day cases, the distinction
               | isn't material, and for those the ecosystem is going to
               | end up preferring one more than the others (which may
               | change over time - hence, 'in vogue'). The references
               | I've seen tend to suggest sticking to (eq) and (equal),
               | for instance, and avoiding (eql) unless you have specific
               | need of it.
               | 
               | I guess they suggest two instead of one because in most
               | cases the difference is material. And I imagine that they
               | also suggest using = to compare numbers.
               | 
               | When the distinction doesn't matter one could just use
               | eq. I'm not sure that this covers most uses though.
        
               | kazinator wrote:
               | If you want to test whether _x_ is 1.0 or 1, then _(= x
               | 1)_ is what you want. But = is specific to numbers and
               | blows up on non-numbers.
               | 
               | The family of functions whose names begin with _eq_ are
               | special in that they are applicable to all objects;
               | _equal_ will tell you that _" abc"_ is not _1_ without
               | complaining.
        
               | kgwgk wrote:
               | But - with the exception of equalp - they may fail to
               | identify as equal numbers which are equal (=). I
               | suggested to use = to compare numbers specifically.
        
               | kazinator wrote:
               | > _rather than engage with my overall point_
               | 
               | So you'd want someone to engage your overall point that
               | there are redundant and deprecated functions, while the
               | specific ones you actually have in mind are not redundant
               | or deprecated (and you know this)? And for that reason,
               | it would be good to keep the specifics out of the
               | discussion? Okay ...
               | 
               | > _There is nothing in the function name_
               | 
               | Yes there is: the names get longer with increasing
               | complexity of comparison.
               | 
               | The common _eq_ prefix puts them into a family.
               | 
               | > _avoiding (eql) unless you have specific need of it._
               | 
               |  _eql_ is the default value of the :test argument in
               | numerous library functions.
               | 
               | Rather, you should avoid _eq_ unless you 're optimizing.
               | Rarely do you want to compare objects in such a way that
               | (<compare> 12345 12345) might be false!
               | 
               | It is idiomatic, though, to use _eq_ in code that
               | manipulates symbols, like _(if (eq arg 'foo) ...)_.
               | 
               | If one of the arguments of an equality function is a
               | constant, it's possible to pick the strongest equality
               | function which goes with that constant's type. All
               | equality functions reduce to _eq_ when symbols are
               | compared.
               | 
               | > _Lisp seems to love doing this._
               | 
               | Many operator names in Lisp are short mnemonics. It is
               | like this in older languages, or older parts of
               | languages. Short identifiers keep programs short.
               | 
               | Short, mnemonic names are part of the elegance of
               | traditional Lisps.
               | 
               | It's not just old versus new; for instance in some very
               | new languages, we see a trend of shortening _define_ to
               | _def_ , or _function_ to _fn_ and such.
               | 
               | My TXR Lisp is much newer than Common Lisp, but I
               | shortened some things. Instead of _stable-sort_ , I have
               | _ssort_. Or instead of _symbol-macrolet_ , I have
               | _symacrolet_. In Common Lisp, like in many languages,
               | there is a  "layer" of newer identifiers that are longer,
               | often hyphenated compounds. You can tell that _define-
               | symbol-macro_ is newer than _defun_. However, someone
               | making a new language which is inspired by an existing
               | one can challenge those decisions, going by what
               | identifiers are often used, rather than going by the
               | chronological order in which they were introduced in the
               | inspiring language. Symbol macros were introduced in
               | Common Lisp for, I think, supporting _with-slots_. But
               | symbol macros turn out to be important, deserving short
               | names.
               | 
               | Why _ssort_ rather than _stable-sort_? Part of the reason
               | is that I made a change of introducing _nsort_ as the in-
               | place sort, making _sort_ pure. That then establishes the
               | idea that we have a one letter modifier. The _s_ for
               | stable becomes another one. And in fact, I have one more:
               | _c_ for caching. There are all eight combinations, in the
               | order _c_ , _s_ , _n_ : in other words c?s?n?sort. Thus
               | csnort ("cee snort") is the caching, stable, destructive
               | sort. I don't want to punish the programmer and reader of
               | the code with _caching-stable-destructive-sort_. This is
               | not Java.
               | 
               | You can't cram meaning into the spelling of every
               | identifier, by making it out of a string of English
               | words, because that makes things comically verbose.
               | 
               | Languages don't do that. You can't guess what "water"
               | means, if you're new to English, and your native language
               | doesn't have a cognate like "wasser". You just have to
               | learn the vocabulary word. Some words are compounds of
               | other words, others aren't. Only some compounds have
               | compositional meanings, bearing out the obvious guess.
        
               | taeric wrote:
               | I always find it odd when I see how hard modern languages
               | move away from mnemonic style. And I share what I feel is
               | your amusement that some people think there is a
               | universal guessability to some symbolic terms. It is all
               | learned, and it is convenient when it leverages other
               | learning. There is nothing really universal, though. As
               | much as that would be convenient.
        
               | lispm wrote:
               | Lisp was developed at a time when space was more limited.
               | Generally operators had short names. Page 147 of the Lisp
               | I manual from 1960 has a function listing: https://bitsav
               | ers.org/pdf/mit/rle_lisp/LISP_I_Programmers_Ma...
               | 
               | Generally in Common lisp we have EQ, EQL, EQUAL, EQUALP
               | -> from the most specific to the most general. The most
               | specific has the shortest name: https://www.cs.cmu.edu/Gr
               | oups/AI/html/cltl/clm/node74.html
               | 
               | EQL is actually often used, since it is also the default
               | equality test in Common Lisp. For example the named TEST
               | argument has the default EQL. That information is
               | slightly hidden. Example: (find 1 '(2 3 2 1 3)) is the
               | same as (find 1 '(2 3 2 1 3) :test 'eql) , since EQL is
               | the default test. One can pass a different equality test
               | predicate, if needed.
               | 
               | Some background about naming and equality operators in
               | Lisp: http://www.nhplace.com/kent/PS/EQUAL.html
               | 
               | Other languages for example use some of =, ==, ===, is,
               | ... what may the difference be?
               | 
               | There were many different naming conventions in Lisp over
               | the decades. One was, as mentioned above, the more
               | specific/primitive operators have shorter names. Later
               | (70s/80s, Lisp got a lot more operators and at some point
               | there were operators with long names introduced. This was
               | not liked by everyone, since one needed to type longer
               | names - completion was often new then (or slow).
               | 
               | For example CLOS was added end 80s. Thus it uses names
               | like UPDATE-INSTANCE-FOR-DIFFERENT-CLASS, instead of
               | UPDINSTC ;-) .
               | 
               | Generally, a good Lisp IDE should make getting the
               | documentation (and source code) for any operator easy.
        
         | superdisk wrote:
         | As someone else said, Scheme is the one that warrants the
         | "pure, elegant" reputation. CL is full of crazy features and
         | weird functions but it's because it's basically the continued
         | lineage of the original Lisp from 1960. It can even run those
         | old 60s vintage programs with minimal tweaks.
         | 
         | https://web.archive.org/web/20150217111426/http://www.inform...
         | 
         | If you just want to play with macros and learn what makes the
         | Lisp thing so special I'd recommend Clojure, it's like a
         | stripped down CL with only functional features, and it's
         | extremely nice and ergonomic.
        
         | kqr wrote:
         | > I've also heard people say reading Lisp functions, inside
         | out, ensconced (heya) in their parentheses, is somehow more
         | comprehensible than sequential C style, but this state of
         | enlightenment thus far eludes me. I can only speak for myself,
         | but I definitely reason about code outside in rather than
         | inside out.
         | 
         | Based on my years tutoring university students in various
         | programming languages throughout their courses, I suspect some
         | of this is personal preference that's set before one starts
         | programming.
         | 
         | Some people who start with C-style languages find Lisp-style
         | languages more intuitive, while some people who start with
         | Lisp-style languages breathe a sigh of relief when they
         | discover C-style languages. I haven't found any predictor of
         | this ahead of time - as far as I can tell it's just something
         | one discovers as one tries different languages.
        
           | pjc50 wrote:
           | As I posted on the "cognition" lexer thread, some users
           | prefer "left handed scissors". Just as it is not equally
           | intuitive for everyone to write with a particular hand, it is
           | not equally intuitive for everyone to program with a
           | particular language.
        
         | brabel wrote:
         | CL does have some weird stuff, after all it's coming from the
         | 1960's LISP tradition. But after you get past some basic weird
         | stuff, it's a quite wonderful language.
         | 
         | > I can only speak for myself, but I definitely reason about
         | code outside in rather than inside out.
         | 
         | You can indent code to make it much easier to "parse", and use
         | some macros that turn the code inside/out, it's more readable
         | than most other languages.
         | 
         | The CL cookbook is an excellent resource, and this page links
         | to several other excellent resources and books you can read for
         | free online: https://lispcookbook.github.io/cl-cookbook/
         | 
         | The "new docs" also present the documentation in a "modern"
         | looking way (rather than the 90's looks of what you get if you
         | Google around): https://lisp-docs.github.io/cl-language-
         | reference/
         | 
         | About other Lisps...
         | 
         | The Racket Guide is definitely not "bone-dry":
         | https://docs.racket-lang.org/guide/intro.html
         | 
         | It is well written and looks very beautiful to me.
         | 
         | On another Scheme, I find Guile docs also great:
         | https://www.gnu.org/software/guile/manual/html_node/index.ht...
         | 
         | They may be a bit more "dry" but they're to the point and very
         | readable! In fact, I think Lisp languages tend to have great
         | documentation. The guy who wrote is an excellent writer (he has
         | written Racket books which are equally great) and I believe is
         | the author of the Racket docs tool!
        
         | Jach wrote:
         | Have you seen https://stevelosh.com/blog/2018/08/a-road-to-
         | common-lisp/ ? "Kludges" everywhere is applicable. On the other
         | hand, having a function like "row-major-aref" that allows
         | accessing any multi-dimensional array as if it were one
         | dimensional is "sweeter than the honeycomb".
         | 
         | I still think CL code can be beautiful. Norvig's in PAIP
         | https://github.com/norvig/paip-lisp is nice.
         | 
         | As for the inside-out remark, while technically you do it for
         | even basic syntax, you don't always exactly have to, and it's
         | very convenient to not do. Clojure has its semi-famous arrow
         | macro that lets you write things in a more sequential style, it
         | exists in CL too, and there's always the venerable let*
         | binding. e.g. 3 options:                   (loop (print (eval
         | (read))))         (-> (read) (eval) (print) (loop))
         | (loop           (let* ((r (read))                  (e (eval
         | r)))             (print e)))
         | 
         | And even the first one isn't that bad to read. For the really
         | annoying cases like a lot of arithmetic, just use the reader
         | macro from the 90s that lets you write in infix mode rather
         | than complain how the quadratic equation is harder to read in
         | prefix notation.
        
         | lispm wrote:
         | On thing to keep in mind when you see the language, which
         | evolved of several decades: it has low-level (go to, ...), mid-
         | level (macros, ...) and high-level (CLOS + MOP) elements in one
         | language. A reason for that: the low-level parts are code
         | generation building blocks for the higher level parts. Example:
         | The SERIES library (a higher-level way to think about loops and
         | sequences) uses macros (mid-level) to transform code into
         | efficient loops (-> low-level): https://github.com/rtoy/cl-
         | series
         | 
         | So one reason for all this functionality is: the language is
         | its own compilation target. One is not supposed to write all
         | the code, but we can write code which writes the lower-level
         | code.
        
         | agumonkey wrote:
         | I'm part of the (lisp) crowd, I always had trouble and anger
         | toward C, Java, (and even ADA for syntactic choices) and when I
         | got into lisps it felt like finding home. There's less of what
         | I don't like (side effects, syntax) and more of what I like
         | (value oriented, composability, principled, interactive,
         | tree/recursive thinking, ability to customize your language
         | more).
         | 
         | A 'cleaner' starting point might be clojure (lisp on top of the
         | JVM). Rich Hickey tried to make it short and principled,
         | leveraging interfaces for polymorphism. schemes are cool too.
         | 
         | Some cruft in lisp I still like, like car/cdr .. in clojure
         | they're named first/rest .. obviously more obvious.. yet a I
         | miss using car and cdr to walk/deconstruct structures. There's
         | something timeless about them.
        
         | bmacho wrote:
         | > I suppose I should try something like Scheme or Racket, but
         | it's hard to find an introduction to those that isn't bone dry.
         | (Recommendations welcome!)
         | 
         | Use it as a tool, instead of an end goal. Your end goal can be
         | the SICP book, HtDP book, leetcode, pet project. Or literally
         | whatever that you like doing.
        
         | mark_l_watson wrote:
         | I kind of like the decades of accumulated cruft and I like that
         | Common Lisp code I wrote decades ago still works as-is. More
         | modern conveniences like Quicklisp make everything simple and a
         | mellow experience to use.
         | 
         | All that said, I also strongly recommend Racket. I just use a
         | small part of the Racket ecosystem: compiler, REPL, Emacs
         | bindings, and sometimes DrRacket. The library and packaging
         | system is simple to get used to and use.
         | 
         | Sorry for going off topic: I need to use Python a lot for my
         | own research and projects, and I find Python tricky. Don't ask
         | me how often I blow away my Python installation, and
         | occasionally even switch between project specific virtual
         | environments and different miniconda environments. Yuck.
        
         | hcarvalhoalves wrote:
         | There's cruft, but there's also decades long backwards
         | compatibility and feature completeness.
         | 
         | Sitting down and doing actual work instead of fighting immature
         | runtimes and toolchain isn't a bad idea, but unfortunately is
         | something pervasive in this industry. In addition, nothing I've
         | tried thus far comes even close to the experience of the CL
         | debugger.
        
       | worthless-trash wrote:
       | I would love to read more on these topics. I keep getting told
       | that lisp isn't "used anymore" (Even though I actively do).
        
       | justneedaname wrote:
       | This reminds me of the very first project that I worked on, a
       | warning system for rail trackside workers. There had been
       | numerous case studies of near misses, injuries and even
       | fatalities.
       | 
       | The system currently in place at the time was, unbelievably, two
       | people (in the case of a bi-directional line) stood downline
       | within earshot of the main crew. When they saw a train
       | approaching they would blow whistles and wave a flag, the workers
       | would then move out of the way until the train passed. Yeah I
       | also couldn't believe that such an archaic system was still in
       | use - this was in 2019 mind.
       | 
       | The company in charge of managing the railway lines reached out
       | to our company and a few others to have us tender on a new design
       | to help protect workers and reduce near misses. Our research led
       | us to an existing system developed by a company in Switzerland
       | which we essentially planned to modify for our national network,
       | as there are differences in how railway lines are signalled
       | across different regions. It consisted of units that could be
       | placed periodically downline of the work site and would alarm
       | when a train was approaching by use of real-time train location
       | data.
       | 
       | The main issue we faced though was how to ensure an accurate
       | reading that gave enough time to vacate the line whilst not being
       | excessive, as research suggested workers may believe it to be a
       | false positive if nothing approached after a couple of minutes.
       | To understand why this is a difficult problem it first helps to
       | understand how traffic within a railway line is managed.
       | 
       | The railway network is split into what is known as blocks, these
       | are discrete sections of track separated by axle counters.
       | Without a train the two sections of track are electronically
       | separate, when one passes over a circuit is completed and the
       | train's position can know be known to that exact location at that
       | exact time. However these readings are discreet, with resolution
       | of the trains position only being as good as the number of axle
       | counters present on the line. This results in some tricky
       | estimating of when "impact" will happen. Train speed is another
       | metric that can be used in conjunction but again you only know
       | the speed read at the last axle counter, anything could have
       | happened between the last reading and "now".
       | 
       | In the end our solution was to assume maximum line speed and warn
       | when this would be within 30s of the worksite. We created a demo
       | that worked flawlessly and the client was visibly impressed.
       | However they then wanted a proposal, cost and everything else for
       | the next phase within 2 weeks - so we had to pull out as we
       | weren't able to produce it. This was a real shame for me as I
       | look back on this project with fond memories, one of the few
       | projects where we were essentially left to figure it out. Already
       | in my short career (<5y) I've been fortunate enough to work on
       | some interesting projects and gain interesting stories to tell...
        
       ___________________________________________________________________
       (page generated 2024-05-04 23:02 UTC)