[HN Gopher] Why Hy?
       ___________________________________________________________________
        
       Why Hy?
        
       Author : tosh
       Score  : 138 points
       Date   : 2022-05-03 11:34 UTC (11 hours ago)
        
 (HTM) web link (docs.hylang.org)
 (TXT) w3m dump (docs.hylang.org)
        
       | adg001 wrote:
       | So, Hy allows "to freely mix imperative, functional, and object-
       | oriented styles of programming."
       | 
       | I wonder: 1/ Shall we mix multiple paradigms of programming in
       | the same project? 2/ Should we adopt a single programming
       | language that supports multiple programming paradigms and utilise
       | single paradigm for each given project, for the sake of
       | minimizing the skill set required to the development team and -
       | not necessarily -the learning curve?
        
         | pmarreck wrote:
         | and any time a language allows this "free mixing", it loses the
         | very tangible guarantees of purely-functional languages such as
         | immutable data, emphasis on no side effects, etc.
        
       | JasonFruit wrote:
       | Hy is a false promise. It looks like a lisp; depending on your
       | idea of a Platonic lisp, it may _be_ a lisp --- but it preserves
       | Python semantics, including its odd scoping rules, and it doesn
       | 't feel like writing actual lisp. Scheme or Common Lisp simply
       | feel more coherent, having semantics that make sense with the
       | language.
        
         | robonerd wrote:
         | I haven't gotten into Hy, but what you say about a 'false
         | promise' of lisp reminds me of the impression Fennel left me.
         | No cons, compile error for '(), no quasiquoting.. it left me
         | wondering where the list processing was.
        
           | giraffe_lady wrote:
           | Fennel made a really interesting choice in rigidly sticking
           | to the lua semantics.
           | 
           | I think in isolation it would be a fairly bad choice, but in
           | practice you get a drop-in replacement for lua that fixes
           | every problem with lua.
           | 
           | I wouldn't want any other lisp to work like it does but damn
           | I consider that thing my savior at this point. I've come to
           | really hate lua and fennel bails me out every time.
        
             | robonerd wrote:
             | I suppose I should give Fennel another chance, since I have
             | similar feelings towards Lua. Lack of quasiquoting
             | particularly does sting though, using quasiquoting to
             | construct lua tables seems like it would be nice.
        
               | giraffe_lady wrote:
               | There's also that partial implementation of the clojure
               | stdlib in fennel that might have it. If not... it does
               | have a macro system though I've avoided using it. Macros
               | can be a quagmire even in popular well-documented lisps
               | which fennel definitely is not either.
        
         | quasarj wrote:
         | What is odd about Python scoping rules?
        
           | xigoi wrote:
           | Variables are function-scoped, not block-scoped. So you can
           | do this:                   if 2 < 3:             s = "Math
           | works"         else:             s = "Math doesn't work"
           | print(s)
        
         | gilch wrote:
         | I wonder if Hissp would be more to your taste?
         | https://github.com/gilch/hissp
        
         | Kodiologist wrote:
         | I've been working on Hy since 2016 and I've frequently
         | encountered, but never understood, the sentiment that Hy isn't
         | a "real Lisp". What makes for a real Lisp? There have been
         | dozens (hundreds?) of Lisps over the decades, and if they all
         | have a defining characteristic that Hy lacks, I don't know what
         | it is. Certainly Lisps have varied in how scoping works, among
         | other things.
        
           | mumblemumble wrote:
           | Agreed. If odd scoping rules are the problem, we can possibly
           | disqualify most lisps that have ever existed. Including all
           | of the ones that John McCarthy had a hand in building.
           | 
           | For my part, I had similar "this doesn't feel _quite_ like
           | lisp " moments with both Hy and Clojure. And I ultimately
           | realized that it's the mere presence of the base platform
           | that gets me. With Racket, I'm used to feeling like I'm
           | sealed off in my own lispy bubble. With Hy and Clojure, there
           | are always bits of Python or Java (read: Not Lisp) hiding in
           | the background. Many differences from other well-known lisps
           | that I know are attributable to that base platform.
           | 
           | And that's a catch-22 situation. Objectively, they might be
           | (and, IMO, are) good design decisions. But they're also
           | covered in non-lisp cooties. I don't know why I should expect
           | otherwise. Brains are weird.
        
       | Qem wrote:
       | I wish there was a IDLE for Hy (HYDLE?), so one could have a
       | minimum effort environment setup to get started. What editors
       | currently support Hylang syntax highlighting?
        
         | kjuulh wrote:
         | emacs has a mode for it: https://github.com/hylang/hy-mode
         | 
         | doom emacs make it easy to get started.
        
           | seanw444 wrote:
           | Went to install the package manually to try Hy out. Figured
           | it was a niche/small enough language that it wouldn't have
           | its own Doom module. I was wrong.
        
         | mark_l_watson wrote:
         | I use Emacs and also VSCode. Easy to set up.
        
         | bayesian_horse wrote:
         | There is also Calisto Hy and JedHy for Jupyter notebook
         | support.
        
       | oleganza wrote:
       | Whenever people bring up Lisp syntax, I like to remind everyone
       | about io language. Its homoiconicity is inspired by Lisp, and
       | almost all good things about Lisp syntax are applied in io, but
       | at the same time it avoids this awkwardness that turns away most
       | of the people (and turns the remaining minority into zealots :-)
       | 
       | So if you design a language and want to use Lisp-like syntax, I
       | recommend to also check out io before steaming ahead.
        
         | spdegabrielle wrote:
         | I'd heard that homoiconicity isn't real and there is no
         | meaningful definition?
        
           | reikonomusha wrote:
           | A language is homoiconic if code in that language is written
           | using the syntax of data literals of that language.
           | 
           | In the case of most Lisps, code is written using the syntax
           | of list and symbol literals. (There are other literals too,
           | of course.)                   (I (usually) like apples)
           | 
           | is a nested list literal with four symbols. You can think of
           | symbols as "interned strings"; they're written without quotes
           | for convenience. It's not unlike                   ["I",
           | ["usually"], "like", "apples"]
           | 
           | in Python, except I had to use actual strings instead of
           | symbols because Python doesn't ship with a standard symbol
           | type.
           | 
           | This is also a nested literal list:                   (loop
           | for i below n do (print i))
           | 
           | but this happens to be a list literal that can be "run" (or
           | in Lisp parlance, evaluated) as code.
        
         | cardanome wrote:
         | Yeah, Lisps don't have a monopoly in homoiconicity. In addition
         | to io, the Rebol family is also worth checking out.
         | 
         | Though I have to admit I can not imagine how a person can be so
         | mentally inflexible as to be not able to tolerate Lisp-style
         | syntax. I get that Common Lisp might look a bit old-school at
         | first glance but something like Clojure is basically designed
         | to look aesthetically pleasing.
        
         | jhbadger wrote:
         | I played with io some time ago as it was one of the languages
         | covered in Bruce Tate's "Seven Languages in Seven Weeks" which
         | give an introduction to seven programming languages (Ruby, Io,
         | Prolog, Scala, Erlang, Clojure, and Haskell) each with a
         | different philosophy. Io seemed an interesting proof of
         | concept, but are you actually using it for a real project or
         | just to explore?
        
       | simulate-me wrote:
       | The first snippet of code I see on that page requires me to
       | understand way too much syntax. It's nice to see smaller snippets
       | of code when first exploring a new language to decide if it's
       | worth the effort to learn the syntax and language features.
        
         | gilch wrote:
         | Would you prefer something like this?
         | https://hissp.readthedocs.io/en/v0.3.0/lissp_quickstart.html
        
       | spapas82 wrote:
       | Does it support some kind of repl driven development similar to
       | lisp/clojure? Ie evaluate expressions on a live app and update
       | the live up with the new values?
        
         | Kodiologist wrote:
         | I'm not familiar with such a feature, but you can certainly run
         | a Hy program and edit its state in the REPL at the same time,
         | if that suffices.
        
       | billfruit wrote:
       | The experience I had with it the last time i tried it was that it
       | was syntactically very similar to Clojure, but certain subtle
       | differences with it. Close but not being precisely same as
       | something else could often result in confusions.
        
         | Kodiologist wrote:
         | I've been trying to steer the syntax towards imitating Python
         | more than Clojure, the idea being that you frequently need to
         | rapidly switch between reading Python and Hy (as when you're
         | writing a Hy program while consulting documentation for a
         | Python library), so it helps to minimize friction there. Thus
         | e.g. `True` must now be capitalized that way, Python-style;
         | `true` used to be allowed as well. But whether a more
         | Pythonesque Hy is more or less confusing than a more
         | Clojuresque Hy is admittedly a matter of taste.
        
       | revskill wrote:
       | Most of python system i've seen is full of bugs, lack of
       | stability, which causes huge damage from developer resources as
       | well as operational costs. It's too hard for a junior Python
       | developer to produce a reliable system.
       | 
       | One of the reason as i know is, they have no idea of using unit
       | test.
        
       | whycombs wrote:
       | I've been using hylang lately to build libraries for my python
       | projects. It's a lot of fun, and close enough to Clojure that
       | there's very little learning curve.
        
       | vindarel wrote:
       | I encourage people to try out Common Lisp because, unlike with
       | Hy, you will get: speed, ability to build binaries, truly
       | interactive image-based development (yes, more interactive than
       | ipython), more static type checks, more language features (no
       | closures in Hy last time I checked), language stability... To
       | reach to Python libs, you have https://github.com/bendudson/py4cl
       | My comparison of Python and CL: https://lisp-
       | journey.gitlab.io/pythonvslisp/
        
         | amelius wrote:
         | What I look for in a language first is how good the support is
         | for concurrency, and especially if it has a good, modern
         | concurrent garbage collector.
         | 
         | A quick search brought up this:
         | 
         | https://lisp-journey.gitlab.io/blog/pro-mailing-list-on-comm...
         | 
         | > This was primarily for the lack of good parallel, concurrent
         | garbage collectors in Common Lisp implementations. The CL
         | version of elPrep was actually still a tad faster than any of
         | the C++, Go, or Java versions, but we had to work hard to avoid
         | long GC pauses. elPrep allocates a lot of memory, and the pause
         | time hurts a lot. We solved this by, basically, disabling the
         | garbage collector, and reusing memory manually as much as
         | possible, which turned the program into almost a manually
         | memory-managed affair.
        
           | throwaway894345 wrote:
           | With respect to concurrency, after a lot of experience
           | operating async Python services, the thing that I look for is
           | _a single, standard, ubiquitous concurrency model_. One of
           | the biggest pain points for operating Python systems is some
           | transitive dependency making a synchronous I /O call and
           | blocking the whole event loop, causing timeouts in unrelated
           | endpoints and often bringing the whole system down
           | (healthchecks start to fail because the endpoint is blocked
           | and then the supervisor kills the whole process/pod/etc).
           | 
           | This doesn't happen in Go or (presumably) languages that run
           | on Erlang's BEAM VM because there is no sync I/O (from the
           | event loop's perspective, anyway).
        
           | throw10920 wrote:
           | > What I look for in a language first is how good the support
           | is for concurrency, and especially if it has a good, modern
           | concurrent garbage collector.
           | 
           | ...in which case you'll _definitely_ not want to use Python
           | either, and so are rather far out of place in this thread.
        
             | amelius wrote:
             | Python is a great language, but its design-mistakes
             | regarding concurrency are exactly why I'm worried about
             | that aspect when looking for a new language.
        
           | vindarel wrote:
           | They didn't try Allegro CL's new parallel GC (see comments).
           | Otherwise, yeah. It depends on one's use case, I guess.
        
         | ducktective wrote:
         | What about other LISPs? Racket? Clojure? What is your view on
         | Red language?
        
           | vindarel wrote:
           | They feel all limited to me :D I only did serious CL
           | development but neither of those two especially attract me:
           | they are less interactive (and that's my ideal and a daily
           | joy), I don't need the Java ecosystem, I want to be lighter
           | on resources... I take news about Red from time to time and
           | it's still in its early phases it seems.
        
             | didibus wrote:
             | I watched the video from your article:
             | https://youtu.be/CNFr7zIfyeM
             | 
             | And as someone who programs in Clojure, I feel the
             | interactivity is the same. Maybe I'm missing a detail of
             | what he's doing though?
             | 
             | The part you don't have in Clojure (without using a
             | library), is the restart options, but he didn't seem to
             | ever use them, seems he just looked at the error message,
             | and went back to fix the code and re-evaluate his test
             | again, and that would be exactly the interactive flow I
             | would follow in Clojure.
             | 
             | Am I missing something?
        
               | BaculumMeumEst wrote:
               | By using Clojure, you're missing out on reliance on
               | poorly maintained ffi libraries, a messy library
               | ecosystem where you get randomly surprised by side
               | effects from mutability where you weren't expecting it,
               | and a poor build system.
               | 
               | I love writing CL but there's a reason it's not enjoying
               | wide usage nowadays, and I definitely wouldn't go around
               | recommending it to unsuspecting people without heavy
               | caveats.
        
               | vindarel wrote:
               | ah, I see. There's another shorter one below:
               | https://www.youtube.com/watch?v=KsHxgP3SRTs In that one I
               | get the debugger, I go to the erroneous function, I re-
               | compile it, come back to the debugger and resume
               | execution (seeing everything pass). Can you do that in
               | Clojure? There's also the typical class change: in CL you
               | can alter a class definition and the existing objects are
               | (lazily) updated. Also (and it's like the only time I
               | tried Clojure) you can't install a Clojure library from
               | the Clojure REPL, right? And then, what's explained here:
               | https://mikelevins.github.io/posts/2020-12-18-repl-
               | driven/
        
               | didibus wrote:
               | I probably would need to play with that facility in CL to
               | really get a sense of the difference.
               | 
               | In Clojure, you can debug at the REPL, but it doesn't
               | drop you in the debugger by default. You'd need to eval
               | the function as debug first, then it will drop you into
               | the debugger next time the function is called.
               | 
               | And there's no restart system by default, so for example
               | you probably wouldn't retry by choosing restart test from
               | the exception debugger, you'd just re-evaluate the test
               | yourself to have it rerun.
               | 
               | There's a condition restart library, and I played a bit
               | with it, but not enough, I was confused about how to go
               | about choosing options to handle the condition or how to
               | define them.
               | 
               | So the typical flow in Clojure would be:
               | 1. Error thrown         2. Go to line of code that threw
               | error         3. Fix code         4. Eval fixed code
               | 5. Eval the thing that threw the error again (seeing
               | everything pass)
               | 
               | And if you want to observe the state at the place of the
               | error thrown you'd add between 2 and 3:
               | 2.1 Eval function as debug         2.2 Re-eval thing that
               | threw error         2.3 When in debugger inspect all
               | locals and state, find the problem
               | 
               | And then go to 3.
               | 
               | I never really looked into if there was a way to make
               | eval as debug default with break on error, then I guess
               | you'd get a very similar flow, except for missing the
               | restart options.
               | 
               | > There's also the typical class change: in CL you can
               | alter a class definition and the existing objects are
               | (lazily) updated
               | 
               | Since Clojure isn't OO, this isn't a 1:1 comparison. But
               | the closest thing to OO is polymorphic facilities, except
               | they don't have state. Anyways, you can update the
               | implementation of the polymorphic methods and it gets
               | picked up for existing types or data that were
               | polymorphic over them.
               | 
               | You can also add more polymorphic methods and those get
               | picked up automatically.
               | 
               | There is a construct that has fields on it, but it's
               | almost never used, so I actually don't remember if it
               | would let you update fields on existing instances, I
               | believe not. In CL can you add/remove fields on the class
               | and the existing instances get updated? What happens to
               | new fields how are they initialized in that case?
               | 
               | > you can't install a Clojure library from the Clojure
               | REPL, right?
               | 
               | Well, you can, but let's say that it's something that
               | easily breaks, so let's call it a "beta" feature. Some
               | people use it effectively and don't seem to have issues,
               | but others seem to always have it not work as expected,
               | so a lot of people restart the REPL most likely when they
               | want to add a lib.
               | 
               | Also, it's not a standard feature of Clojure, instead
               | it's a feature of your build tool, either Leiningen or
               | Tools.deps, and both have a different way to do it.
               | Though tools.deps is the default dependency manager that
               | comes with Clojure now, and its add-lib feature should
               | one day get out of beta and become permanent, probably
               | once they iron out the quirks.
               | 
               | https://practical.li/clojure-staging/alternative-
               | tools/cloju...
        
               | vindarel wrote:
               | > In CL can you add/remove fields on the class and the
               | existing instances get updated? What happens to new
               | fields how are they initialized in that case?
               | 
               | yes, and you can even specialize built-in methods so that
               | the update does exactly what you want O_o See update-
               | instance-for-redefined-class. It takes as arguments the
               | added slots, the discarded ones, it's supposed to do the
               | right thing but we can customize it.
        
               | didibus wrote:
               | Ah I see, ya that's a pretty neat feature for an OO
               | language.
               | 
               | You wouldn't get that in Clojure for defining types,
               | since they'd be Java types and then they only get what
               | features the Java runtime allows on types and it doesn't
               | have that one.
               | 
               | But in practice, since Clojure is functional, it's kind
               | of a non-issue.
               | 
               | I should really try CL to be sure, but it seems you'd get
               | 95% or more of the same interactivity in Clojure.
               | 
               | What I can tell you is I find Clojure superior to Emacs
               | LISP in interactivity (which I've used both extensively).
               | Emacs can technically redefine more things inside-out,
               | like it can do the full runtime rebuild from the example
               | link, but because it isn't functional and immutable
               | first, managing the state as you redefine things tends to
               | be more complex, and I find that makes it less
               | interactive, since I need to do a lot of state setup and
               | teardown to get things back to what I want to re-
               | evaluate.
        
               | pcr910303 wrote:
               | Admittedly I've never seriously investigated Clojure
               | debugging tools so it might be that Clojure already
               | supports something similar; but the Debugging Common
               | Lisp[0] series might showcase how Common Lisp (with
               | signals, restarts, mechanisms for redefining classes, p
               | and more...) and SLIME aids debugging in how other
               | 'usual' languages don't.
               | 
               | [0]: https://malisper.me/category/debugging-common-lisp/
        
         | Kodiologist wrote:
         | Hy has closures. They work just like Python's.
         | 
         | (Common Lisp is super cool, though. Perhaps one day Hy will be
         | as cool.)
        
           | vindarel wrote:
           | oopsy, thanks, I was thinking about let (discussed below).
           | (yep, I tried Hy but not for long, since I needed something
           | more than Python)
        
         | mrtranscendence wrote:
         | Common Lisp is great, I'm sure, but it's a bit of a nonstarter
         | for me because most of my work is Spark ETL and machine
         | learning. I can theoretically sneak some hy in for low-
         | visibility code but I can't do the same for Common Lisp.
         | 
         | > no closures in Hy last time I checked
         | 
         | I don't know when the last time you checked was, but as far as
         | I can tell hy definitely has closures. It largely follows
         | Python semantics, after all.
        
           | vindarel wrote:
           | If you're (very) motivated you could try MGL or CLML!
           | https://github.com/melisgl/mgl -
           | https://github.com/mmaul/clml -
           | https://github.com/CodyReichert/awesome-cl#machine-learning
           | 
           | MGL's auhor [won](https://github.com/melisgl/higgsml) the
           | Higgs Boson ML Challenge.
        
         | lf-non wrote:
         | Can you elaborate on how CL provides more static type checks ?
         | I am not much familiar with CL, but does it provide something
         | similar to typed-racket ? Do major libraries actually use it ?
        
           | vindarel wrote:
           | Not so easy question, especially because it depends of the
           | implementation, but SBCL gives pretty good static type errors
           | and warnings. Mostly, you get warnings at the function
           | boundaries. It isn't complete like type checking in the
           | modern languages, but it helps catch many errors. And quickly
           | & interactively, because we compile our functions as we write
           | them, with a keystroke (or the whole file, and from time to
           | time, we build the whole project from scratch). So, coming
           | from Python, that was superbly useful to me. This, everybody
           | uses it. We can also add gradual typing to our variables and
           | functions. It might help for the static checks, and it also
           | gives hints for the compiler to speed things up. We can also
           | declare our own types, but these won't be used for compile-
           | time inference.
           | 
           | For a type-racket equivalent, we now have Coalton, it's like
           | a Haskell on top of CL: https://github.com/coalton-
           | lang/coalton/ Its author says:
           | 
           | --
           | 
           | Take this with a grain of salt, because I'm neither a user
           | nor expert of Typed Racket, but:                   Typed
           | Racket focuses more on the gradual typing of a given program.
           | It has lots of features to make that easier, such as
           | occurrence typing. Coalton is a separate, embedded language.
           | Typed Racket achieves polymorphism through subtyping and and
           | first-order type variables. Coalton achieves polymorphism
           | through type variables, higher-kinded types, and type
           | classes.         Coalton, like ML and Haskell, focuses on
           | defining objects by their properties and supported functions.
           | This is a proposed way of having modular, reusable code.
           | Typed Racket, as far as I can tell, has no such features.
           | Coalton code can be fully inferred, so type annotations are
           | not necessary. Typed Racket cannot.
           | 
           | All in all, I think the biggest and most important take-away
           | is that Typed Racket goes through great effort to seamlessly
           | blend with ordinary Racket. But that means Typed Racket has
           | to compromise on type system features that can only be
           | supported if you're willing to change the language itself.
           | 
           | Coalton puts the type system first, opting for something
           | close to Haskell, at the expense of not being a system for
           | gradually typing Common Lisp, and instead being a separate
           | language altogether.
           | 
           | ---
           | 
           | They use it for their open-source quantum compiler and other
           | things.
        
             | lf-non wrote:
             | Coalton looks interesting - hadn't heard of it before.
        
         | emptysongglass wrote:
         | This reads out of touch with why curious people use Hy, like me
         | who wanted to get going with an easily accessible language and
         | ecosystem (Python) while rewriting bits in Hy to grok some lisp
         | magic.
         | 
         | No, of course I wouldn't have reached for CL first and it's
         | disappointing to read the top-comment is this.
        
           | IshKebab wrote:
           | But... by using Hy you're already learning a new super niche
           | language. If you're going to learn a new language why not
           | ditch Python and use something good?
           | 
           | Ecosystem size is really the only thing I can think of.
        
             | emptysongglass wrote:
             | Because I write Python to plug into a bigger ecosystem and
             | I can mix and match Python and Hy freely. I can also use
             | Poetry to package and manage dependencies and Poetry2nix to
             | output a Nix derivation that is guaranteed to run on
             | someone else's machine. I can also freely tap Python
             | packages like Beautiful Soup or use frameworks like Django
             | (which I am). The entire Python universe is available to
             | me. The number of accessible tutorials for Django, videos
             | for Pythonistas and community support channels is
             | monumentally large. I even get to do cool things like use
             | Django's ORM for learning how to interact with and
             | manipulate data in Postgres, all right there available to
             | me.
             | 
             | I can use Discord (despite my distaste for it as a platform
             | it has a _huge_ Django and Python community), Telegram,
             | IRC, and Matrix to ask for help and get metric tonnes of
             | friendly advice, suggestions and criticisms from
             | Pythonistas.
             | 
             | And I can take all of this at my own pace, writing only
             | bits in Hy and branching as I go. Every step is as gradual
             | as I want it to be.
             | 
             | Common Lisp is not the answer to my needs. Presenting it as
             | so is tone deaf at the least.
        
               | vindarel wrote:
               | BTW, about Postgres, data, web app... pgcharts, that
               | turns queries into charts:
               | https://github.com/dimitri/pgcharts is written in CL :)
               | Speaking of Postgres, pgloader was re-written from Python
               | to CL, here's why: https://tapoueh.org/blog/2014/05/why-
               | is-pgloader-so-much-fas...
        
               | vindarel wrote:
               | but who's presenting CL as the answer to your needs?
               | (me?)
               | 
               | If you're happy with your mix of Python and Hy, well,
               | great. But you know what, you can do what you described
               | with CL too! Need to do some webscraping? Beautiful Soup
               | -> lquery. Django -> well... no CL framework gives you
               | all these batteries included, but what if you want to
               | extract data from a Postgres DB and display it in a web
               | app? that's very easy [1] in CL too. Django ORM ->
               | postmodern or Mito (or more). IDK about Nix but several
               | people are working with CL and Guix.
               | 
               | https://github.com/CodyReichert/awesome-cl
               | 
               | What worked out for me was to write companion services in
               | CL, instead of extending my big Django app. This new
               | service that takes data from a FTP server, transforms it,
               | stores it, displays it in a web app? CL. That web app
               | that serves another kind of customers than the Django
               | one? A CL app. It isn't for everybody and sometimes you
               | wish for a bigger ecosystem, but anyways, many things can
               | be done in CL.
               | 
               | [1]: ok honestly the learning process was not that easy.
               | It's a bit easier with my contributions now! (Cookbook
               | etc)
        
             | stingraycharles wrote:
             | There are two "ecosystems" at topic here: the language
             | you're writing code in, and the environment that it's being
             | executed in. In this case, you're writing Hy that's
             | executed in a Python language environment, that allows you
             | to tap into its entire ecosystem with Hy (in a similar way
             | like Clojure and the JVM). These types of "alternative
             | front ends" are a great way to bridge the gap for a new
             | language.
             | 
             | As such, for Hy's target audience, I think it's not as much
             | "ditch a new language" as it is "I have to use Python for
             | $reason, but I want something more like CL". A good example
             | of this would be any machine learning related work.
             | 
             | Last but not least, I would expect that on HN we focus a
             | bit more on "what could make Hy even better" rather than
             | "what other languages are better than Hy".
        
             | aeturnum wrote:
             | I think you're misunderstanding the appeal of ecosystems
             | here. It's not just about install base - it's about the
             | mental load of adjusting to a new set of assumptions and
             | paradigms for interacting with the computer.
             | 
             | To me, the way to think about "introducing" someone to Lisp
             | and helping them understand the choices the language makes
             | - you really want to focus on the things that make Lisp
             | stand out, and one way of doing that is re-using a lot of
             | the functionality of a language that outsiders may be
             | familiar with.
             | 
             | I generally agree that if you want to build something
             | substantial you probably would choose CL over Hy, but if
             | you want to "try a lisp" while minimizing startup costs and
             | you have a Python background I think Hy makes way more
             | sense.
        
               | reikonomusha wrote:
               | I don't want to devolve into any petty arguments about
               | what makes a Lisp a "Lisp", since everybody has their own
               | incompatible definition, but I will say writing Hy feels
               | like writing Python with weird syntax, and it does not
               | feel like writing Lisp with a huge, familiar ecosystem of
               | libraries.
               | 
               | I will give you this, though, you can have a taste macros
               | with Hy, which of course are one of the cornerstones of
               | different Lisps.
               | 
               | With that said, I do not feel like one would accurately
               | develop a feel for what Lisp is like (be it Common Lisp,
               | Scheme, Racket, or Clojure) by using Hy.
        
               | aeturnum wrote:
               | > _I don 't want to devolve into any petty arguments
               | about what makes a Lisp a "Lisp",_
               | 
               | Very much agree! I shouldn't have framed it that way.
               | 
               | I should have said: each time you make a hybrid language
               | between approaches, there are new people who will try it
               | out and may discover a new and exciting way to program.
               | Some people, in hindsight, will certainly wish they had
               | jumped further - but they can always do that in the
               | future and some will only make the bigger jump after
               | making a smaller one.
        
               | cjohnson318 wrote:
               | On top of that, just figuring out which Lisp to start
               | with, and how to get started with it, is an ordeal. In
               | the JVM ecosystem, Java is pretty obvious, and Kotlin is
               | a pretty obvious alternative. In the Lisp ecosystem, the
               | well known SCIP is targeted at Scheme, Clojure is pretty
               | well known, then there's Racket, ChezScheme, CommonLisp,
               | and the they all look like pretty good starting places.
        
               | mumblemumble wrote:
               | It's an expensive choice to make, too. It quickly becomes
               | apparent that, no matter which lisp you choose, there
               | will always be a group of people trying to convince you
               | that you picked the wrong one, and pressuring you to
               | second-guess yourself.
        
               | reikonomusha wrote:
               | You're saying it's expensive because... people on non-
               | topical forums might tell you their opinion, uninformed
               | of your circumstances?
               | 
               | If you choose language X, I advise learning it alongside
               | people who know and use X. It seems like a no-brainer to
               | me, and not all that expensive.
        
               | mumblemumble wrote:
               | It's expensive because seeing that kind of stuff as a
               | potential newcomer to a community can have a way of
               | psyching a person out and making them think they need to
               | be extra careful about this decision.
               | 
               | Basically, that "if you choose..." advice is for the
               | wrong context, specifically because of the "if you
               | choose" qualifier. I'm talking about what happens during
               | the pre-choice time period.
        
               | reikonomusha wrote:
               | I don't want to diminish the challenges newcomers have
               | with interacting with people online, but we have to
               | understand that even _choosing Lisp_ is going to be met
               | with significant derision _from people who don 't write
               | Lisp_ since it's not a top-10 language. "Lol just use
               | Python it's the second best at everything," is a common
               | refrain to people who are trying in earnest to learn
               | something new and nonstandard for a change.
               | 
               | While I won't claim _nobody_ has been  "psyched out" by a
               | community of people for their language-learning choices,
               | I just don't think that this is something that happens
               | with Lisp particularly often. The subreddit r/Lisp is
               | predominantly Common Lisp, but more frequently than not
               | accepts viewpoints from Clojure, Scheme, Racket, and even
               | NewLisp programmers all in the same comment section,
               | without bickering.
               | 
               | As I said, if anybody wants to learn a new technology,
               | and that somebody is a social person, finding a
               | supportive community is important. If somebody going to
               | be a novice at a particular language, and broadcast
               | opinions about that language on disparate forums--some
               | opinions which may come across as uninformed--sure,
               | people will likely come out of the woodwork to correct
               | them, suggest allegedly superior technology, etc.
        
           | alimov wrote:
           | Why is it disappointing? It's just a suggestion (take it or
           | leave it), and links out to an interesting and well written
           | article.
        
         | pmarreck wrote:
         | possibly because i've been playing with Guix lately, and also
         | because all the smartest people I know seem to use lisp-likes,
         | I'm on team "just use a Lisp" (possibly with some sort of API
         | interface to Python)
        
         | gilch wrote:
         | No closures? Hasn't it always had them?
        
         | catchclose8919 wrote:
         | Which CL "interactive development" feature can't you get with
         | either a jupyter notebook or ipython + autoreload enables? With
         | a smart editor like VSCode or Spyder you also get visual
         | variable inspections, history of executed code in one way or
         | another etc. Only that can't easily save an "image" auto-
         | magically, but data science and ML people wouldn't want to do
         | this other than explicitly (eg. using fast loading formats like
         | feather to reload semi-processed vars etc.).
         | 
         | I don't think you are aware how much the Python workflows of AI
         | / ML / datasci people resemble you "common lisp ideal" ...but
         | with a different language and better libraries :)
         | 
         | And if Julia succeeded, it will also bring decent performance
         | to such workflows.
         | 
         | Sure, the way backend devs or devops people use Python is very
         | static and different, but any experienced ML practitioners are
         | at home with "interactive development".
        
           | reikonomusha wrote:
           | Re-define a class and have all objects automatically get
           | updated to reflect the changes.
           | 
           | Evaluate arbitrary expressions mid-stack trace.
           | 
           | Run into a bug, get caught in an error, re-define the
           | offensive function interactively, and re-run the computation
           | before that point, _all without stopping and restarting_.
           | 
           | (Example real-world use-case: You re-define one of your REST
           | API endpoints without having to restart your server or
           | interrupt the request-flow, be it in test or--if you so
           | desire--in prod.)
           | 
           | Change the class of an object at run-time.
           | 
           | Re-compile and re-load individual functions _from your editor
           | with your production, git-committed code_. This one is huge.
           | You use interactive and incremental development to, well,
           | _develop_! Not side-by-side with your code, but in your code
           | as well, at a fine-enough grained level.
           | 
           | Common Lisp was _designed_ to be both interactive and
           | incremental. It 's not a bolt-on feature.
           | 
           | Jupyter notebooks and auto-reloading have a very different
           | feel, and (dis)incentivize different qualities and processes
           | of development.
        
           | vindarel wrote:
           | This set of jupyter + autoreloads + editor features might get
           | you close, but you won't be on par to CL's level. I'm
           | thinking about CL's interactive debugger, and about language
           | features that were thought with interactivity in mind. On an
           | error, you get the interactive debugger, you can explore the
           | stack frames and get to the erroneous function, change it,
           | recompile it, come back to the debugger and ask it to resume
           | progress from this point, and see execution pass. You didn't
           | have to re-run the whole operation. If we can do that in
           | Python, I've been in my cave for too long^^ As such, this is
           | how debugging a complex program looks like in Python vs in
           | CL: https://lisp-journey.gitlab.io/images/debugging-python-
           | VS-li... (Ravenpack [1] is a company that does big data
           | analysis and that uses CL, they gave some talks, maybe you'll
           | find more practical reasons from them)
           | 
           | for the second point:
           | https://mikelevins.github.io/posts/2020-12-18-repl-driven/
           | 
           | There might be more CL libraries than you think:
           | https://github.com/CodyReichert/awesome-cl but I'm not that a
           | zealot to say you can ignore Python's ecosystem, especially
           | in certain areas...
           | 
           | [1]: https://www.ravenpack.com/
        
           | throw10920 wrote:
           | In addition to the comprehensive answers of reikonomusha and
           | vindarel, I'll give you some specific things you can't do:
           | 
           | Jupyter notebook: you can't run it as normal code - that is,
           | you can't import your notebook from another file. You also
           | can't evaluate arbitrary regions of the notebook (it's cells,
           | the whole thing, or nothing), or nested sub-expressions. You
           | can't evaluate code in parallel - if you have a cell calling
           | a function foo() in a loop, and you try to redefine foo() in
           | another cell - impossible in Juypter, trivial in CL.
           | 
           | iPython + autoreload: you also can't redefine a foo() in a
           | file when it's being called in a loop, docs state "reloads
           | modules automatically before entering the execution of code
           | typed at the IPython prompt". You don't get any sort of
           | interactive debug-and-fix-up when you encounter an error. And
           | so on.
        
             | breuleux wrote:
             | For the record, I have written a reloading library for
             | Python called jurigged[0] that works on normal Python code
             | and can indeed replace foo() when it's being called in a
             | loop. There is also a way to do debug-and-fix-up, but only
             | if you specify restart points in advance, unfortunately.
             | 
             | It is probably still a good deal more limited to what can
             | be done with CL, there are no miracles here, just saying
             | the gap may not be that big.
             | 
             | [0] https://github.com/breuleux/jurigged
        
           | omaranto wrote:
           | I don't think it's fair that you got down-voted for not
           | knowing what Lisp-style interactive development offers beyond
           | what ipython or jupyter offers. Many people don't know either
           | and the proper response would be to explain, not to down-
           | vote.
           | 
           | EDIT: I was made aware of the guidelines to not comment on
           | voting, I apologize.
        
             | throw10920 wrote:
             | > Please don't comment about the voting on comments. It
             | never does any good, and it makes boring reading.
             | 
             | From the HN guidelines at
             | https://news.ycombinator.com/newsguidelines.html
        
               | [deleted]
        
         | peatmoss wrote:
         | Hy is cool because it allows people to explore some lisp
         | concepts in context of libraries they may already be familiar
         | with. And Python has an enviable set of batteries. But compared
         | to CL or Racket, Python's performance is a bitter pill to
         | swallow.
        
           | Kodiologist wrote:
           | Even with PyPy, or Python libraries that are themselves
           | written in C?
        
             | mrtranscendence wrote:
             | PyPy won't be a candidate in some scenarios (nor is it
             | always _that_ much faster), and even libraries written in C
             | leave some performance on the table when Python is the glue
             | language. Don 't get me wrong, I'm hardly ever in a
             | position where Python limits me from a performance
             | perspective ... there's always Cython. But it could be
             | better.
        
               | masklinn wrote:
               | There's also a new kind on the block with mypyc, though
               | it's pretty much pre-alpha and I assume it comes with a
               | very long list of limitations.
        
       | adenozine wrote:
       | There's also https://github.com/basilisp-lang/basilisp
       | 
       | If you desire a path closer to clojure
        
         | chrisrink10 wrote:
         | Hey! I'm the author of Basilisp. Thanks for the mention here!
         | 
         | Basilisp is much less mature than Hy but tries to stay
         | generally compatible with Clojure, which is somewhat different
         | than the goals of the Hy project.
        
           | Kodiologist wrote:
           | Cool, I'm a Hy guy; glad to meet you. Hy in its early years
           | imitated Clojure syntax much more closely, and Clojure
           | compatibility may've been implicitly a goal even if it never
           | got to the point of cross-testing. These days we prefer to
           | think of Clojure as one of several possible influences.
        
             | chrisrink10 wrote:
        
       | natrys wrote:
       | This encouraged me to go back and get a two year old small
       | project up to scratch with current Hy:
       | 
       | https://github.com/natrys/ghdl
       | 
       | I definitely had fun writing that in Emacs/hy-mode. And indeed
       | having access to Python ecosystem is neat. However, if I may:
       | 
       | - I didn't get to use any intellisense, which was quite painful.
       | Is there any Language Server for Hy now?
       | 
       | - I think Hy tends to break with every Python minor release,
       | which is a bit annoying. Stable is still broken on 3.10, and
       | alpha is a big change.
       | 
       | - This one might be a matter of subjectivity but I felt that Hy
       | is trying to be more "pythonic" and less "lispy", and I am not
       | sure what to feel about that. For example, familiar things like
       | `&kwargs` or `&optional` seems to have got replaced with
       | something less familiar (particularly, change to `#**` for
       | keyword arguments spurred this though).
        
         | Kodiologist wrote:
         | 1. Nope, sorry.
         | 
         | 2. That's right. Hy depends much more on finicky details of
         | Python than most Python packages do, particularly Python's AST,
         | so each 3.x release of Python usually requires some changes to
         | Hy to support it. Each Hy release supports (at least) all
         | versions of Python 3.x that have been fully released and are
         | not yet at end of life.
         | 
         | 3. More precisely, we're trying to take more of our conventions
         | from Python rather than Clojure. See
         | https://news.ycombinator.com/item?id=31250992
        
           | gilch wrote:
           | Not Intellisense, but there is jedhy:
           | https://github.com/ekaschalk/jedhy which can do completions.
           | Last Hy version verified working for: Hy 0.16.0
        
         | gilch wrote:
         | Hissp is an alternative approach. Unlike Hy, which compiles to
         | Python AST, Hissp compiles to Python, so it doesn't break with
         | every Python release.
         | 
         | Its read language (Lissp) doesn't have an Emacs mode (yet), but
         | its syntax is so close to traditional Lisps that lisp-mode
         | pretty much works. No completions either. There is Lily
         | https://github.com/mjobuda/damascus-tools/tree/main/lily, which
         | proved Jedi works on Lissp, but it's never quite worked right.
         | 
         | Hissp leans more Lispy than Pythonic compared to Hy, but still
         | prioritizes interop, so the object model is still Python's.
        
       | potta_coffee wrote:
       | I haven't used Hy for anything serious but I've poked around with
       | it before and it's loads of fun.
        
       | jhbadger wrote:
       | Have they ever fixed the problem with let not being implemented
       | (which was the case when I looked at it a couple of years ago).
       | Lisp-like languages without let lose a lot of the inherent power
       | of lisps.
        
         | EnderShadow8 wrote:
         | This might be interesting https://pypi.org/project/scoping/
        
         | Kodiologist wrote:
         | It's been implemented, found to be subtly broken, and re-
         | implemented a number of times. Ultimately trying to impose a
         | different model of scoping on top of Python's scoping is living
         | in a state of sin; thus the difficulties. The status quo is an
         | apparently working `let` due to a truly heroic effort by Sunjay
         | Cauligi ( https://github.com/hylang/hy/pull/2125 ). You're
         | encouraged to try to find bugs in it.
         | 
         | In truth, I've never understood the fuss about `let`. It's
         | taken a huge amount of Hy development effort, but it adds very
         | little. Python's native scoping works well in the large
         | majority of cases, and in tricky cases, I'd rather use
         | `nonlocal` or `global` explicitly so I'm sure what's happening
         | at the level of Python semantics. I suspect that people who
         | heard that previous versions of Hy were missing `let` assumed
         | that some other feature (such as nested lexical scopes) was
         | also missing that has actually always been there.
        
           | contravariant wrote:
           | What problems did you encoutner implementing 'let'? Shouldn't
           | it be equivalent to lambda expressions somehow?
        
             | Kodiologist wrote:
             | In some other Lisps, yes, but Python has its own idea of
             | how function scoping works that generally isn't what you'd
             | want with `let`. For example, in                   (let [a
             | 1]           (defn foo []             (setv a 2))
             | (foo)           (print a))
             | 
             | you probably `2` to be printed, but the seeming equivalent
             | Python code                   a = 1         def foo():
             | a = 2         foo()         print(a)
             | 
             | prints `1`. Python interprets the assignment as declaring a
             | new local variable. Frankly, Python got scoping wrong (in
             | its quest to eliminate declarations), but here we are. So
             | `let` needs to work around this somehow. The current
             | implementation implicitly adds `global a` or `nonlocal a`
             | as appropriate. (Actually, the name `a` is also mangled so
             | that any references to `a` outside the `let` refer to a
             | different variable.)
        
               | m45t3r wrote:
               | For me the example printing `1` makes sense because I
               | think `let` as being something immutable, so I wouldn't
               | expect `setv` to mutate that variable (would expect
               | either a compiler error or the introduction of a new
               | local variable).
               | 
               | But maybe it is because I am familiar with Clojure (where
               | `setv` or equivalents doesn't exist) and not other Lisps.
               | 
               | This would be the equivalent Clojure code anyway:
               | user=> (let [a 1] (defn foo [] (def a 2)) (foo) (println
               | a))       1       nil
               | 
               | So yeah, makes sense for me. But can understand why some
               | other people would expect the other way though.
        
               | gilch wrote:
               | Equivalent in Common Lisp:                   * (let ((a
               | 1))             (defun foo ()               (setq a 2))
               | (foo)             (print a))                  2         2
        
               | ashtonbaker wrote:
               | this made me wonder - I know I can use global variables
               | inside a function definition:                   a = 1
               | def foo():           x = a         foo()
               | 
               | so if this 'a' is a new variable, what happens when the
               | name collides with a global variable?                   a
               | = 1         def foo():           a = a         foo()
               | > UnboundLocalError: local variable 'a' referenced before
               | assignment
               | 
               | yuck!
        
               | all2 wrote:
               | I'm not sure this is so much of a problem? Changing what
               | you name the variable fixes the issue.
               | 
               | Python is generally quite good at having a verbose option
               | to express things, so I'm surprised there's not an
               | explicit way to reference the enclosing scope from an
               | object.
        
               | vegai_ wrote:
               | Is there any non-horror piece of code where supporting
               | this latter case would be useful?
        
               | m55au wrote:
               | It is not a particularly good example. A better one would
               | be                   a = 1         def foo():           x
               | = a           a = 2         foo()              >
               | UnboundLocalError: local variable 'a' referenced before
               | assignment
               | 
               | Basically a name cannot be both global and local inside
               | the same function. Otherwise it would be a total mess.
               | 
               | "a = a" just means assign the value of local variable "a"
               | to a local variable "a", so the error makes sense.
        
               | gilch wrote:
               | It works if you disambiguate your namespaces:
               | >>> a = 1         >>> def foo():         ...     a =
               | globals()['a']         ...     print(a)         ...
               | >>> foo()         1
               | 
               | Still yuck?
        
               | baq wrote:
               | it kinda sorta works when wrapped in a function
               | def f():           a = 1           def g():
               | nonlocal a               a = 2           g()
               | print(a)
               | 
               | though nonlocal can't be used when referring to global
               | variables... it's kinda bad.
        
               | gilch wrote:
               | You can still use `global` though.
        
           | vaylian wrote:
           | > In truth, I've never understood the fuss about `let`. It's
           | taken a huge amount of Hy development effort, but it adds
           | very little
           | 
           | My use case is Jupyter notebooks. With normal Python scoping
           | you quickly accumulate a lot of global variables and you
           | might accidentally use the wrong one. With let-bindings you
           | have variables that clean up after themselves.
        
             | Kodiologist wrote:
             | I'm not familiar with Jupyter internals, but I think
             | functions would work well for this. Hy allows multi-
             | statement anonymous functions, and you can do stuff like
             | `((fn [] ... ))` to define and immediately call the
             | function. One advantage of this over `let` is that it
             | allows old locals to be garbage-collected. If memory isn't
             | an issue, though, `let` should work well.
        
         | mark_l_watson wrote:
         | They are working on improving it. I wrote a short little book
         | on Hy and I initially used the "let" macro. I stopped using it
         | because in general Hy code can be automatically translated to
         | very readable Python code, but using the "let" macro generates
         | ugly Python code.
        
         | rcarmo wrote:
         | It's sort of back, implemented as a macro. I've yet to go back
         | to Hy (I left because of the removal of let, plus other things
         | I found missing), but I try it every now and then and the last
         | time I did the namespacing was still a tad weird.
        
           | gilch wrote:
           | Have you tried Hissp yet?
        
       ___________________________________________________________________
       (page generated 2022-05-03 23:01 UTC)