But does it any more than a live editor and type checker? Can you actually create a program that does something?
* Elm because Elm focused on making the language pleasant to use, and Hazel is in the same tradition of combining HCI + PL
* ML because Hazel is a strict / eager language, and people talk of ML family languages, of which Haskell is one.
So I don't think omitting Haskell is meant to be a slap in the face.
biggest reason more haskelley syntax didnt/hasnt happen/ed is the current syntax engine does not support significant indentation. hazel concrete syntax isn't stable yet though we're also thinking seriously about semi-colons
Hazel: A live functional programming environment featuring typed holes - https://news.ycombinator.com/item?id=24299852 - Aug 2020 (14 comments)
Also:
Tylr: Demo of tile-based editing, a new kind of structure editing - https://news.ycombinator.com/item?id=27926758 - July 2021 (40 comments)
Agda has them too and they're more powerful there: https://agda.readthedocs.io/en/latest/language/lexical-struc...
Super useful for when you don't know what are you missing and get a type signature for it.
It's mostly useful for when you declare some `const foo: (bar: Bar) => Whatever` and in the midst of your implementation you don't know what you're missing.
Requires an advanced level in TS to be used to the max.
https://gcanti.github.io/fp-ts/modules/function.ts.html#hole
https://effect-ts.github.io/effect/effect/Function.ts.html#h...
const transformFoo: (foos: Foo[]) => Bar
and you start implementing it and get stuck with some callback or whatever you can put a `hole` and it will tell you the type signature of what you're missing.
we (team hazel) recently used that device in our typescript version of a hazel setup for typed-hole-contextualized code completion as described in https://dl.acm.org/doi/10.1145/3689728
[1] - https://www.manning.com/books/type-driven-development-with-i...
It was honestly one of the most productive environments I ever worked in, and I'm somewhat sad nobody else has implemented this.
The really neat thing was that the Ecliose Java compiler is built specifically to support the IDE, so all the the warning and error annotations in the editor come from the actual compiler even while you are typing. There is no separate parser and linter just for the editor. I believe that the ability to translate broken source files on a best effort basis is actually an offshoot from that functionality.
When it worked, it was really, really good, agree. My experience was that it usually didn’t though, swap branches a few times and the caches would be broken, time for “invalidate caches and restart”. Multiple times per week, each time it’d take an hour to re-index.. that was a lot of time we got back again when we switched to IntelliJ
You could literally start the skeleton of a webserver and gradually add functionality to it without recompiling and it would mostly "just work". Certain changes would require the app to be restarted.
I'm asking as I prefer strict compilers that force me to handle all cases.
In an ideal world, the codebase would be modular and testable and all those good things but I work in a large enterprise dev team and some of the codebase is many (many) years old and it's no longer feasible to refactor it into anything like what would be needed to allow the code to be modularized in such a way that would obviate the necessity to do the above.
It does sound like a good feature though - very few languages have opt-out type checking. This is much better than opt-in IMO.
func TestWhatever(t *testing.T) {
// ...lots of code
_, _, _, _, _, _, _ = resp3, resp4, fooBefore, subFoo, bar2, barNew, zap2
}
Like, I get it, it's a good feature, it caught quite a lot of typos in my code but can I please get an option to turn this checking off e.g. in unit tests? I just want to yank some APIs, look at their behaviour, and tinker a bit with the data.The go devs decided against this since they didn't want to build a highly optimizing (read: slow) compiler, but that is missing the point of developer ergonomics.
Most people nowadays ban building with warnings in CI and allow them during local development. But “CI” was barely a thing when go was developed so they just banned them completely. And now they are probably too stubborn to change.
Q. Why can’t I have feature X?
A. We thought of that already, and your opinion is wrong.
Q. But basically every other language in existence supports this. And it makes development easier. We would really, really like it. Please?
A. Apparently you don’t get it. Here’s a pointer to a 15 year-old post on a mailing list where the first time someone asked for this, we said no. Your opinion is wrong.
Sounds like we agree!
https://gist.github.com/umanwizard/9793393083a42db933579fe21...
func TestWhatever(t *testing.T) {
var resp3, resp4, fooBefore, subFoo, bar2, barNew, zap2 theirType
// ...lots of code
}
Alternatively, use '_' where they are being defined: // instead of
resp2, err := doit()
// use
_, err := doit()
If, and given this context it's likely, you're checking these errors with asserts, then either change the name of the error variable, predeclare the err name (`var err error`), or split it into multiple tests instead of one giant spaghetti super test.That said, in a code review, at a minimum, I would probably ask that these variables be checked for nil/default which would completely eliminate this problem.
$ cat foo.hs
something = to be done
x = x + 1
wat = x "¯\\_(ツ)_/¯"
main = print "hi"
$ ghc --make -O foo -fdefer-type-errors && echo sucesfuly compoiled && ./foo
[1 of 1] Compiling Main ( foo.hs, foo.o )
foo.hs:2:13: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: to :: t1 -> t2 -> t
|
2 | something = to be done
| ^^
foo.hs:2:16: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: be
|
2 | something = to be done
| ^^
foo.hs:2:19: warning: [-Wdeferred-out-of-scope-variables]
Variable not in scope: done
|
2 | something = to be done
| ^^^^
Linking foo ...
sucesfuly compoiled
"hi"
$
Typed holes (but not the defer- option) have been enabled by default for some time now. They're an immediate go-to when scratching my head over types. I prefer them to the type error output, not only because they give better suggestions, but also because they can be named (_a, _conversionFunction, etc).
Found hole `_' with type f (Free f b)
and relevant bindings, if applicable: Relevant bindings include
>>= :: Free f a -> (a -> Free f b) -> Free f b
(bound at holes.hs:28:3)
f :: f (Free f a) (bound at holes.hs:29:8)
g :: a -> Free f b (bound at holes.hs:29:14)
In the first argument of `Free', namely `_'
Very useful for working your way out of a situation where the specific incantation to get to the right type isn't obvious.Examples from [0].
and here's me speaking last week about using typed holes and the hazel language server to help provide code context for LLM code completion: https://www.youtube.com/watch?v=-DYe8Fi78sg&t=12707s
As in, is this “just” a less boilerplate-heavy version of that, or is it more capable?
But small question related to https://hazel.org/build/dev/, given
> Non-empty holes are the red boxes around type errors
... why is the case statement in the list example red-boxed?
Because that case is non-exhaustive. It will match a list with 0, 1, or 2 elements, but the last arm matches a list with exactly 2 elements, not 2 or more, so as soon as you get to 3 or more elements, there’s no code to execute.
Here are some of the biggest questions I have:
Do you have any plans to bring editor gaps to languages other than Hazel?
Why is the Hazel editor first a text editor? E.g. it seems 100% happy to let a single poorly judged keystroke create an unbalanced brace or quote pair when it has much more semantically correct options for the next state it could generate...
P.S. Feel free to come check out BABLR: https://github.com/bablr-lang/, https://discord.gg/NfMNyYN6cX
For example in VSCode if I type ( the editor inserts () -- it's actually not a text edit in the sense that the code I produced doesn't map 1:1 to the keys I pressed. No, what actually happened there was already a semantic edit. It was quick and efficient. One keypress. Having a busted document is a worse experience than that, and having a document which is in a sort-of-busted-ghost-mode is also a worse, less semantic experience than I already have. Why would I want either of those experiences for myself or others?
in general though i have mixed feeling about making structured editing more text-like; the above is just about trying to patch a hole in existing structured editors, which doesn't in-itself improve on text. i think we can do better than that; we're exploring more radical directions in a separate project. but i do think it is interesting to see how close to regular text entry we can stay while always maintaining a well-formed (though incomplete) parse state which we can use to constantly run type-checking and evaluation.
the current model partially succeeds in the above, but at some significant usability cost, including the fact the the backpack obscures what the actual underlying parse state is. the ghost model i'm describing can basically be thought of a generalization of the vscode parentheses insertion you describe; it just works for every multi-delimiter form (eg when you insert 'let' you get ghosts '=' and 'in', with appropriate holes inserted). the utility is (A) the same as an incremental parser in a language server (you get semantic feedback in every state), but because of the ghost/hole insertions it's crystal clear what the parse state is that you're getting feedback from. but yeah the current version doesn't live up to that standard
Recovering from bad parses is the state of the art in the industry right now, but it suffers from the "garbage in garbage out" problem because the user's intent is lost. In point of fact it is never captured in the first place! When you say that typing `let` ghosts out should all that other stuff, that's based on pure assumption. The state of the editor would look just the same if the user was part way through typing out the word `letter` which they intended to use as an identifier. No technology in the world can make things right after the user's intent has been lost.
The real way forward, the direction nobody is looking, is how to make tools that are more like musical instruments. An instrument doesn't guess at your intention and then aim to please you, but rather it amplifies the importance of each decision and impulse that go into playing it, making the player more expressive then they could have been otherwise.
And it had a release today.
https://www.noodlesoft.com/release_notes
Seems rough to jump on a name that's been in continuous use for that long. Would it be hard to add another word to make it easier to disambiguate?
Jokes aside, name collisions are bound to happen. These two apps seem entirely unrelated so I doubt anyone will accidentally install "Hazel, the Mac app for organizing folders and files" when they meant to use "Hazel, the live functional programming environment organized around type holes."
I can position the cursor by tapping and I get a virtual keyboard but I can't type anything.
Is this a bug or am I just missing something because If terrible UX?
I prefer to have code layered in a way that my inflection points happen across well defined interfaces. Then I can make changes one layer at a time in increments that are small enough to still be able to reason about. But maybe I am totally mising the point of typed holes!
A hole is the answer to this question. You ask the compiler "what abstraction is missing?" and it tells you.
let comparison =
(0 == 0, 0 < 1, 1 <= 1, 2 > 1, 1 >= 1)
in
Anyone know why "in" keyword?Haskell does the same thing.
Hazel appears to be written in ocaml and mentions being "ml-like" on the site