HNHacker News
TopNewBestAskShowJobs

zenhack

684 karma · joined June 20, 2017

[ my public key: https://keybase.io/isd; my proof: https://keybase.io/isd/sigs/sp25K1JliIwzg06OIG9xoMjX6G7YxK3taKIPr-hp2MI ]
submissionscomments
zenhack··on JavaScript Promises Discussion: Make Them Monadic? (2013)
First, going straight to "How do I understand Monads?" is not a good idea. I remeber when this article showed up on the web, and I remember wishing it had been written before I started learning Haskell:

https://byorgey.wordpress.com/2009/01/12/abstraction-intuiti...

If you want to understand monads, start hacking and watch for patterns.

> But, just to be super honest -- and possibly completely wrong -- the terminology is really off-putting. At a glance it just feels super complex, academic and completely divorced from practical coding. I get vibes of enterprise java class hierarchies looking at this stuff.

Yeah, and here's my take on why it looks like that:

First, the terminology is all borrowed from mathematics, hence the academic tone. People can debate on the merits of this; I think it makes more sense when you're making tools for folks who are already familiar with the usual notation, but e.g. if you're not dealing with people who are already accustomed to the way physisicts talk about things, "p" is probably not the best variable name for momentum, traditional as it may be.

The authors of that document seem to have gone even farther in that direction than the Haskell folks -- Setoid? really? It's just fing equals! even Haskell calls it Eq. At least they kept Ord.

Also, the design looks to be basically transliterated from Haskell. There's been no attempt to adapt it to either javascript's strengths or its weaknesses. For example: Conceptually a monoid is a special case of a category, but it's fiddly to abstract out the commonalities in Haskell because of the way the type system works. In javascript you could basically collapse the two, with id == empty and concat == compose. You might still want a blurb in there somewhere about the differences; not every category is a valid monoid, but there's no reason to have a whole separate hierarchy with different method names. * The whole TypeRep thing they talk about is a complication that is unnecessary in Haskell; having methods that aren't attached to an extant value is just a non-issue, because the compiler can figure out which one you mean based on the types.

The libraries were designed around Haskell, and they lose something in translation. One of the things that kept in that thread was why not build some experience using these patterns before writing a spec? I tend to agree.

The other thing is that it is a big pile of abstractions. Even when working in Haskell, though I am more or less familiar with all of the type classes on that chart, I've only really had call to use 9 of them. Including Eq(Setoid) and Ord. The abstractions can definitely get to be a bit much.

There is some real use for this stuff; here's one I find kindof shiny:

https://apfelmus.nfshost.com/articles/monoid-fingertree.html

...but I would say these abstractions are as applicable to day to day programming as the rest of computer science -- no more and no less.

I'm with you on the complexity allergy thing. Lately I've been doing some stuff in elm[1], and the simplicity has been a wonderful breath of fresh air coming from Haskell. I might recommend it if you're curious about functional programming. Some of the same ideas are sprinkled throughout the libraries; every time you see a function called "andThen," there's a monad lurking there, but because elm doesn't have type classes, you won't find anything called Monad. The flip side is you end up writing more boilerplate than you would in a language that can abstract these things away.

[1]: http://elm-lang.org/

zenhack··on A Brief Glance at How Various Text Editors Manage Their Textual Data (2015)
I do most of my work on a laptop with 4GiB of memory (manufactured in 2009). Probably the last time I did anything dev related that meaningfully stressed the machine was when I decided to give android studio a shot.

Just sitting there, with nothing else open, the machine was completely unusable.

I cannot recall anything else I have done with the machine in it's lifetime that's been a real problem.

This includes running firefox and chromium concurrently, plus a couple virtual machines .

zenhack··on C++ and the Culture of Complexity (2013)
Also, if you really want to write code that's agnostic to whether you're working directly on the DB object or a transaction, you can just declare that interface yourself; it's not like in java where the implementing class has to opt in.

The absence of the interface being predeclared for you does mean more boilerplate, but I agree that transactional vs. not doesn't strike me as a good thing to be hiding; this particular case seems like maybe a very reasonable omission. I try to avoid abstractions that leak.

zenhack··on A Letter from Dijkstra on APL (1982)
While I agree with your point about the keyboard, I'm not actually sure that's what EWD was on about. He famously thought people should be learning to program without actually using a computer. My reading of the letter is that the complaint is about needing a computer at all.
zenhack··on Kotlin: The Problem with null
That doesn't do quite the same thing; the original example gets rid of the Maybe, defaulting to 0.
zenhack··on Kotlin: The Problem with null
Rice's theorem is a bit more direct here: C is Turing complete, some C programs derefernce null pointers, and some don't. Therefore, the question of whether a an arbitrary C program derefernces a null pointer is in general undecidable.

But I don't think the Op was claiming it was possible to do this perfectly, just possible to write very useful tools. You will always have either flase positives or false negatives (or I suppose inputs where you just hang).

Turing completeness is the bane of static analysis, but that doesn't make it a fruitless endeavor.

zenhack··on Kotlin: The Problem with null
Or just:

    fn (Just q) (Just z) = q + z
    fn _ _ = 0
zenhack··on Why I'm suing Google
Fair.
zenhack··on Why I'm suing Google
> Not really. Did you actually read the memo?

The sentence immediately following your quote:

> (e: Yes, I've read it several times for those who question it)

zenhack··on Breezy: Forking Bazaar
(Queue semi-weekly flamewar re: modifying history)

It would be nice to see the foss vcs monoculture shaken up a bit. There are lots of neat tools out there (fossil is pretty cool), but having an established workflow and a ton of users is worth so much for a collaborative tool.

zenhack··on Casting in ATS
It isn't just that ATS is understaffed. I gave up trying to contribute because I got tired of getting active pushback on basic style issues that I would expect CS undergrads to have figured out by the end of their first semester.

Case in point:

https://github.com/githwxi/ATS-Postiats/pull/35#issuecomment...

Seriously, "When the dust settles, we will think of better names ..."

Hongwei is a great researcher, but he hasn't displayed particularly good judgment wrt. software engineering, and no amount of external contributors can fix problems that come down to a maintainer who actively pushes bad practices. It was almost heartbreaking to walk away from ATS for me, but I came to the conclusion that I just wasn't going to be able to fix the things that needed fixing while Hongwei was making decisions like these.

At (IIRC) Hac Boston 2012, Edwin Brady gave a talk on what was at the time a very work-in-progress version of Idris. There were several points during the talk where he went to demo some basic feature in the repl, got some nasty error message, and went "oh right, I haven't implemented that yet." But even then, it felt more polished than ATS does now.

zenhack··on Casting in ATS
ATS compiles down to C, so I suspect they're just leaning on C's implicit coercions. Yeah, it's a bad example.
zenhack··on Casting in ATS
Executive summary: ATS has a much more powerful type system, but from a human factors standpoint suffers from death by 1000 papercuts. Rust is much more usable as a tool, but very intentionally only pulls ideas from established research, and is somewhat more limited in what the type system can do.

Lifetimes (typically referred to as "regions" in the literature) come most directly from Cyclone (which first applied Tofte & Talpin's work on regions for ML-ish languages to the systems space). Type-level ownership tracking goes back to ATS (or possibly one of its predecessors, not sure) as well.

What rust does well is package up a lot of this knowledge into something that's actually a usable tool. The ATS compiler spits out some of the worst error messages I've ever seen, and while Xi has done some really incredible groundbreaking stuff, he doesn't have the kind of design sense that it takes to make tools that developers can actually use. It's the little stuff, really -- error messages, tooling, documentation. Some of the instructional material reads like stream-of-conciousness, and clearly doesn't have a specific audience in mind:

http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/...

The biggest fundamental technical difference is dependent types. The Rust community has been flirting with some more limited forms of this; search for "const generics" to see what they're up to.

ATS's version of dependent types is of a different flavor than what's available in e.g. Idris/Agda/Coq, and not as powerful, but still able to do some really impressive things. There are still a lot of low-level tricks that folks regularly pull in C that can't be done in a type/memory-safe way in Rust, but can in ATS. This paper gives a neat example of converting an array to a linked list in-place, which I think is pretty mind-blowing:

http://www.ats-lang.org/MYDATA/SPPSV-padl05.pdf

It's also one of the better descriptons of what's special about ATS.

zenhack··on Wekan: An open-source Trello-like kanban
> I know self hosting is actually better but it is also work ...

Worth pointing out: they have a sandstorm version, which changes the amount of justification need rather a lot.

zenhack··on Why Python Is Not My Favorite Language (2016)
I'm generally skeptical of gradual/optional typing.

The reason is this: It's really, really hard to design a good type system after the fact. There are some pretty compelling theoretical reasons for this (Rice's theorem) and also a fair amount of history of mediocre results.

With OCaml/Haskell, not only do you get strong, static types, but the compiler can figure them out on its own. There's just no way that can happen for python.

I've seen more compelling gradual/optional type systems. Last I checked, MyPy still had structural types as a "someday" thing. This puts a huge percentage of python code in the position of basically needing to be rewritten to be usable with MyPy.

TypeScript has interfaces, and generally looks better put together to me.

Racket takes an interesting approach, where whole modules are either typed or untyped, and it's pretty strict about enforcing things at the border:

* If you import something from an untyped module into a typed module, you have to specify the type.

* If you call a typed function from an untyped module, the type is checked dynamically.

So you get much better guarantees.

Erlang's dialyzer takes an interesting approach -- rather than being a conservative type system (where if a program type checks it is definitely type-correct), it is optimistic, so it will only bother you if it's sure it's found a problem. This lets you graft it on to existing programs without having to do major refactorings of parts that don't fit. But you lose a lot of the assurance that way. Still, my impression is it sees wider adoption (as a percentage of Erlang users) than any of the conservative gradual type systems I've seen.

I haven't actually tried any of those beyond tens of minutes of playing around though.

zenhack··on Why Python Is Not My Favorite Language (2016)
I think this is pretty insightful. You won't find this kind of post about shells on my blog, despite being much worse for building "real software." Stuff like autotools is an exception, and I think it kinda enforces the point. I'd be much less annoyed with python if people stuck to quick and dirty scripts (and had the sense to use something else when their scripts got too big).
zenhack··on Why Python Is Not My Favorite Language (2016)
> In functional programming EVERY function is a single expression, including the main itself. In fact, in functional programming, your Entire program is just a single expression.

This is a technicality. There's basically always a mechanism for chaining two expressions and junking the result of the first. In OCaml, the semicolon operator does this. In Scheme (and most lisps) you can just put multiple expressions in the body of the function, and the return value will be the last one. And there's `begin` if you want a block that's not a function. In Haskell, the purity makes this actually not make sense in most contexts, but you've got `(>>)` for monads, and the do-notation which sugars it into something that looks basically like a statement.

Some version of that in python would be an acceptable alternative.

But there's also stuff like moving reduce to a separate package.

zenhack··on Why Python Is Not My Favorite Language (2016)
Yeah, I'm actually pleasantly surprised by the level of discourse; when I saw this was on the front page I was like "Oh god somebody linked /that/ post."
zenhack··on Why Python Is Not My Favorite Language (2016)
> WRT private class members, I can understand why this might be frustrating for library writers. But it's just so damned useful to be able to reach into a library and get functionality the library's writer didn't think I'd need, that I'll personally never consider this to be bad.

I can only really think of one instance where I've used this, and it was to work around an outright bug in the library (which was unmaintained, and I was using out of a certain amount of desperation).

FWIW, most of the complaints around private in my post would actually be solved just by having a separate namespace for "private," even if there was a back door. I'd be pretty willing to forgive that.

> Multi-line lambdas would certainly be nice, but most of it can be handled with a scope-level function.

In the absence of the with statement can you really imagine yourself writing this all the time:

    def _with_body(f):
        print(f)
        print("I am a teapot")

    with(open("foo.txt"), _with_body)
?

Strikes me as pretty ugly, despite not actually adding much code.

> As for syntax, no need to use Ruby's syntax, just incorporate parenthesis (a well established continuation construct within Python):

Yeah, that's a bit nicer.

> As for the example error - there is a typo. Of course it's going to throw a traceback. The error message is even more explicit than I expected, frankly. It pointed out the missing function name, which would make the typo rather easy to find.

Yeah, that was kinda my point; I was comparing this to what happens if you try to "take duck typing to heart", where you don't get the error until you try to call request. The earlier you find out about mistakes the better.

← PreviousPage 8 of 8