HNHacker News
TopNewBestAskShowJobs

T-R

1,361 karma · joined June 14, 2010

submissionscomments
T-R··on Haskell In New Clothes
TemplateHaskell and QuasiQuotes are very closely related. They're where that square bracket syntax comes from:

    [whamlet|Hello World!|]
I would say that they're closer to the situation you're concerned about - they're very much like C++ templates, and equally controversial for exactly the same reasons. Still, I don't usually think of C++ templates, or Haskell ones, as being a different style per-se, just an advanced feature to use sparingly, mostly just when they'll save you from writing a bunch of boilerplate.

For completeness - Overloaded strings are the Haskell parallel to Python's b-string, f-string, u-string, etc. TypeFamilies are "let me write functions over types", which sounds like it would be dramatic enough to introduce a different coding style, but since it, like other extensions, needs to play nicely with the type inference, it doesn't conflict with other extensions, so things mostly just work as you'd expect. Since extensions generally work nicely together, most people just turn on "the usual" extensions for the whole project (all the more reason we need a new standard), and only add explicit pragmas in files to call out heavyweight things like TemplateHaskell. In tutorials you're more likely to see them all listed at the top, though, to be clear about what's being used.

T-R··on Haskell In New Clothes
You say "of course... I'd have to learn one or more flavors/styles of it", and that seems like a reasonable assumption, but it's not accurate in practice - the extensions largely just add features, so you just turn them on if you're using that feature; there's not much of a separate style for coding around not using one. It's like, if your Java project used a Singleton class, you might feel a need to document it, but if it doesn't, it doesn't mean you have a separate "Singleton-less" style, you just didn't feel the need to use one.

Which isn't to say they're not an issue - Haskell really needs a new language standard to clean up that mess, but they don't really fragment the ecosystem the way that, say, the Python 2 vs 3 split did.

T-R··on Software reuse is more like an organ transplant than snapping Lego blocks (2011)
Careful decisions can scale with abstractions, if they're made with some rigor.

In Python, for example, whenever I'm doing operations on lists, I need to consider every function in isolation - will this break for an empty list (zip), or will it break when given a generator (anything that traverses twice)? If I pass a callback with side effects, how will it behave differently if someone calls it twice?

In a a more rigorous ecosystem, I can instead only worry about edge cases on classes of functions/data types - In Haskell, when doing the same operations, I can generally assume that traversal functions were written with consideration for functor/foldable/traversable laws, and those laws tell me how I can safely compose or swap them out without breaking expectations around those edge cases. Higher Kinded Types let code be constrained to work strictly with those abstractions, so I mostly just need to worry about "does this typecheck" and, very rarely, "is this an unlawful traversal". With things like linear and dependent types entering this mix, library authors can communicate even more subtle expectations at compile time instead of leaving users to try to anticipate them or find them at runtime - when you do need to explicitly consider edge cases, the turnaround time on discovering them is important.

T-R··on Attempting to Use GNU Guix
I'm hoping that maybe Flakes[1] will help ease the issue/pull request situation by letting some of the namespaces move out of the main repository.

[1] https://github.com/NixOS/rfcs/pull/49

T-R··on Modern SAT solvers: fast, neat and underused
SAT solvers are starting to be used as tooling for functional languages - Liquid Haskell uses one for refinement types[1], and Djinn uses one for suggesting functions given a type[2]. Similarly to Djinn, Edwin Brady gave a presentation on using an SMT solver to do live code suggestions/implementation inference in the successor to Idris[3].

[1] https://ucsd-progsys.github.io/liquidhaskell-blog/

[2] http://lambda-the-ultimate.org/node/1178

[3] https://www.youtube.com/watch?v=mOtKD7ml0NU

T-R··on Tutorial series for simulating NES Graphics (2018)
This came up indirectly in the thread on color emulation earlier[1] - there was some discussion of the need to emulate phosphor glow[2]

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

[2] https://sites.google.com/site/psigamp3/PhosphorSimTest1.jpg

T-R··on Why GitHub used Haskell for Semantic
The omission of where clauses was explicitly a stylistic choice[1].

This is perfectly valid Haskell:

    #!/usr/bin/env stack
    {- stack script --resolver lts-12.19 -}
    data Test = Test {count :: Int}
    
    test = let
      something = Test {
        count = 5
      }
      in 5+(count something)
    
    main = putStrLn $ show test

To get the equivalent Elm to compile, it must be indented like this:

    test = let
               something = {
                 count = 5
                 }
      in 5+(something.count)
Note that `something` must be indented beyond the beginning of `let`, and the closing curly brace must be indented to the same level as `count`. These are both not a warning, but a parse error - you can confirm it with Ellie[2]. If that were due to a lack of resources, it would absolutely be understandable, but this also was an explicit choice[3] which developer time was spent implementing.

[1] https://github.com/elm/compiler/issues/621

[2] https://ellie-app.com/5KRg4g5ZMkba1

[3] https://github.com/elm/compiler/issues/1573

T-R··on Why GitHub used Haskell for Semantic
I've worked in Elm a decent bit, and used PureScript a little.

Elm is a very opinionated language - it's very deliberately missing some abstraction power (typeclasses), and some functions that are the bread-and-butter of every functional programmer have steadily been getting removed from the base libraries, so if you're used to Haskell, you'll find yourself falling back to duplicating code by hand a lot. Elm also makes certain stylistic choices into parse errors - "where" clauses are strictly forbidden, and indentation preferences are strictly enforced. It's basically taken an awkward edge-case from Haskell's indentation rules and made it not only a requirement, but a prerequisite to seeing if there are any other errors in your program. The back-and-forth trying to get the compiler to accept things that would just work in Haskell, but don't because of someone's stylistic preferences, is absolutely maddening.

PureScript, from the bit I've used it, is like a strict version of Haskell with row polymorphism, a feature Haskellers have been hoping for for a while. I've chosen Elm over PureScript in the past because of PureScript's dependency on Bower (which I think has changed since then), but that's the only reason.

T-R··on Make the Leap from JavaScript to PureScript
Well, that's pretty much equivalent to the the language preventing bugs, for the purpose of the conversation. You can imagine similar cases that would be harder for a linter to pick up. Things like type errors, or accessing the wrong side of a union - in C++ people used Hungarian Notation for a good while to try to make these kind of errors more detectable; now some languages have tagged unions/sum types to make them nearly impossible. The point where a linter is distinct from the language in catching syntactically evident errors is that, even if I use a linter for my own code, that isn't the same as having buy-in from the whole team to block any code that doesn't pass the linter from shipping to production; language syntax, on the other hand, is implicitly agreed upon.

Addressing this specific example, historically, running a linter all the time wasn't always practical, and `if(a = b)` was used intentionally a lot, e.g. to inline a check for a null pointer with an assignment.

T-R··on Make the Leap from JavaScript to PureScript
This is a really arrogant statement. In C, `if(a = b)` could cause incredibly subtle bugs. It was prominent enough that it got addressed in all the best practices books, like "Writing Solid Code", with a style that got later termed "yoda conditions" - a style that was prominent in spite of being acknowledged as less readable, because it forced a compiler error more often. It's hard to even think of many other types of bug with that kind of significance, and you just dismissed it out of hand with "I don't make those kinds of mistakes".
T-R··on South Korean students flock to Japan
To be fair, they only elected the conservative party, the LDP; the party elected the prime minister. Granted, they've elected the LDP almost continuously since 1955. Of course, they tried electing the other party in 2009, but their leadership kept resigning. Of course, given the LDP's stranglehold on politics, one has to wonder why they feel a need to pander to the nettouyo.
T-R··on Stephen Wolfram Version 12 Launches Today (and It’s a Big Jump for Wolfram
Haskell has a few libraries that do this[1]. Not trying to one-up the article or anything, just thought you might be interested to see that there are other places where this is available, and that it's not even something that needs full language support in some cases, just a library. Also similar - you can pretty transparently model nondeterminism[2] and probability[3] on a "promise"-like interface with just a library. Of course, whether or not there's good documentation is another story.

[1] https://stackoverflow.com/questions/19598906/is-there-a-valu... [2] https://stackoverflow.com/questions/20638893/how-can-non-det... [3] http://wiki.haskell.org/Probabilistic_Functional_Programming

T-R··on US Army applying new areas of math
HoTT was a popular topic in the Haskell ecosystem a little while back, so worth digging around there for info:

- https://softwareengineering.stackexchange.com/questions/2623...

- https://www.reddit.com/r/haskell/comments/6nxgkc/similaritie...

- https://bartoszmilewski.com/category/homotopy-type-theory/

T-R··on How we made Haskell search strings as fast as Rust
The thesis of laziness by default isn't "everything should be lazy", just that there's some benefit to having strictness be something you add as necessary - maybe that it's easier to add strictness to something lazy than add laziness to something strict, that it gives you more abstraction power, or maybe increases surface area for optimizations.

Similarly, the existence of generators and zero-argument functions in Python doesn't undermine the idea that strictness by default could have benefits.

T-R··on YouTube Stars Are Pushing a Shady Gambling Site
Not just games - toys like Hatchimals and LOL dolls are just loot boxes targeting an even younger demographic, with similar unboxing videos to market them.
T-R··on Rust RAII is better than the Haskell bracket pattern
Something to keep in mind - linear types are on their way[1], with exactly this usecase in mind. Simon Peyton Jones gave an excellent presentation on the topic[2], briefly discussing exceptions, as well as giving a mention to ResourceT and the phantom type solution in the article (described as channel-passing).

[1] https://arxiv.org/abs/1710.09756 [2] https://www.youtube.com/watch?v=t0mhvd3-60Y

T-R··on Functional core, imperative shell (2012)
I don't think we disagree in spirit - I didn't mean to imply that it prevents you from, e.g., writing all of your code in the IO monad, just the points you made in your last paragraph. So, more that they're a useful tool to help you realize these goals, not something that gets you there on its own. It does let you broaden/specify your definition of "effectful" a bit - modelling event streams with monads gives you FRP (as in your robot example), and I vaguely remember reading in some paper somewhere the suggestion of using monads to separate out unconstrained recursion/non-totality/co-data from total code.
T-R··on Functional core, imperative shell (2012)
This concept is a big part of what the "big deal" around monads is - using monads to model effectful code conveniently puts the information of "this should be shell code" into the type, in a way that ensures that code that calls it also gets annotated as "shell" code. Monads are of course also a much more broadly applicable abstraction, but their application to effectful code, enforcing this design, is usually the first and most apparent place people run into them in the ML family of languages.
T-R··on When Is Haskell More Useful Than R or Python in Data Science?
It's not about it being hard to write them out; everything that needs to get written out is surface area for bugs. One missed edge case could just mean that a node of your input layer gets zeroed for some of your rows where it shouldn't, and all you see is no correlation where you expect some. The little bugs that creep in writing this simple boilerplate kill days of work.

One person writes unzip as zip(*arr), another writes it as two separate assignments with the list comprehension written out. It's a tiny bit of code; they both look like perfectly fine unzipping code, and they pass tests, but if you pass one of those code blocks a generator instead of a list - say, someone swaps a list comprehension for map - half your data disappears. No errors, just a node that shows no correlation.

Since the results are all getting serialized anyway, the amount of work to just have that part of the pipeline in a language with some guard rails against that kind of thing is pretty minimal.

T-R··on When Is Haskell More Useful Than R or Python in Data Science?
I agree in principle, but this is exactly why we've moved our data pipeline from Python to Haskell.

The Python ecosystem has this concept of what is "pythonic", which, while it results in more code around the internet looking familiar, it largely resolves to "write it out yourself by hand". The result is that there are often no library functions for these things, even in libraries where you'd expect them to be. Need to coalesce an Optional, or need a switch statement? Write out the conditional. Need zipWith, flatMap, or mapMaybe? Write out the list comprehension. Need a combinator, or something curried? Write it out.

We spent an obnoxious amount of time fighting with bugs from this, or weird edge cases in pandas and numpy, that would show up halfway through training, or not at all until we measured results. Heisenbugs from generators were also a huge issue. We ultimately decided the situation wasn't tenable for the quick iteration cycles we needed, and moved all the data munging to Haskell. Almost everything we need for data munging is in base, usually in prelude. If it isn't, it's in lens. Changes and refactors are quick, and no more surprises halfway through training.

T-R··on North American vs. Japanese zoning
I'm not familiar with public green spaces in Europe, but there are definitely traditional parks all over Japan. In one place I lived, there was a sizeable park with a nice walking path through the woods just off the train into the city; it was always nice to look out the window and and see all the families hanging out there on the way into town. Where I studied abroad, there was an open park that regularly had town events, but more notably had beer vending machines, so it was always full of loud foreign college students; there was a quieter one with hills and trees where locals walked their dogs a little further away. Osaka castle park also has a lot of grassy area to just hang out; everyone goes to picnic (read: drink) there when the cherry blossoms are blooming. Parks did seem a little more sparse in Tokyo.

Edit: Here's one of those parks: https://www.hamamatsu-pippi.net/docs/2014030700074/

T-R··on Thousands of Americans Will Be Denied a Passport Because of Unpaid Taxes
To the extent this comment can be construed as anything but content-less partisan dog-whistling, it's pretty off the mark here. Obnoxious as this particular measure is, it was passed as part of the funding for a, relatively speaking, bipartisan infrastructure bill focusing on highways and rail. It's hard to imagine what "real Americans", whoever that's meant to imply, would rather it be spent on.
T-R··on Thousands of Americans Will Be Denied a Passport Because of Unpaid Taxes
Which is doubly disgusting, since the US is one of the only countries that double-taxes its expats.
T-R··on The Logical Disaster of Null
I think that's kind of his point - Optionals/tagged unions are "Null values", but only in the places where they semantically make sense.

The problem with nulls isn't strictly null references, in the sense of "a pointer that points to nothing" or "a pointer that throws a null pointer exception", it's that languages with nulls implicitly make null an element of every type. They tend to do this because variables are allowed to have null references, but if you changed the semantics of variables to technically forbid null references, but still had a null value as an implicit element of every type, you'd still have the problem of needing to do runtime checks for null everywhere.

T-R··on Common combinators in JavaScript
I think those single-letter names like "S combinator" are a holdover from Math notation, where it was a practical consideration, but in practice in functional programming, those names aren't used (I certainly haven't memorized them); If you look at the Haskell column on the page, you can see that they're actually named for readability (though it might not initially seem like it if you don't do a lot of coding in Haskell):

- K is "const" and C is "flip"; they're generally used to for arguments to a higher order function: "map (const 5) myList", "foldl (flip f) 0 myList"

- Psi is "on", since it's regularly used to construct a new function "h = f `on` g"

- S is a specific type of application, called infix as "f `ap` x", but also has an operator to intentionally make it look more like just line noise: "f < * > x". (Had to add spaces to this operator so HN wouldn't interpret it as italics)

The operators might seem opaque, but the idea is to make it more visually apparent that it's a pattern, not some application-specific business logic. There are lots of concepts of "apply" - there's pure application ($), Applicative application (< * >), Monadic application (=<<), etc. - writing them out would distracting to read. Using operators makes it easier to skim and get the general idea of how the code works without worrying about the underlying structural details, while still being precise about them.

T-R··on Common combinators in JavaScript
It's intentionally to get across the idea that you don't, and shouldn't, know anything about these arguments within this scope beyond "this is a function" and "this is an argument". These functions just define how to combine things; if you knew any more about the arguments, it would be breaking the abstraction.

The only better names you could really give are ones like func1, func2, arg1, arg2, which don't add any information, just add noise. Trying to get any more specific than that would leave the reader trying to interpret the meaning of the name, but the whole point is that it's strictly "apply this thing to that in this way, without looking at what they are". Even fix-point, which is unarguably cryptic, really needs a paragraph explanation for the unfamiliar more than it would benefit from better names.

T-R··on What People Think You Can’t Say in Silicon Valley
> They chose (perhaps felt forced to chose) to change their body to fit the stereotype.

This is kind of presuming the conclusion, and ignoring the stated experiences of the people being discussed. The concept of gender identity (whether or not it does a good job of it) is explicitly intended to highlight that the causation isn't "I fit this stereotype, therefore I am this", but just "I feel I am this", with the implication that it may (or may not) be reaffirming to fit in socially with other people who are that way. Many don't identify with the stereotypes. Sure, some cling to stereotypes - maybe because they previously felt constrained from expressing themselves, or just as a practical measure against getting misidentified - but that doesn't imply that that's the cause or the goal. If you don't believe the claim that it isn't the cause, that's fair, but then it's just a person's beliefs against anothers' self-assessment.

The term "transitioning" is also used in a general sense, including "being yourself", as opposed to necessarily taking hormones. Taking hormones, changing paperwork, doctor appointments, losing fertility, etc., is kind of a long, drawn out, stressful ordeal that inherently starts with "being yourself in your own body" until changes kick in; it's pretty unlikely that someone transitioning hasn't considered just not doing the hard part, especially since it's so slow that there's ample time to turn back.

I'd wager most trans people are as opposed to gender essentialism and gender stereotypes as other feminists are. Nothing about accepting that they might actually just not be comfortable in their bodies, or at least just letting them be, implies philosophically accepting gender essentialism. Moreover, making the world more accpeting of people just being themselves is pretty closely aligned with just letting trans people be - if they actually don't need to transition, they'd be less likely to in a world where those who don't fit stereotypes, like trans people, are more accepted. And it's not a verboten topic - the Reddit trans communities have these discussions pretty often, when the questions are asked genuinely. It's just that, as with other minority-focused topics, it's often brought up with the clear intention of harassment rather than having an actual discussion, so there's a low tolerance for things that signal disingenuousness.

T-R··on Super Mario 64 Online Release [video]
I can't speak to the complexity of this project, but for ROM hacking in general, it's not all too complicated, but it does take some persisence.

First you need to find code relevant to what you want to do. You can take diffs of memory as you do things in the game to narrow down where the relevant addresses are, and then set breakpoints on read/write to those locations to find relevant code. After that, you can mostly just follow the assembly - you can even read backwards up the call stack by reading to what look like the beginning of a procedure, and searching for jumps to that address. Once you've found the code you want to modify, you just need to find some empty space in the ROM that you can branch out to to write your code.

The trickier bit is if you're in a spot where you need to worry about timing. On older consoles, this included things like changing the HUD or wave effects, etc., since you need to make sure whatever work you do gets done in time for HBlank/VBlank.

Some consoles also had some built in functions that would give you an idea of what code was for, like the lz77 compression on the GBA, which was mostly just used for graphics. Similarly, DMA was most often used for copying sprite data. On newer consoles where code was often compiled from C (rather than assembly with macros), I'm under the impression you can also do things like try to pattern match on the signature of standard library functions.

T-R··on Imperative Haskell
Impurity is a lack of constraints. You can, with impure code, write an interpreter for a language that constrains code to being pure, and implemented correctly, you can then depend on code written in that langauge to be pure.

His point is that there's no lost benefit in calling pure code from impure code - the code is already unconstrained. Calling impure code from pure code, though, means you've lost the purity constraint, which means you've lost the nice emergent properties you get from that constraint.

Even if you write 'pure' code in an impure environment, you can't depend on it being pure, because that constraint isn't actually enforced. No matter how pure I try to keep my Javascript, I can never depend on it being pure - there could be a bug, or someone could add impurity at the bottom of the callstack, breaking referential transparency.

T-R··on Bad Character: If Chinese Were Phonetic
That's a fair point - seems related to the fact that people aren't writing as much anymore.

Anecdotally, I feel like Japanese picks a better point in the tradeoff space than other languages - Chinese characters are used where they get some leverage, with phonetics for everything else, even with a bunch of half-kanji words. Still, I'd imagine some of the less-commonly used ones will get dropped over time.

On the other hand, English+Emoji+Txt simplification seems to be approaching the same point from the other direction.

← PreviousPage 2 of 14Next →