HNHacker News
TopNewBestAskShowJobs

zeugmasyllepsis

158 karma · joined May 9, 2014

submissionscomments
zeugmasyllepsis··on Show HN: Corgi, a helpful {agent, terminal} multiplexer
I plan to look into this deeper today, but truth be told I saw the little animation at the top of the page and paused.

Throwing the ball and watching this little character run was truly a delightful interaction. For whatever part you had in its creation, thank you.

zeugmasyllepsis··on Accelerate Python code by importing Taichi
I was curious about node/jitless node versus python/pypy:

      src time node primes.js             
    78498
    node primes.js  1.75s user 0.05s system 102% cpu 1.761 total
      src time node --jitless primes.js
    78498
    node --jitless primes.js  5.06s user 0.04s system 100% cpu 5.088 total
      src time python primes.py
    78498
    python primes.py  4.27s user 0.03s system 100% cpu 4.276 total
      src asdf shell python pypy3.9-7.3.9
      src time python primes.py
    78498
    python primes.py  0.91s user 0.07s system 100% cpu 0.970 total
Actually relatively on par with one another.
zeugmasyllepsis··on Ask HN: What are some cool but obscure data structures you know about?
A GADDAG[1] is a combination pre-/suffix trie that's used for move generation in Scrabble. Unlike a traditional dictionary to find anagrams for words, a GADDAG makes it easier to identify plays based off of available letters already on the board. I made a little visualization of how they work for a data visualization class a few years back.[2]

[1] https://en.wikipedia.org/wiki/GADDAG [2] https://www.axioms.me/gaddag/#?page-5

zeugmasyllepsis··on Postgres 15 improves UNIQUE and NULL
Playing around in a docker image of the beta build, it looks like this allows you to add a `unique nulls not distinct` constraint to a composite set of fields, but still does not allow you to specify those same fields a primary key. For example

    -- This works
    alter table announcement_destinations
        add constraint announcement_destinations_pk unique nulls not distinct (sender, receiving_group, optional_filter);
but

    -- Still does not work
    alter table announcement_destinations
        add constraint announcement_destinations_pk2 primary key (sender, receiving_group, optional_filter);
fails with a message like "ERROR: column "optional_filter" of relation "announcement_destinations" contains null values". Is there a motivation for this distinction?
zeugmasyllepsis··on Scripting with Go
Curious, what is your argument in favor of a container over a type union to represent Result? As long as the type checking system forces users to refine the union to use the value and is aware of blocks of code within type guards (I've heard this referred to as "flow-aware typing" but I'm not sure if that's a standard term) then the advantage of an explicit Result type isn't very obvious to me. What am I missing?
zeugmasyllepsis··on Ask HN: What languages deploy and are also themselves standalone executables?
Smalltalk
zeugmasyllepsis··on Functional programming is not popular because it is weird (2016)
This might work out well in practice when tracking a single effect with a monad (e.g. with Haskell's `do` notation) but I think it quickly falls apart when working with multiple effects. Monads don't have a general form of composition - at the very least the order that they're composed matters to the outcome of the program. Procedural code is generally flexible enough to allow you to mix-and-match how effects gets handled, which I think would be difficult and impractical to work out in monadic contexts.
zeugmasyllepsis··on How many real numbers exist? New proof moves closer to an answer
> Real number counting is a bit more loose. To find the numbers between .1 and .2, you find all fractionals of a given size, normally 1/10.

Unfortunately the fractionals method does not work, since there are numbers (in fact, uncountably infinitely many!) irrational numbers which cannot be expressed as fractions, which are nonetheless real numbers (such as the square root of two and pi).

zeugmasyllepsis··on Half a million lines of Go
Go supports a handful of built-in generic types, like hashmaps. What Go currently lacks is user-defined generics, though that is actively being worked on.
zeugmasyllepsis··on Mugo, a toy compiler for a subset of Go that can compile itself
Thank you for providing details and not just assuming the JIT was the cause of the difference.
zeugmasyllepsis··on Interfaces and Protocols in Python
Right - so if you're introducing type annotations into an existing project and have a method expecting some interface, used by many call-sites spread across various parts of the project, then you can go around wrapping the original type at each call-site as you've indicated.

Or add a single type annotations to the method declaring that the parameter satisfies a protocol.

zeugmasyllepsis··on Interfaces and Protocols in Python
Not without modifying the existing type. Since Interfaces rely on nominal typing, each type implementing an interface must explicitly declare that they do so. On the other hand, since Protocols are checked structurally you can declare a protocol after several types already implement it, and type checking will pass without having to modify the implementing types.
zeugmasyllepsis··on Golang generics proposal has been accepted
Sum and intersection types + pattern matching feels so natural in languages like F#, OCaml, Reason, and Elixir. I know they add a significant amount of complexity to the language, but the more I use them, the more I feel that the tradeoff lands in the goldilocks "just right" zone. I find myself missing them often.
zeugmasyllepsis··on ShenScript – An Implementation of the Shen Language for JavaScript
> static type checking based on sequent calculus, one of the most powerful systems for typing in

Not exactly a common characteristic for Lisps

zeugmasyllepsis··on A History of Clojure [pdf]
This reminds me of a discussion between Alan Kay and Rich Hickey on role of "data" that occurred right here on HN[1]. The TLDR (though the thread is very worth reading, IMO):

Alan Kay argues that bare "data" isn't very meaningful on its own because it leaves the interpretation too open. His view is nicely summarized by the following quote:

> For important negotiations we don't send telegrams, we send ambassadors.

Rich Hickey argues that bare "data" is a fundamental primitive that, while leaving open the possibility of misinterpretation, leaves open the possibility of re-interpretation in multiple contexts. This is the strongest quote I took away from his POV:

> None of the inputs to our sensory systems are accompanied by explanations of their meaning.

Based on your above post, it looks like you're strongly in Alan Kay's camp, which may also explain (in part) your experience struggling with Clojure's approach.

[1] https://news.ycombinator.com/item?id=11945722

zeugmasyllepsis··on In Defense of the Modern Web
> .. in favor of targeted JS libraries that extend HTML capabilities.

Do you mean libraries like Turbolinks[1] and/or Intercooler[2] here? I'm interested in what libraries you use, and others like these which help "bridge the gap" between traditional and single-page sites.

[1] https://github.com/turbolinks/turbolinks [2] https://intercoolerjs.org/

zeugmasyllepsis··on Go + Services = One Goliath Project
While functions are first class in Go, the limitations of the type system make them less ergonomic to use, I think. Without user defined generics, many of the common uses of first-class functions become a lot less convenient to use.
zeugmasyllepsis··on Functor, Applicative, and Monad
Maybe a simpler way to illustrate this is two different functions built off of filter:

`keep`: Given a predicate and a collection, filter the collection to retain only items for which predicate evaluates to true.

`discard`: Given a predicate and a collection, filter the collection to discard items for which the predicate evaluates to false.

These are two very reasonable functions that would have the exact same signature, would be appropriate for the same arguments, but have two different behaviors!

zeugmasyllepsis··on Why is collapsing a Hacker News comment so slow?
Persisting it on the server allows users to browse on multiple devices and keep their collapse settings in sync. This is useful in particular for long threads of comments, where collapsing can be used as a tool to keep track of progress through the thread by collapsing comments along the way.
zeugmasyllepsis··on Alan Kay and Missing Messages
I agree with you! Static typing and more broadly static analysis can help catch some types of backwards incompatibilities. The intent of my comment was to highlight complementary techniques that can minimize the reliance on static analysis as the primary tool for keeping code in sync with dependencies. Alone, any one technique is not particularly fool-proof.
zeugmasyllepsis··on Alan Kay and Missing Messages
I apologize for being unclear. My intent was not to suggest that static type checking (and more broadly, static analysis) were not useful tools in catching errors early. Rather, I wanted to emphasize that other techniques could be used to mitigate the risks associated with change, such that the reliance on static analysis could be minimized. In that sense, both static analysis and the mitigation techniques help prevent the angry commenter from waking up to 4am alarms in prod.
zeugmasyllepsis··on Alan Kay and Missing Messages
I don't disagree that static type checkers and analysis software can be useful for catching many kinds of errors. In fact, at the end of my comment I emphasize exactly their strength: in automatically detecting when and where clients need to make changes. My intent in making the comment was to highlight that static analysis is only one part of a larger solution to the problem of keeping call sites in sync with the code they depend on, and to discuss other techniques that don't rely on static analysis. I think articles and comments online focus too much on the debate between static and dynamic typing, instead of the engineering principles that apply to both camps, which can help mitigate the risks associated with change.
zeugmasyllepsis··on Alan Kay and Missing Messages
> ...would have told them immediately at compile time that the last_name field access by other client code was broken.

What's the proposed fix in this case? Should all clients accessing that field switch to `customer.full_name`? Do you control all of the call-sites? If so, that change is pretty easy to automate in dynamic languages by marking the field as deprecated, adding the new field, and forwarding `customer.last_name` to `customer.full_name`. That way, running systems don't break but you get the new behavior. You can automate logs to track when the deprecated field is accessed and, if necessary, fix call-sites after a reasonable period of monitoring, reducing risk (assuming there's not "once-in-a-century" paths in the code that invoke the call site).

It seems reasonably likely that this is not the desired behavior - you may have external clients, and some callers may be relying on this field to actually return only a last name. In that case, deprecation is still the correct path, I think, since it's unreasonable to expect external clients to immediately fix systems relying on that field being available.

Static typing can tell clients where they need to make changes, but it's not realistic demand that they immediately update every call site, every method depending on that behavior, and every integration with their external dependencies that relied on the interaction between your code and another system. This is why we have (semantic) versioning, deprecation warnings, and support agreements for larger systems. API's should evolve slowly and gracefully over time, not shift suddenly overnight.

zeugmasyllepsis··on Alan Kay and Missing Messages
To be fair, their general use is discouraged unless you want the process to terminate. Not that you can't do that in other languages, but the culture in Go seems to prefer returning error codes.
zeugmasyllepsis··on Alan Kay and OO Programming
> It seems like a messaging system like this would require all calling components to micro-manage...

I think that's part of the trick, actually. When every component of a system behaves in similar ways, it's easier to extract that behavior into re-usable patterns.

Rather than each component worrying about handling failure and micromanagement, that job is delegated to an another component, a supervisor or orchestrator. Supervision trees, automatic service discovery, and elastic resource managers all come to mind.

What payment systems don't send messages to communicate with the credit card company, or the eCheck service, or Venmo/PayPal/Apple pay? Websites and native apps alike have spinning graphics and loading bars, messages that say "please don't refresh the page while we do this". These systems are fundamentally asynchronous to begin with. By uniformly applying the practices you get consistency, in exchange for a higher low-bar of complexity (which you're likely to exceed anyway).

zeugmasyllepsis··on Virtual DOM is pure overhead (2018)
To varying degrees depending on the library, I believe the answer is "yes, they sometimes do". Angular and Ember at least have systems for batching user interactions, which translate into model updates, and thus potentially DOM updates. I believe the respective systems for handling this are called Zone and Backburner for Angular and Ember, but I've been out of touch with those projects for a couple of years.

There's definitely a trade-off, however. They make a huge difference for noisy events (like mouse move, scrolling, dragging, etc), but tend to make debugging much harder in my experience. When things go wrong, the stack traces nest deeply into the event handling systems and code paths no longer resemble the relatively straightforward world of traditional event calls, where a callback handler is invoked directly in response to a single event.

zeugmasyllepsis··on Migrate Jest to TypeScript
I'm certainly not well versed in OCaml, but my understanding is that it is also structurally typed. This particular example would also be permitted in OCaml, correct?
zeugmasyllepsis··on Just tell me how to use Go Modules
> Pretty sure abstraction power drives _less_ consistency, not more.

It depends, I think. Abstractions allow users to specify part of a program's behavior independently from others. This is not intended to start a flamewar or pick on Go, but for better or worse Go does not support user defined generic functions. One consequence is that certain kinds of methods are difficult to write in a generic, performant, and type-safe way. If users want performance and type safety, they need multiple implementations of those methods for each desired type. This leads to multiple copies of very similar code (which can evolve independently, lowering consistency) or the use of on of the community-driven code generators (which all have their own differences, again lowering consistency).

Adding generics could largely make all of this inconsistency go away, but as you point out would enable a whole slew of other programming patterns more ways to make a mess.

I prefer to think of abstraction techniques as shifting consistency. Ideally, they provide an obvious way to factor out one piece of a program's behavior, allowing developers to focus on the rest of the behavior independently.

zeugmasyllepsis··on Qwant – An alternative to Google
In some sense that's kind of the point right? If Qwant isn't tracking user information than we _expect_ the results to be different, since the engine doesn't have a chance to build up an information bubble about its users.
zeugmasyllepsis··on GoAWK: an AWK interpreter written in Go
That would have been... GAWKward.
Page 1 of 2Next →