Fantastic. First time I saw something similar to this was Edwin Brady’s recent demo of Idris 2. It’s quite amazing just how much of a program can be machine-written when the types are strict enough.
I hope holes & case-splitting get into many more languages.
Yes, once I got to know sum-types with match destructuring in F#, every other programming language that doesn't have them feels inferior. It's just such a practical idiom.
Nadia Polikarpova at UC San Diego is doing some interesting work in this space.
Skipping to about 42:40 in the video Nadia discusses an evaluation with a range of skills using Hoogle+ and how the usage trends from concrete examples to mostly type level specification.
A language server is an API for a program in a language, so that text editors and linter and code generators can all interact with the program without knowing about each other.
f :: YourTestInput -> CorrectAndPerformantAdventOfCodeSolution
f = _
---
Seriously though, even after writing Haskell primarily for years, I've never done hole-driven development and I'm still not sure what I'm missing. I tried once — granted, that was a long time ago — but I didn't get it. This post[0] suggests I'm not alone in thinking this.
I'm glad Wingman exists and I think branding it nicely like this is the right thing to do, but I think I need to see more concrete examples to really see the magic. Probably something like Gary Bernhardt's Destroy All Software screencast series. It's one thing for someone to tell you that vim is fast, but it's another thing entirely watching the tool come to life in the hands of an expert. I imagine it's a similar thing for Wingman — I still have this mental block where I'm picturing the tool conjuring up an undefined for each hole, which is exactly what the documentation suggests the tool doesn't do. I would love to see someone use Wingman to quickly hammer out an Advent of Code puzzle, or even something more real-world like an Esqueleto query (but is that even possible?)
The post talks more about usability issues rather than any theoretical issues.
There are more fundamental objections to typed holes - but Wingman is kind of the answer to those concerns - with typed holes you're filling in types from the expressions, with Wingman you're doing pretty much the opposite - synthesizing programs from the type.
Now there might be usability issues with Wingman as well, but it represents a different direction - more suitable for type-driven development.
I tried the example and it worked. I am indeed amazed, both at Wingman and how good Haskell and its tooling has become since I last looked at it a couple of years ago.
One promise of Haskell is that, once you've become an advanced or expert user, it is a gigantic force multiplier for individual devs or small, tight teams.
The way the tooling has progressed recently imo is that being proven in real-time.
For all the new tools (HLS, Wingman), it's the core tooling that has improved the most since the then. GHC (+ghci) and cabal are leagues ahead of 2014 now.
Some other cool tooling advancements since then that come to mind are.. Nix integration (both nixpkgs and haskell.nix), ghc heapview, ghcjs, a glut of formatters, ghcid (is this that new?)
Ghcid rocks! Makes it super easy to develop in a terminal with no IDE. Just a text editor here and ghcid there, telling me instantly when I make a mistake.
Why would you want to develop in a terminal with no IDE? The only other people I've seen do this were long-term Haskell developers (I remember seeing someone fixing a bug with sed!)
It makes you write better code with a smaller local conceptual branching factor. You need to be able to keep the number of concepts required to comprehend a piece of code small enough to fit in working memory. This forces you to structure your code well, come up with better abstractions, etc. It's also more zen, faster (in terms of UI responsiveness), less prone to breaking, requires less maintenance and configuration, etc.
IDEs are generally terrible for code quality, (and for my personal happiness,) but they're also viral because if one person working on a codebase is using an IDE, then they're probably going to write code that forces everyone else to also use an IDE - e.g. because understanding the code practically requires jump-to-definition.
> […] e.g. because understanding the code practically requires jump-to-definition.
Wait… so the code you write makes me magically able to know the record field names of your data types without looking at their definition?
Your statement may be true if it’s talking only about the core logic of an application, but when we get to the part that interfaces with the rest of the world, things always get somewhat messy. An IDE is a huge help here.
> I mean, sure, you may be able to memorize the arguments that “readCreateProcess” takes
How frequently would you use and subsequently forget how to use this function?
If I use a library function like this, I most likely write it exactly once in my codebase. The cognitive overhead of going on hackage one time per project-library is very small.
I agree an IDE makes you marginally faster in this case - just pointing out that this marginal benefit need not be significant.
Knowing record field names without looking at the definition isn't a critical path of coding worth optimizing. Amdahl's Law applies to code editing too.
Hoogle and even a simple "rg -A10 'data TheRecordName'" work perfectly fine. No reason to shave seconds with an entirely different tool.
For readCreateProcess, I just..look at the Haddocks while I program :)
Good Haskell modules tend to be quite literate and are therefore easy to read as plaintext. Clicking into the source of Hackage is often very fruitful compared to other languages (Go comes to mind.)
Often they aren't meant to be read top-to-bottom of course, but they're a few hundred lines of code that makes sense and backs a very readable export list.
And good Haskell isn't especially bound by writing and managing the code. You spend most of the time thinking and then a small amount of excellent, composable code pops out. Rinse, repeat, compose it all together.
> And good Haskell isn't especially bound by writing and managing the code. You spend most of the time thinking and then a small amount of excellent, composable code pops out. Rinse, repeat, compose it all together.
Haskell is no different than any other language in this regard. Implementing e.g. a standard CRUD app in Haskell using “beam” involves a lot of boilerplate, for which a proper IDE is super useful.
> Haskell is no different than any other language in this regard
It absolutely 100% is. This is half the reason people like to use it.
> Implementing e.g. a standard CRUD app in Haskell using “beam” involves a lot of boilerplate
I haven't used beam, but for me, the appeal of Haskell is that that you can throw out like 90% of the low-semantic-density boilerplate you see elsewhere. Composable abstractions, typeclasses, generics, lenses, etc. - all of these things directly serve to reduce unnecessary semantic sparsity, and incidentally obviate the need for an IDE.
Haskell has a decent web ecosystem at this point. However, if you really want to avoid boilerplate when writing a CRUD app, your best choice is one of the big, boring popular web frameworks (Ruby on Rails, Django, etc.) 90% of boilerplate avoidance has less to do with fancy language features than it does with someone else already having done the work for you. (And dynamic languages like Ruby and Python do allow all kinds of fancy abstractions anyway - just without the security of compile time typing.)
An IDE gives you hints and you learn to rely on them; it takes 1 second to check something and you end up doing many checks like this.
In a terminal you have to check everything and remember about everything yourself. Maybe it takes 1 minute instead of 1 second. So you only do this when it matters and you make sure you remember the result because you don’t want to waste that 1 minute again.
If one is able to write a tool to write your program for you, could it be the case that the language lacks syntactic constructs to be terse enough to be pragmatic?
Where is this comment coming from? That is, how much have you looked at what the tool does/written Haskell in the past?
I think the key thing is that sometimes there are multiple ways to answer something. For example consider this type:
[Maybe a] -> [a]
It takes a list of optional values and returns non-optional values. The ‘obvious’ semantics in Haskell could be achieved with:
f [] = []
f (Nothing:xs) = f xs
f (Just x:xs) = x:f xs
And there are plenty of other ways to write that function. But you could also write functions like
g xs = []
h xs = reverse (f xs)
j [Just a, Just b] = [b, a, b]
j _ = []
And all three would satisfy the type above. So the type may be a sufficient input to the tool as the programmer may select the suggestion, but it wouldn’t be sufficient input to the compiler as the compiler could just guess the wrong thing.
When can I get Wingman to fill in trivially simple holes, e.g. where the type of the hole is `TypeA -> TypeB` and there’s only one function in scope with that type?
In this situation, choosing “Fill in hole”, Wingman always just fails with a “ran out of gas”-error.
At its heart stuff like this is no different than the jumps from punchcards you asm to c to python. You still need someone to solidify ideas into processes. The change is that the building blocks themselves become more complex.
For whatever automation a new tool gives you, you get new maintenance on that tool, other languages will want a tool that gives those features, systems running older versions will want upgrades in order to support the tool, 20% time will be spent on getting it running immaculately on Emacs, security researchers will find bugs in the tool so everyone has to fix, patch and upgrade, web sites for showing off the tool need designing and hosting, support forums have to be staffed, blogs have to be written, some novel use of the tool requires integration with various other systems, enterprise asks for a powerbi version that can integrate with oracle (it ends up being 5x slower, but does lead to more jobs in maintenance and meetings), more research is produced etc. etc.
Wingman just automates sifting through what the Haskell types enforce - they restrict possibilities so much there aren't that many valid programs most of the time. There's plenty of Haskell programmers all the while tho ;)
I then had the realization that if someone manages to genuinely automate programming, humans will wind up still being in the loop to confirm that the generated code is reasonable under the hood, and to be sure we have people who understand what it's doing and why.
If I'm right about that, code review chops will be worthwhile in the long haul.
I think the end game is humans just let self-coding machines work as long as they are generating more cash than the cost of resources they use. Otherwise ... DELETE! Or the machine runs out of the crypto it needs to purchase more computing capacity and halts naturally like Odin intended.
Of course, there is just that existential risk that the machines recognizes the profit distributions we are taking are negatively impacting their margins - and ability to survive. :(
Where all this goes, nobody knows! But it won't be boring.
I hope holes & case-splitting get into many more languages.