News for hackers. Stuff that matters.
Re:Why Hy? by jhbadger on Tuesday May 03, 2022 @09:36AM (#31248127)
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.
Re:Why Hy? by Kodiologist on Tuesday May 03, 2022 @10:03AM (#31248445)
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.

Re:Why Hy? by vaylian on Tuesday May 03, 2022 @10:52AM (#31249094)
> 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.

Re:Why Hy? by Kodiologist on Tuesday May 03, 2022 @10:59AM (#31249177)
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.
Re:Why Hy? by contravariant on Tuesday May 03, 2022 @10:24AM (#31248688)
What problems did you encoutner implementing 'let'? Shouldn't it be equivalent to lambda expressions somehow?
Re:Why Hy? by Kodiologist on Tuesday May 03, 2022 @10:35AM (#31248845)
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.)
Re:Why Hy? by m45t3r on Tuesday May 03, 2022 @02:06PM (#31251456)
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.
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:04PM (#31252893)
Equivalent in Common Lisp:

    * (let ((a 1))
        (defun foo ()
          (setq a 2))
        (foo)
        (print a))
    
    2
    2
Re:Why Hy? by ashtonbaker on Tuesday May 03, 2022 @11:02AM (#31249195)
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!
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:23PM (#31253107)
It works if you disambiguate your namespaces:

    >>> a = 1
    >>> def foo():
    ...     a = globals()['a']
    ...     print(a)
    ...
    >>> foo()
    1
Still yuck?
Re:Why Hy? by gilch on Wednesday May 04, 2022 @06:22PM (#31266628)
Here's another way to do it:

  >>> def foo():
  ...     import __main__
  ...     a = __main__.a
  ...     print(a)
  ...
  >>> foo()
  1
Re:Why Hy? by all2 on Tuesday May 03, 2022 @03:40PM (#31252562)
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.

Re:Why Hy? by vegai_ on Tuesday May 03, 2022 @03:40PM (#31252568)
Is there any non-horror piece of code where supporting this latter case would be useful?
Re:Why Hy? by m55au on Tuesday May 03, 2022 @03:47PM (#31252657)
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.

Re:Why Hy? by baq on Tuesday May 03, 2022 @03:56PM (#31252801)
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.
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:20PM (#31253074)
You can still use `global` though.
Re:Why Hy? by rcarmo on Tuesday May 03, 2022 @09:48AM (#31248264)
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.
Re:Why Hy? by gilch on Tuesday May 03, 2022 @03:52PM (#31252738)
Have you tried Hissp yet?
Re:Why Hy? by mark_l_watson on Tuesday May 03, 2022 @10:07AM (#31248480)
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.
Re:Why Hy? by EnderShadow8 on Tuesday May 03, 2022 @10:01AM (#31248425)
This might be interesting https://pypi.org/project/scoping/