The second is a explanatory story, or "discovery fiction" as the article classifies itself: https://paulbutler.org/2022/what-does-it-mean-to-listen-on-a...
I love these humorous yet pedagogic technical writings, woven with a bit of literary eloquence and down-to-earth narrative. Thank you for this.
https://aphyr.com/posts/353-rewriting-the-technical-intervie...
https://aphyr.com/posts/342-typing-the-technical-interview
(Also linked I the first paragraph of the link you posted, as well as in the intro of the OP.)
The ending is perfect.
Vidrun, born of the sea-wind through the spruce
Vidrun, green-tinged offshoot of my bough, joy and burden of my life
Vidrun, fierce and clever, may our clan’s wisdom be yours:
Never read Hacker News
But Hacker News has read of you, in their snicker-slithing susurrential warrens, and word has spread...That post was in Haskell, where it's not too surprising that you can do serious computation inside the type system.
This new post translates the ideas to TypeScript, which is more widely known, and which I once heard described as having "accidentally Turing-complete" types:
The part about using the typescript language server to compute the solution, and the protagonist claiming the code is "concise" because only 4 lines of javascript were generated, was absolutely brilliant. Cracked me up at least.
Glancing at the actual code, I admit I'm with Criss in my ability to follow the logic, but it doesn't look like a direct translation from Haskel types to Typescript types either.
At any rate, very well done.
0: https://github.com/microsoft/TypeScript/issues/14833
1: https://github.com/microsoft/TypeScript/issues/14833#issueco...
import { Query } from "@codemix/ts-sql";
const db = {
things: [
{ id: 1, name: "a", active: true },
{ id: 2, name: "b", active: false },
{ id: 3, name: "c", active: true },
],
} as const;
type ActiveThings = Query<
"SELECT id, name AS nom FROM things WHERE active = true",
typeof db
>;
// ActiveThings is now equal to the following type:
type Expected = [{ id: 1; nom: "a" }, { id: 3; nom: "c" }];Still don’t understand anything though.
That is pretty neat, and silly.
I also think it highlights my natural aversion to static type checking in dynamic languages. I know that I could get sucked into writing a bunch of code for the checker, instead of using my energy for making the application work.
Ideally, I would have written:
type Nil = unique symbol
Which would ensure the Nil type wouldn't match with anything but itself. Unfortunately, the compiler doesn't allow unique symbol other than on const variables initialised with Symbol(). So I needed some meaningless symbols.I could also have done
type Nil = "nil"
But then it would have looked like the string meant something.“Making the application work” is only half the story. Making a large application stable and maintainable is only really possible with static type safety, IMHO.
Personally I also find coming up with the correct types to be gratifying if they’re a little tricky.
But in a smaller shop, oncall are developers, that is, ourselves.
Template metaprogramming is all about code generation. You would expect them to look different.
I’ve never worked in a Typescript shop, is there any truth to the satire here? The sea of confusing types to solve any problem?
Where complex types can be a problem is when working with open source libraries, especially when the types are community-developed, separate to the library itself. The library API may not be particularly amenable to easy typing, and the community types can end up being rather confusing, especially to people who developed neither the types nor the original library.
In my experience, 90% of the time when a developer uses any, they just don't know about unknown. 9% it's because they are lazy. 1% is because you are implementing something from an imported library, and they fell into the other 99%.
In this case it's using the type system to calculate the answer to a problem, which is not useful because the type system can't output anything to the console or do other IO. The "answer" will only be visible in your IDE.
The type system is powerful and extremely capable because it had to support existing javascript patterns, like "this function takes a parameter that might be a string or might be a number or might be an array" and make them type-safe.
Mostly in typings either provided by the library itself or via the 3rd party DefinitelyTyped project. Some typings have been made so complex, that it is hard to follow what kind of concrete type is exactly expected or allowed.
As long as you're satisfied with the answer being shown on a tooltip when you hover over a variable... sure.
Notice how the whole type structure ending up as 4 lines of inconsequential javascript after going through the typescript compiler at the very end.
I'm reminded of https://github.com/type-challenges/type-challenges -- I've only looked at some of the more challenging problems, but one involves writing a JSON parser in the type system. The easy problems look reasonably useful to solve.
There's a recursion depth limit of 500 on the TypeScript compiler, which prevents this solution working for N > 7
Even Aphyr's original Haskell solution only demonstrates N = 6, so in some sense this is an improvement on the state of the art for type-level N Queens solutions /s
> Invoke the compiler
$ tsc *.ts --lib esnext --outFile /dev/stdout
var ᚾ = Symbol();
var ᛊ = Symbol();
var ᛚ = Symbol();
var ᛞ = Symbol();
Why is there so little output? Is that because the compiler removed the unneeded types? And the author is implying that the task was boilerplate and pointless?I would not hire nor want to work with this developer.
I was going to try to pick out one of my favourites from this series, but I really can't. Every last one is a treasure.
EDIT: Oops! This is based on Aphyr's work. My bad!
This post is a pastiche of https://aphyr.com/posts/342-typing-the-technical-interview
This post translates one of them from Haskell to typescript (very well IMO).
I wish TS didn't evolve into this complexity. Library types that should be simple turn into a machine you have to understand (for no good reason).
There's a bug in the Solve "function" due to which you'll get the right answer only for 1x1, 5x5 and 7x7 (I checked till 8x8).
The base case makes a wrong assumption that there will always be a candidate available for the last row. If there are no candidates available, it should return Nil, and backtrack.
Basically, replace
Concat<candidates, placedQueens>
with candidates extends Cons<infer x, any>
? Cons<x, placedQueens>
: NilI've corrected this, and credited you in the errata - https://www.richard-towers.com/2023/03/11/typescripting-the-...
If it's the former, go for it.
If it's the latter, don't worry about it. I have a CS degree, did 6 years on a team writing C++ at Microsoft, and only briefly flirted with understanding this stuff. A couple of the wizard devs on the (very large) team could do it, but they also knew that code needed to be simple above all else, so it was effectively banned in our code base.
The other is building up basic "data types" by pretty standard lambda calculus > LISP route. "Understanding Computation" book has a great chapter 6 on that, which is available in blog & video forms on https://computationbook.com/extras - Here, Church numerals were used to represent numbers. - booleans & conditionals here didn't resort to the lambda representation you'll see in the book, but relied on type conditionals builtin to TypeScript. - The names "Cons" & "nil" are a ringer for LISP-like building of lists, and recursive processing of lists, from a "pair" data type.
What's common to both approaches to building arithmetic is starting from zero + a "successor" function T. That approach is called "Peano arithmetic".
I still recommend that post/video (and the book in general) but I have to admit there is no 1:1 correspondence to the TypeScript going on here.
Still, it'll teach you some general maneuvers for bootstrapping computation out of almost nothing , qnd once you're comfortable with those, you can read things like this TypeScript post, or aphyr's original Haskell post, which bootstrap computation out of sjighly different" almost nothings" and without following the details still have a high-level idea of where it's going (like the poor interviewer in the story ;-)
Even so, JS itself being so dynamic, TS still can’t claim full type safety.
And as much as people complain about the type system’s verbosity, many newer features are designed specifically to allow you to be much more terse while improving expressivity and safety. A great example: the satisfies operator lets you narrow a value’s type to conform to whatever it satisfies, and simultaneously widen it to whatever it adds (including anything optional in the narrower type). This is great for composition, only takes two words to accomplish. And its meaning should be immediately obvious at a glance once you know about the operator.
which tends to happen at the edge of the application where it interacts with the outside world and all the interesting things happen.
https://www.typescriptlang.org/play?#code/PTAEEkDsAsEMBsCmAa...
I didn't follow any of that shit. The fuck is an 'n-queen'? I don't think I learned that in my coding bootcamp.
Is that a bad sign?