HNHacker News
TopNewBestAskShowJobs

T-R

1,361 karma · joined June 14, 2010

submissionscomments
T-R··on WebAssembly: a binary format for the web
You might be interested in looking at Gabriel Gonzalez' Morte ( http://begriffs.com/posts/2015-10-16-internet-of-code.html ), which started off as a supercompiler project, but seems to be moving somewhat in that direction.
T-R··on From REST to GraphQL
> Though HTTP proxies are dead thanks to HTTPS

Well, they're not as broadly useful as without HTTPS, but you can still always MITM yourself to get a free transparent caching layer between the client and your end server.

T-R··on From REST to GraphQL
It may be worth looking into HTTP 2. While it may or may not be supported widely enough for production yet, it provides for things like "server push", which should allow you to minimize network round trips while keeping components separately cacheable (and therefore not requiring you to do gymnastics with your API to keep your cache granularity down), which should be helpful both with and without GraphQL. I would recommend, either way, though, thinking about organizing your objects around how quickly they spoil for their given cache key (usually the URL) across multiple clients, since that ultimately determines where you can hit cache and where you need to make a new request, regardless of what libraries you're using.
T-R··on From REST to GraphQL
It's great that GraphQL's solved some of your issues, and you've encouraged me to look into it a bit more. One thing you should worry about, though - if at any point there's any user-specific data in an HTTP response that doesn't have the user's ID in the URL (or something pointed to by the 'vary' header), it kills the idempotence of the request, whether you're using what Rails gives you or GraphQL or XML-RPC or whatever, which is pretty much the whole point of REST. It's not just REST-nazism, this completely destroys the usefulness of any cache past that point if it doesn't understand the internals of your API (as you seem to note that you've realized at the end of the article). It might make sense to just not expose the GraphQL to the client, so you can think about the idempotence of your requests from the backend, and allow yourself to keep making use of caching proxies and client-side cache.
T-R··on Data Behind Super Mario Maker Popularity
I'd interpret this a bit differently - levels with good design are likely to be few and far between, since good level design is a skill. Moreover, you can't really communicate "has good design" well in a title or with stats (and to the extent you can, no one can trust it), so it's actually pretty impressive that these levels can compete at all with levels that can easily market themselves through gimmicks, references, or ridiculous difficulty.
T-R··on Ask HN: How do I convince my coworkers to use HTTP well? Or am I being a pedant?
Talk about the practical benefits you can get, and decide based off of those:

- GET requests are supposed to be idempotent so they can be transparently cached by caching proxies. Even if you won't be taking advantage of caching proxies, it makes it easier if you can use the same data and mechanisms (i.e., HTTP headers) for server-side caching (and makes it easier to pull it out onto a separate server later). This is important if it gets a bunch of traffic or requests are resource intensive.

- Thinking about endpoints as "resources" instead of as function calls discourages you having parameters with a large or infinite set of possible inhabitants, which would dilute your cache utilization. "mysite.com/multiplicationTable.html" is nicely cacheable; You can cache "mysite.com/mult?a=5&b=10" if you want to, but how likely is someone to request that same URL again before it falls out of cache? Any information that changes the response is technically a parameter, too (since it invalidates your cache) - that especially means things like session state and side effects. That doesn't necessarily mean "never have side-effecty/RPC endpoints", but you should minimize them if you want to be scalable, since every request to one pretty much has to put load on your server.

- PUT/DELETE requests are supposed to be idempotent so they can be re-issued in case of failure. I also find it encourages design with immutable/replace semantics, rather than partial update semantics, which puts you in a better position when you want to move toward distributed/eventual consistency systems (or even just for debugging), since the data's all there in the request, and likely easier to make it commutative with other requests. Some of these things might matter to you more than others, depending on what you're building.

- Using headers properly gets you nice features like content negotiation, and provides what's needed for caching to work (e.g., 'vary' header). Using the built-in stuff means you can probably use someone else's library instead of hacking out something buggy yourself.

- HATEOAS gets you fully dynamic API discoverability. Describing your links well enough to accomplish this is pretty involved, and I'm personally not really sure it's worth the benefits, at least for anything that isn't an API having arbitrary clients built for it, or otherwise being directly navigated by some unknown end user. Maybe if there were more standardization around hypertext formats.

- Proper error codes can be nice for debugging, and theoretically can let certain situations be handled automatically (e.g., 401s could direct a user to authenticate, 302s generally redirect transparently) They also communicate some intent to e.g., search engines ("pass on my SEO link juice to this new URL"). They're a bit of a harder sell for internal APIs, since they're not really as descriptive as they should be. Probably the best practical benefit would be the ability to use client- and server-side libraries with them, or to be able to categorize your errors easily to simplify your handling, without having to dig into the response body. Also nice that you can look them up on Wikipedia - you don't have to maintain documentation for your own error format.

TL;DR: sticking to HTTP as intended helps to save you from rolling your own cache invalidation and coming up with your own new names for things, which are well known to be the two hard things in Computer Science.

T-R··on The Algebra of Algebraic data types
To add another way to look at it (thinking of a function as a set of tuples):

With tuples (A,B), you're listing As uniquely paired with Bs

With functions (A -> B), you're listnig unique sets of (As non-uniquely paired with Bs), so each A can go to any value of B, with replacement.

T-R··on Ask HN: Learning a foreign language
My basic strategy is that component composition gives you more leverage than memorizing individual words. Most languages have some degree of composition for vocabulary, like root-words, prefixes/suffixes, or individual chinese characters (and the radicals they're built up from) for CJK languages. Learning those root-words/components and how to put them together into compound words, or learning how to compose words into sentences by learning grammar gives you the most leverage, once you have a small base vocabulary to practice with - it doesn't just let you build more words, it also gives you bits and pieces you can look for to help you parse out meaning of things you don't know. For vocabulary, focus memorization on verbs and their conjugation - nouns and adjectives tend to be easier to look up (and not conjugated as much as verbs, and so easier to identify), and tend to be easier to infer from context if you don't know them - if you don't know a noun in conversation, you or they can usually point to it.

I also listen to music in whatever language I'm learning - I used to use it to switch my brain between languages on the way from one language class to another. For memorization, the best way really is to just write it and repeat it a dozen times, so putting a song on repeat is really useful for refreshing your memory on commonly used words, practicing pronunciation, and even occasionally picking up new words by looking up lyrics, etc. Nothing beats immersion, though, just because, on top of practice (inherently prioritized by common usage), it gives you all the extra context to infer or reinforce meaning - memorizing words or working from a textbook means you have no extra information to go off of but what's written there. If you want to get those benefits of immersion without actual immersion, find things that mimic those qualities (extra context, prioritized by common usage, repetition), like music, kids TV shows, comic books, conversation, etc.

T-R··on Monadic IO: Laziness Makes You Free
That's part of it. For IO/State, the idea is basically, if you wite a function that does something, you have to test it by doing that thing, so, instead, let's write recipes to do things, and then run them (recipes here just being sets of instructions - not trying to make a weird kitchen metaphor, just seemed more clear than "build computations"). Then, the code to build the recipes can be pure, and we can maybe do neat things like check recipes for equality, change up how we run them to do practice runs while taking notes, pass the recipes around and modify them, and build up libraries of not just recipes, but recipe modifications. A nice side effect is that it lends itself really well to separation of concerns/testable code - if your language is type-checked, it enforces it. If not, it's kind of optional, but there's not much reason not to keep it pure, since you're effectively doing dependency injection already. It's useful for non-side-effecty things, too - for State monads without side-effects, our "recipe" is a state machine, and it means we're being explicit about our inputs, which also makes it easy to do stuff like lookahead - changing the state and then dropping back to a previous one.

It turns out this style of recipe-building, when you get down to the minimal stuff you need for it, is really useful for any sort of computation-in-a-context (for a recipe, the result of running the recipe is the value "in" the context - you can "modify" it by adding to the recipe, same as you can "modify" a function's return value by composing it with another function). Basically, the interface says that "return" lets you put something in a context, "join" describes how you can compose contexts, and kleisli-compose says that if you have two functions that return results in a context ( a -> ctx(b) and b -> ctx(c) ), you can compose those functions by composing the resulting contexts with "join". The end result is that if you have some context, like a recipe, you can apply changes to it ("bind"). In fact, if you have no context (the Identity monad) kleisli-compose reduces to just normal function composition, and bind reduces to application.

TL;DR: separation of concerns is a really nice side-effect of what's just a really broadly applicable interface for "more complicated but still composable stuff".

T-R··on Becoming Productive in Haskell
For Monad, 'join' or the kleisli arrow (>=>) might give better intuition than bind/flatMap - maybe something like "contextComposable": kleisli arrow in the Identity monad is just function composition, and for everything else, it's function composition within a context, combining contexts according to 'join'.
T-R··on An Experiment in Purely Functional IO for Clojure
Surprised no one's brought up Haskell's Debug.Trace, which effectively does this, but returning whichever value you tell it to.
T-R··on Category theory for beginners
My understanding is that it's not a proper category due to the presence of Bottom - https://wiki.haskell.org/Bottom

> Bottom is a member of any type, even the trivial type () [...] If it were not, the compiler could solve the halting problem and statically determine whether any computation terminated

You can imagine function composition and identity don't work too well on things that never complete.

T-R··on Why I love databases
That sounds fantastic. I'll give it a look
T-R··on Why I love databases
When you say "NoSQL-Koolaid free", do you mean "focuses on Relational" or "treats the topic objectively/academically"?
T-R··on Thinking Functionally with Haskell – Richard Bird's New Book
Just taking a quick glance through the table of contents, it looks like it aims to focus more on "how to think about problems in this paradigm" (as the title implies) than the more practically-oriented "let's go write fizz-buzz" approach. For example, it jumps into function composition before it even talks about how to use GHCi. It has a chapter called "Proofs", and it seems to have a chapter focusing on using lazy evaluation to trade off time and space consumption.

Glancing at the text available, it doesn't seem to make any references to other programming languages, and takes an approach of "let's build this up from the things you learned in Math class". Seems like it might be a good fit for someone with more math than programming background, or someone with enough programming experience that they want to get to the heart of what functional programming is, but a bit jaded by the usual language tutorial format.

T-R··on Function Purity and Immutability in D
But that's a pretty low bar. Using just 'pure', can you mutate an argument in a function called in a conditional expression (making it unsafe to check again)? Can it matter what order a list gets processed in a call to `map` or `filter`? Preventing mutation of global variables narrows the scope of the damage, but having just that still means that if you're maintaining someone else's code, you need to double check everything for side effects, even if they'd be limited to the inputs.
T-R··on Function Purity and Immutability in D
I'm not saying it isn't - it's certainly good that it's also possible to declare something as referentially transparent, but defining the keyword "pure" to imply something much less than referential transparency is still a poor choice.

Edit: To be clear, I don't really feel too strongly about it. It's still leagues ahead of many other languages - I just think that particular choice of keyword is likely to confuse things a bit.

T-R··on Function Purity and Immutability in D
That still means the function can't be treated as referentially transparent (whereas a Haskell function with debug output still can be, for the most part).

Don't get me wrong, that's still somewhat useful - it tells me "this function doesn't do anything too crazy", but it doesn't tell me "it should be safe to refactor this without having to read the function bodies of the entire call graph below this point", which makes calling it "pure" seem a bit disingenuous.

T-R··on Dirty Assembly Tricks in NES Assembly (2013)
These kinds of tricks actually are being done: by the compiler (as long as you give it enough information and don't try to outsmart it) - they're exactly what gets put into optimization passes. Trying to do these optimizations by hand generally turns into a time sink that results in buggy, unmaintainable code, which is, pretty much by definition, too low level to take advantage of current or future compiler optimizations.
T-R··on Dirty Assembly Tricks in NES Assembly (2013)
One of my side projects is very similar: I built a recursive descent disassembler for Gameboy that I'm working on building into a decompiler. I took a slightly different approach - rather than generate assembly, I generate a call graph - each instruction is a node with zero or more potential following nodes.

The key word, though, is 'potential' - as the author mentions, one of the issues you run into with disassembly is that you sometimes run into code that jumps into garbage (dynamic jumps with insufficiently constrained inputs, or code that should've been unreachable), and sometimes you just hit an infinite loop waiting for an interrupt. It really needs some input/interactivity to determine likely entry points and dead ends/unreachable code.

One nice thing you can do while you have the call graph, though, is propagate constraints (basically type inference/data flow analysis) to get an idea of where dynamic jumps may go, which ones might be under-constrained, and which branch targets are likely dead ends. Haven't gotten as far as implementing it yet, but there's a paper on it here: http://www.cs.rhul.ac.uk/home/kinder/papers/phdthesis.pdf

T-R··on Ask HN: Replacement for VIM
If split screens are your thing, it might be worth it to try a Tiling Window Manager. I agree with you that Sublime doesn't natively have enough split screens, so I use XMonad, and split them and organize them as I please.
T-R··on Game about squares
This was the first thing that struck me as well - just fantastic level/game design. Immediately brought to mind the instructional level design from Super Mario Bros - http://www.theoryofgaming.com/gold-standard-for-game-design/
T-R··on Hudson's Lost Mario Trilogy (2010)
I think he might be referring to Mario Bros VGA - http://www.abandonia.com/games/880/MarioBrothersVGA
T-R··on Hudson's Lost Mario Trilogy (2010)
The SMB3 mini-game was based on the original Mario Bros; The author describes Punch Ball as a distinct game:

> This is almost identical to the original Mario Bros, except you can't knock enemies upside down by hitting the platform they're standing on. The only way to defeat them is by hitting the POW block or throwing the Punch Ball which Mario and Luigi carry around.

T-R··on When REST Gets Messy
I wasn't aware of that, that's good to hear. I'm under the impression, though, that since SPDY encrypts everything, that you can't get caching at intermediate nodes unless you explicitly MITM yourself, which would reduce the utility of that feature. Then again, I'm not sure how much caching happens outside of places where you'd MITM yourself now anyway, so I guess in practice, that might not be a huge step back.
T-R··on When REST Gets Messy
I really do wish HTTP had a mechanism for responding to a single request with multiple combined response bodies as if requests were made for each individually (from the perspective of, e.g., a caching proxy) - the loss of separation of concerns from merging children into the parent isn't just a usability issue, it also means you lose your cache granularity - the cache for the parent object is now stale whenever a child is modified, and a request for a child after getting the parent won't hit the cache at the request level.

There's keep-alive, but that still means that if you want to get a parent and its children, you have to wait for the parent request round-trip.

To add - this is a major issue we've been working through at Slant.co - we've combined child objects into the requests for the parent objects (sometimes even two levels down), but it's significantly complicated caching efforts - we're in the process of building some namespacing into our server-side request cache, so we can transparently make cached Question and Option pages stale whenever, e.g., the title of a Pro/Con gets changed. If HTTP allowed multiple responses, we could treat everything transparently server-side as individual requests, and get much higher hit-rates for proxy and client-side caches.

T-R··on When REST Gets Messy
> I'd argue that in REST it would be desirable that resource representations do do that (provide [...] the direct locations of any embedded subentities that are separate addressable).

You could actually go a step further - if you're using "Hypertext as the engine of application state" (HATEOAS), URIs for the locations of direct subentities need to be there, if the client is expected to be able to make those state transitions, for the API to be "fully RESTful". (Though, I'd personally agree with the article that features like discoverability and content negotiation are secondary to those you get from idempotence/properly using HTTP methods, and feel they should be considered bonus features, rather than strict requirements)

T-R··on NES Dual Port RAM Interface
That's fantastic.

I'd been thinking about modifying an emulator to do automatic speedrun splits based on changes in memory. Many of the people who'd most appreciate that kind of thing prefer to speedrun on original hardware, though, and a lot of them would be happy to pay for modifications like this - as many have, e.g., paid to have their 3DS modded with HDMI output.

T-R··on 2048 in Idris
Thanks for this - I've bookmarked it to read later. It looks like you've explained everything pretty thoroughly in the readme, and looks like an excellent example for getting started.
T-R··on 2048 in Idris
I think this past month has been a bit of an outlier with new languages, such as Avail, being posted. That said, I wouldn't count Idris as one of them - it's been around for a little while now, and in the community of people familiar with purely functional languages, it's probably about as well known as Elm or Agda: If talking to a Haskeller, there's a good chance they've at least heard of it.

Of course, it's all relative - this community does have a good number of early language adopters and people involved in programming language research. At the other end of the spectrum, just a few years ago, I met a Java developer who, at the time, hadn't even heard of C# - I'd imagine he'd've been quite shocked by the languages talked about here.

← PreviousPage 4 of 14Next →