Hacker News new | past | comments | ask | show | jobs | submit login
Some thoughts on hylang (2017) (beatworm.co.uk)
45 points by asimjalis 30 days ago | hide | past | web | favorite | 24 comments



Hy feels all wrong to me, though I really wanted to like it, and I put some time in when I tried it.

Part of it is that it compiles to Python bytecode, and took the simplest route of adopting Python's not at all lisplike scope. With `let`, you have a visual clue of variable scope; Hy had a broken `let`, and then got rid of it completely. Now it looks like there's a new `let` that might make more sense. I haven't used it in a couple years.

But that's not the only problem. It has the same feeling I get from Clojure and the various lisps that compile to javascript; it just doesn't feel divorced enough from its parent language to be satisfying in itself. I'd rather write lisp than Python, sure, but except for a few libraries I'd like to be able to use, I don't see much reason to prefer Hy over Racket or some other similarly-mature Scheme, which would have somewhat fewer libraries, but would feel like a consistent and self-contained language.


I wonder if you might like "Burgled-Batteries" [0], which gives you access to Python objects from Common Lisp. I have not tried it myself, and it does not yet support CLOS integration, but it looks pretty interesting.

[0] https://www.cliki.net/burgled-batteries


I suspect the problems of Hy are caused precisely by not compiling to bytecode, but to Python abstract syntax. I suspect that a Lisp that bypasses this syntax and goes right to bytecode could do things better: have a real let and such.


I feel the same way. I found a nice Hy LSTM demo that uses TensorFlow and had fun playing with that. I did another night of hacking around with Hy and put it in the ‘really interesting, revisit later’ category.


>It's a lisp that compiles? (transpiles? I never get the difference)

I've seen others make the same claim. How's the difference difficult to get. It might not be 100% clear-cut and have some edge cases, but in common parlance:

Compile -> compiles to executable machine code (or executable bytecode for your VM).

Transpile -> produces code in another language (which is then compiled or interpreted or whatever).


I make no shame of it. I am an imperative programmer at heart. Hy is beautifully imperative.

return/if/while/break/continue actually work in Hylang. Common Lisp doesn't have these. Scheme purists won't let you have them. Clojure obviously doesn't have them.

Let that sink in.

The fight against imperative programming has come so far that we banned not just goto but every commonly used control flow primitive. We have banned global variables too and FP purists want to go even further and remove the assignment operator. What is a monad exactly if not the ";" ? What is the end result except more confusing code ?

Hylang is a completely distinct lisp and breaks the tradition of all lisps before it. Sibilant is another lisp which does the same but for javascript.

What does Hylang do ? It translates almost 1-1 the features of Python onto itself and its a transpiler if I am not mistaken. So you get all the features and libraries of Python without much fanfare. This is such a good idea that we need a C++ version of Hylang.

Now if we could get rid of the parens and have begin and end or something like "if .. fi" like civilised folks, that would just be perfect.


> return/if/while/break/continue actually work in Hylang. Common Lisp doesn't have these.

It has all of them!

Return:

    CL-USER> (defun foo () (return-from foo 1) 2)
    → FOO
    CL-USER> (foo)
    → 1
If:

    CL-USER> (if t 1 2)
    → 1
    CL-USER> (if nil 1 2)
    → 2
While:

    CL-USER> (let ((x t))
               (loop for j from 1 to 10
                     while x
                     do (when (= j 3)
                          (setf x nil))
                     collect j))
    → (1 2 3)
Break:

    CL-USER> (loop for i from 1 to 10 do (format t "~&i: ~a~%" i) when (> i 4) do (return) do (format t "~& -~%"))
    i: 1
    -
    i: 2
    -
    i: 3
    -
    i: 4
    -
    i: 5
    → NIL
Continue:

    CL-USER> (do ((i 1 (1+ i))) 
                 ((> i 10))
               (format t "~&i: ~a~%" i)
               (when (= i 4) (go end))
               (format t "~& -~%")
               end)
    i: 1
    -
    i: 2
    -
    i: 3
    -
    i: 4
    i: 5
    -
    i: 6
    -
    i: 7
    -
    i: 8
    -
    i: 9
    -
    i: 10
    -
    → NIL
Common Lisp has goto, has traditional control structures and can be as imperative as you like.


I made a mistake of mentioning Common Lisp in the same line. Common Lisp has pointers (cons) as well.

Hylang doesn't have goto, as Python doesn't have it.

Well you can always implement a goto by having

1. A list made of lambdas. List gives numeric addresses. Dict will give you named addresses.

2. Pass the above list itself to each of the lambda or make it a global variable called ADDRESSES.

No one talks about the cool imperative features of Common Lisp right ? The was the point I was trying to make.

Scripting is imperative.

Python is a scripting language .. right ? That makes Hylang a scripting language too. Hylang is (Python).


Not disputing the central point, imperative is ok, but Common Lisp has all of it in one or other way - It's pretty much imperative, indeed.


Having started with C at college and then moving onto Common Lisp on my own was a massive headscratch when I first started. I abandoned lisp after that. Common Lisp has tagbody and go of course ... but there is so much shame around it. Why ?

How did people learn sh, perl, ruby, python ? By writing dumb imperative scripts of course! Why the shame ?

Even from a cursory glance Hylang has more libraries than all the lisps combined. FACT. I think it fits perfectly for scripting tasks and for a change its easier for beginners to get started with. ipdb works with hylang folks!

I had to google it. Remember Liskell ? The Lisp that mapped onto Haskell ? I think Hylang and Sibilant should be treated as minimal lisps along the same lines. As compared to Common Lisp .. Hylang is worse and that can only be a good thing.


>The fight against imperative programming has come so far that we banned not just goto but every commonly used control flow primitive.

Not really. We have not banned them from anywhere, except where they were not part of the culture (e.g. Scheme -- and even there you can use them trivially).

Almost all working professional programmers (say, 99% of them, aside a statistically insignificant percentage working professionally with Haskell and Lisp and F# and so on) use for, while, if, exceptions, and so on. Hardly "banned".

>We have banned global variables too

And for good reason.

>and FP purists want to go even further and remove the assignment operator

Your initial data and constants need to come from somewhere, so nobody bans the assignment operator. But if you can avoid mutations, sure.

>What is the end result except more confusing code ?

Clearer code that you didn't took any time to study the concepts of to understand?

Having to know fewer concepts to use a language is not the same thing as the code being easier to understand.

A language with fewer concepts can lead to weak expressibility, so you need to e.g. write 100 lines to do what another does in 5, and with their intention more explicit in the code.

For an extreme example, consider how easy it is to understand a piece of code doing the same thing in assembly and in C. The C code will be much easier to follow, despite requiring you to learn more language constructs.

And inversely, a BASIC programmer could say the same things you said, but about, say, Python: "Why do we need all those language features, aren't line numbers and GOTO simpler?"

If learning 5 new concepts makes it possible to handle the same functionality in half the code, understand old codebases better, and write the same thing with less bugs, then those 5 concepts lead to simpler code -- even if they add to what someone already knows.

>What is a monad exactly if not the ";"?

Tons of other things.


> return/if/while/break/continue actually work in Hylang. Common Lisp doesn't have these.

Don't know where you get your facts from, but Common Lisp certainly has those.


This is how it looks in Hylang because it maps onto Python semantics.

  (for [element (range 1 10)]
    (print element)
    (if (= element 5)
      (break)))
I prefer this over Common Lisp because it looks shamelessly imperative.


are you sure you have ever used Common Lisp? Maybe you were thinking about a different language.

  CL-USER 51 > (loop for element from 1 upto 10 do
                     (print element)
                     (if (= element 5)
                         (return)))

  1 
  2 
  3 
  4 
  5 
  NIL


I have not used CL. I was horrified by the loop macro infact because I jumped from C to CL.

I definitely made a stupid mistake of clubbing CL with scheme and clojure but in those languages they avoid these imperative features.

I have made other points as well which makes Hylang different from the rest.

1. Hylang is a transpiler. Don't compare it with other lisps. Sibilant and Liskell are others in the same league.

2. Hylang has more useful libraries than all the other lisps.

3. Right now, I find Hylang best suited to write good old imperative dirty scripts that get stuff done. If you have used Python, Ruby, Perl ... it's practically heaven.

4. I stress the imperative part again because ... because that's my stupidity of choice. I'm a scripting guy! I'm familiar with that stuff. The best part of lisp for me is not the macros. It's that I don't have to google for syntax that often and "-" beats the "_" for variable names.

5. ipdb works too!


> I was horrified by the loop macro infact because I jumped from C to CL.

But you are aware that the FOR loop code you posted looks almost exactly like the LOOP FOR code in Common Lisp?


> return/if/while/break/continue actually work in Hylang. Common Lisp doesn't have these. Scheme purists won't let you have them.

Common Lisp does have them, as does. Scheme purists will let you have pretty much whatever imperative control structures you like (that's what macros are for), but you would be right if you said that none of the Scheme standards mandate simple equivalents for all of those (though since Scheme looping is usually recursive—which is perfectly imperative—“break” is usually just not recursing.)

> The fight against imperative programming has come so far that we banned not just goto but every commonly used control flow primitive.

Well, they weren't banned, Hough of course you won't find them in pure functional languages like Haskell. But CL and Scheme and Lisp-family languages with strong roots in those have robust imperative controlled structures and the foundations for building more if you need them.


The monad does enable imperative programming in Haskell, yes. But it is not needless complexity. It enables an imperative program to be assembled using a pure functional program. Imperative statements become first class values, control flow constructs can be just user-defined functions, no macros needed. Monads, of course, also allow us to change the meaning of a semi-colon. This can be used, for example, to implement lightweight fiber threads with custom schedulers, again all without macros.

It has been said that Haskell is the world's best imperative programming language: https://stackoverflow.com/questions/6622524/why-is-haskell-s...


Meh, continue seems like a weird keyword to use, since it means you act on a "negative" condition. If this is true, skip the rest. Most code like thay could just be inverted and be perfectly readable.

For when you really need it, you could just use a block in CL and emulate it using return-from. Return and break are really the same thing, and don't really need to be separate.

CL is really an imperative language as well, it is just that it doesn't force you to be imperative to return things from an if or such things.

Scheme is a different beast. Since it provides you with the mother of all control structures (call/cc or prompts in guile/racket) mutability isn't really good if you want safety.


"posted by cms on 2017-12-31". Has anything significant changed since then?


So: (2017)


Missing some olde lisp things like car/cdr/lambda

A quick perusal of hylang.org didn't reveal how a Lisp works without cdr. I'm envisioning something awful with a colon...


more likely car = first and cdr = rest.





Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: