Live data from Hacker News

Hurl, a terrible (but cute) idea for a language

ntietz.com

41–50 of 84 posts

Re: Hurl, a terrible (but cute) idea for a language

#41
post #28

Earlier quoted context omitted.

Yep! Everyone should read https://overreacted.io/algebraic-effects-for-the-rest-of-us/ for how powerful this can be in practice. The caller gets to pause execution on the raising/hurling of an event - which makes many crazy things possible.

I feel like I must be missing something. It seems to me (just from reading this post) that if you need algebraic effects you’ve probably painted yourself into a corner and should probably reconsider your program’s architecture. It seems like a good way obscure what the code is really doing and end up with poorly organised spaghetti code. In the post he’s effectively making a function async while pretending it’s not,…

You're not missing anything. Algebraic effects are basically typed gotos†[1][2], and are generally a bad idea to use and/or implement. They can be useful in a few very niche situations when using typed functional languages.

† With added asynchronicity.

[1] http://community.schemewiki.org/?call-with-current-continuat...

[2] Some argue call/cc is, in fact, worse than goto: https://okmij.org/ftp/continuations/against-callcc.html

Re: Hurl, a terrible (but cute) idea for a language

#42
post #32
post #23

While cute this is really close to call/cc and/or algebraic effects as an abstraction for control flow, which isn't as much "cute" as it is "a powerful way to express programs in as few expressions as possible"

> express programs in as few expressions as possible I don't find this appealing on its face. Extreme terseness, even when done very elegantly, makes programs very hard to read and sometimes also hard to maintain. I suspect that's one of the reasons Lisps (and functional languages in general) haven't caught up in popularity even as it becomes much easier to adopt one for any target and in any organization.

> I don't find this appealing on its face. Extreme terseness, even when done very elegantly, makes programs very hard to read and sometimes also hard to maintain.

In that case, it's more about minimizing the language, rather than the programs. call/cc is a single instruction that is sufficiently expressive to implement e.g. exceptions, coroutines and lots of stuff for which people typically use monad-style embeddings.

Making the language easier to specify is generally a good thing, because it makes all forms of static analysis and compilation easier (at least theoretically) and because there are fewer places to hide bugs in the compiler/interpreter. Of course, you move the potential bugs to the libraries, but that's generally considered better, because it's easier to debug.

> I suspect that's one of the reasons Lisps (and functional languages in general) haven't caught up in popularity even as it becomes much easier to adopt one for any target and in any organization.

Well, to be fair, functional constructs have made it to pretty much all mainstream languages these days.

Re: Hurl, a terrible (but cute) idea for a language

#43
> Oh, also, functions cannot be recursive (without passing in a function to itself), because we won't have the function bound to a name in the local context when defining itself. Fun, right?

The startup accelerator that runs this forum is named after a pretty neat thing you can do with a language that only has anonymous functions:

https://en.wikipedia.org/wiki/Fixed-point_combinator

Re: Hurl, a terrible (but cute) idea for a language

#44
post #23

While cute this is really close to call/cc and/or algebraic effects as an abstraction for control flow, which isn't as much "cute" as it is "a powerful way to express programs in as few expressions as possible"

Generalized exception-throwing is pretty much the Common Lisp condition system.

Re: Hurl, a terrible (but cute) idea for a language

#45

This is very fun! I am only making suggestion because it rhymes with "hurl" (and it works well metaphorically for the repeating tossing/hurling): you could introduce a "whirl" keyword or part of the standard library as the way to handle loops. It could be functionally the same as your loop example but removes the self-referential first argument (i.e. whirl(count, [1,3])).

In my university, the slang term for an uninitialized variable was "dead squirrel". IIRC, some TA had described uninitialized C++ variables as follows: "It could be any value: zero, 100, or even a dead squirrel." If hurl ever allows uninitialized variables, I would love to see use of an uninitialized variable to `hurl` a `squirrel`! :)

Re: Hurl, a terrible (but cute) idea for a language

#46
post #42
post #32

Earlier quoted context omitted.

> express programs in as few expressions as possible I don't find this appealing on its face. Extreme terseness, even when done very elegantly, makes programs very hard to read and sometimes also hard to maintain. I suspect that's one of the reasons Lisps (and functional languages in general) haven't caught up in popularity even as it becomes much easier to adopt one for any target and in any organization.

> I don't find this appealing on its face. Extreme terseness, even when done very elegantly, makes programs very hard to read and sometimes also hard to maintain. In that case, it's more about minimizing the language, rather than the programs. call/cc is a single instruction that is sufficiently expressive to implement e.g. exceptions, coroutines and lots of stuff for which people typically use monad-style embeddings…

I believe the point was you can say the same about goto. With goto you can replace if/else, for loops, while loops, functions, exceptions, etc, making for a very minimal language. Yet structured programming is superior.

(I probably don’t know enough about call/cc to know if that’s a totally fair comparison, but languages being more restrictive/less flexible can be good overall in terms of aiding understanding/reducing bugs/etc)

Re: Hurl, a terrible (but cute) idea for a language

#47
post #28

Earlier quoted context omitted.

Yep! Everyone should read https://overreacted.io/algebraic-effects-for-the-rest-of-us/ for how powerful this can be in practice. The caller gets to pause execution on the raising/hurling of an event - which makes many crazy things possible.

I feel like I must be missing something. It seems to me (just from reading this post) that if you need algebraic effects you’ve probably painted yourself into a corner and should probably reconsider your program’s architecture. It seems like a good way obscure what the code is really doing and end up with poorly organised spaghetti code. In the post he’s effectively making a function async while pretending it’s not,…

Look at it less like a first class language feature and more like a language feature for implementing others in terms of it.

Re: Hurl, a terrible (but cute) idea for a language

#48
Or you can go all the way in the other direction (double- or triple-barreled CPS) and have functions that can't return but only call other functions.

    let fizzbuzz = func(ret, fizzbuzz, x, max) {
        (x == max)(ret, func() {
            let printed = false;
            (x % 3)(func (t0) {
                let k0 = func() {
                    (x % 5)(func (t1) {
                        let k1 = func() {
                            let k2 = func() {
                                (x + 1)(func (t2) {
                                    fizzbuzz(ret, fizzbuzz, t2, max);
                                })
                            };
    
                            (printed == false)(func () {
                                print(k2, x);
                            }, k2);
                        };
    
                        (t1 == 0)(func () {
                            print(func() {
                                printed = true;
                                k1();
                            }, "buzz");
                        }, k1);
                    });
                };
    
                (t0 == 0)(func() {
                    print(func() {
                        printed = true;
                        k0();
                    }, "fizz");
                }, k0); 
            });
        });
    }
    
    fizzbuzz($halt, fizzbuzz, 0, 100);

Re: Hurl, a terrible (but cute) idea for a language

#49
post #41

Earlier quoted context omitted.

I feel like I must be missing something. It seems to me (just from reading this post) that if you need algebraic effects you’ve probably painted yourself into a corner and should probably reconsider your program’s architecture. It seems like a good way obscure what the code is really doing and end up with poorly organised spaghetti code. In the post he’s effectively making a function async while pretending it’s not,…

You're not missing anything. Algebraic effects are basically typed gotos†[1][2], and are generally a bad idea to use and/or implement. They can be useful in a few very niche situations when using typed functional languages. † With added asynchronicity. [1] http://community.schemewiki.org/?call-with-current-continuat... [2] Some argue call/cc is, in fact, worse than goto: https://okmij.org/ftp/continuations/against-ca…

loops are typed gotos, so are if statements, so, really are functions.

Goto isn't bad, it's integral to programming. It's just too powerful, so we tame it in various ways. Algebraic effects are one of those ways.

Re: Hurl, a terrible (but cute) idea for a language

#50

> Oh, also, functions cannot be recursive (without passing in a function to itself), because we won't have the function bound to a name in the local context when defining itself. Fun, right? The startup accelerator that runs this forum is named after a pretty neat thing you can do with a language that only has anonymous functions: https://en.wikipedia.org/wiki/Fixed-point_combinator

You don't even need that, there is a much more efficient way in a language that supports let-bindings (but not letrec):

    let f' = func(f, g, other_args...) {
        // ...
        g(f, g, whatever...);
        // ...
    };

    let g' = func(f, g, other_args...) {
        // ...
        f(f, g, whatever...);
        // ...
    }

    let f = func(other_args...) { return f'(f', g', other_args...); }
    let g = func(other_args...) { return g'(f', g', other_args...); }
That's basically just closure conversion, only instead of doing it the compiler backend, you do it manually yourself.
Post reply on HN