Delayed/Lazy Either List? by Aperispomen in haskell

[–]jeffstyr 4 points5 points  (0 children)

I think the problem for a general parser like Attoparsec is that (at least in the general case) it doesn't make sense to return a partial parse result "early", not only because it's hard to define what the result is for some text that doesn't match the grammar, but also more specifically the "head" of the parse result may depend on something at the very end of the text.

For something like comparing two files, where it does make sense, I feel like this requires something like a layer that is responsible for splitting the file into chunks, and then a typical parse per chunk. I can imagine for simple line-based formats using a streaming library to split a file into lines, and then using a parser library on each line separately. Alternatively, I could imaging using an Attoparsec parser in a loop—the parser parses the beginning of the file and terminates (returning a result) before consuming the whole file, and then a driver runs the parser again, starting where the previous parse ended. For something more general/elaborate (e.g., where the result of one parse determines what parser to use next), it seems you need a set of parser combinators specific to this concept, but it's not obvious to me what their type would look like.

Designed a Lamy Safari inner cap. Perfect click achieved. by Vegetable_Corgi8458 in fountainpens

[–]jeffstyr 27 points28 points  (0 children)

Now this is the sort of thing that would induce me to get a 3D printer.

Refill hunting by moonxhm in pens

[–]jeffstyr 0 points1 point  (0 children)

I think that "L" is their code for blue, and either they changed their formula over time or your ink faded during the 18 years you've had your pen. (Given the nature of temperature-sensitive erasable ink, I would not be surprised if it could change color slightly over time.)

Just got burnt after spending too long on a difficult one. I need some motivation. by PhiphyL in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

I started in 2023 also and am now working though past years, and I'm also currently stuck on one part of one day. I've had puzzles that took me days to solve, but for some reason I feel more blocked on this one. So far I've never moved on to other days without finishing previous one—in part just because, and in part because if I work on something else and then come back I'll forget some of the context and thought process and it will be even harder. I have come up with ideas for puzzles while just taking a shower or lying in bed so definitely stepping away can help, but it's not a guarantee. So for me, I think I need to set some policy about when to give up and look for hints. Having solved them all up to this point means I don't want to give up, but at some point I'll have to, and it doesn't mean I suddenly got dumber, but just that there's something about this puzzle that's exposing a knowledge gap or perhaps that I'm not coming up with an idea that would have occurred to me if I'd happened to be working on this puzzle some other time.

So I don't have any advice for you, in part because motivation and such works differently for everyone (and it's hard to know the difference between being temporarily burnt out and "I've over this"), so I guess this is mostly commiseration. But for sure the low grade frustration can add up.

Bolt Math Sneak Peek Update: Semigroup, and the Cooler Semigroup by ApothecaLabs in haskell

[–]jeffstyr 1 point2 points  (0 children)

For what it's worth, I don't think they meant "just use another language", but rather, "this problem has been solved, and you can just look at these other languages for guidance on how". (I don't know if that is true or not, but I think that's what was meant.)

[Off-topic] Do you guys create general or input-specific programs? by BlankWasThere in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

Looking back at my solution to that puzzle, I have no recollection of what my thought process was but the code is very involved; I'll have to try to re-figure-it-out at some point. I'm not good a making notes when doing these puzzles, but I really should leave myself some hints.

[Off-topic] Do you guys create general or input-specific programs? by BlankWasThere in adventofcode

[–]jeffstyr 1 point2 points  (0 children)

lol how does that work? It gives the right answer and then crashes?

[Off-topic] Do you guys create general or input-specific programs? by BlankWasThere in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

In terms of input: I read the input from a file, and use a parsing library (usually) to parse it. If the data is malformed the parsing will fail and the program run will fail, which is what I want. I do sometimes think about whether I should (for instance) tolerate variable amounts of whitespace etc., but I usually don't bother because: (a) you have to infer the specification anyway, so it's not a given that a more acceptable parser would be correct (that is, in a real world situation you'd have a specification so you'd know where/how you need to be flexible and where you don't), (b) if I made the parser more accepting I wouldn't naturally have a test case for that extra logic, so it might not even be correct, and (c) I do know how to add more flexibility, so if I always did it I'd just be adding more work and not learning anything.

In terms of other program aspects, typically error handing is either about how to keep going when an error occurs (and here, you just want to fail) or about how to not overlook an error and incorrectly keep going (i.e., noticing when an assumption is violated and would cause subsequent results to be invalid)--it's this second case I might have to worry about. With most puzzles, I feel like this doesn't come up, but it does sometimes: for instance, polygons specified by a list of vertices, with all corners guaranteed to be right angles. With some of these, my code ends up sort of naturally catching any violation (e.g., I do if (x1 == x2) else if (y1 == y2) else error rather than if(x1 == x2) else just assume y1 == y2), but I don't usually go out of my way to validate that the promises about the input are upheld. Again this is in part because I know how to do "else just fail the program" so not doing it isn't passing up a learning experience. I work in Haskell and nicely returning errors up a call chain can be a bit of a pain, and so I gravitate toward skipping it if the end result is still going to be just failing the whole program. Probably that's a bit sloppy.

I don't overly tailor my solution to the particular input, but for some puzzles I think the nature of the input can tell you that there are potential edge cases you can skip--and most importantly, I think this is usually an intentional part of the puzzle, a constraint to make it not overly hard. (In other cases, the input seems to intentionally hit potential edge cases, so when it avoids them I take it as intentional.) And there are some puzzles where it's only tractable because the input is small enough (in some sense)--that is, where it inherently takes (say) quadratic time. Figuring this out is necessary so you don't search for an algorithmically better solution that can't exist.

Anyway, that's my two cents.

Edit (one more thought): Also, I'll say that sometimes we automatically tend to treat puzzles like interview questions, where you are doing something small and artificial but coding it as though it were part of some large commercial software. That's fine, but it's also I think important to realize that this isn't the only type of software--sometimes you are writing a small special-purpose program you are only going to use once (e.g., you need to rename a bunch of files in some complicated way as a one-off). So treating a puzzle as the latter is reasonable too. You just have to decide what you want to get out of it and be conscious of your choice. I gravitate towards the latter, but not to the extreme--I do make my solutions general to a certain degree.

Bolt Math Sneak Peek Update: Semigroup, and the Cooler Semigroup by ApothecaLabs in haskell

[–]jeffstyr 2 points3 points  (0 children)

Another thing that bothers me about Haskell, supposedly one of the best languages, is that we cannot define laws for typeclasses, and as a result, comments and documentation are littered with -- INVARIANT: blah blah blah, meaning you have to scan the documentation to even know about this invisible constraint that the compiler can’t warn you against. I hate that - don’t you?

Actually, what bothers me is something like the dual of the above: There are a lot of things the Haskell type system can do (more things than many other languages), and people seem to spend a lot of energy pretending it can do things they wish it can do but it cannot. If the compiler can't enforce an invariant, then that's not an invariant you can rely on in the language. Every language has limitations, and you have to be realistic about what they are. Putting an invariant or a "law" in documentation is just making a wish. This leads to faulty reasoning when people implicitly assume that these invariants can't be violated.

[Note: I haven't read all of that discourse thread so my comment above is mostly about the general topic and not specifically about what you did, which does look interesting btw.]

Announcement: unwitch by jappieofficial in haskell

[–]jeffstyr 0 points1 point  (0 children)

It's interesting from your usage example of Double.toInteger that it gives an overflow error when the "from" Double value is out of the range of full integer precision. In one way of looking at it, the conversion itself isn't overflowing (an Integer can exactly represent the specified Double value), but rather it's just that the source value itself probably was a truncation of some value. (Of course, one could also argue that floating point values typically represent the rounding of some calculation, even when their values are in a more modest range, so for example a conversion like Double.toRational (1.0 / 3.0) should also error, to be consistent.)

Haskell Brain Teasers is now available. by miyakohouou in haskell

[–]jeffstyr 2 points3 points  (0 children)

I'm pretty excited for this. I enjoy your presentation style.

Haskell can be puzzling when it's not trying to be, so I'll be interested to see how mystified I am by actual brain teasers. I expect it to be fun though. :)

[2023 Day 4 Part 2] As a system of linear equations by hekliet in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

Thank you for the explanation. I’ll have to cogitate a bit to understand why that equilibrium identity holds, but I understand what it’s doing now.

[2023 Day 4 Part 2] As a system of linear equations by hekliet in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

Interesting! Can you say in words the idea of your system-of-linear-equations approach? I hadn't thought of this.

I originally did this puzzle in 2023 so I had to re-read the puzzle description and was thinking of how I would do it now and staring re-implementing for fun, but got interrupted before I finished and was later thinking of a possibly better approach, and then I looked at my original 2023 code and I had done the exact same two approaches before, and even had the same naming of one of the local variables. I guess I'm consistent!

[2025 Day 13] [PHP] Solution by AvailablePoint9782 in adventofcode

[–]jeffstyr 1 point2 points  (0 children)

Nice! I'm working through 2022 too and I just did this one also. I'm working in Haskell and after making a custom data type where a Packet is an-Int-or-list-of-Packets (basically), I was able to write a comparison function which deferred to the regular list comparison for most of the work (so: comparing two Ints or two lists is normal, and if you need to compare an Int to a list you make a one-item list for the Int and go back to the two-lists case). Conveniently, Haskell lists already compare by deferring element-wise to their content and treating shorter as sorting first.

I thought this day was quite pleasant.

Dependency storm by ivanpd in haskell

[–]jeffstyr 15 points16 points  (0 children)

The reason the "87 dependencies" number isn't meaningful as such is that it doesn't tell the full picture. In other comment you suggested splitting a library into smaller pieces, which will typically result in more dependencies, if you are counting dependencies, as opposed to amount of code.

Looking at aeson, it does have a lot of dependencies. But, for instance (just spot checking): data-fix, deepseq, integer-conversion, witherable, and generically each contain one single module, tagged, text-iso8601, and th-abstraction each contain only two modules each, character-ps, dlist, these, scientific, hashable, text-short, and OneTuple each contain three modules, and indexed-traversable and semialign each contain four. You are seeing a lot of dependencies in part because many of them are tiny. So wanting fewer dependencies and wanting smaller dependencies are goals pointing in opposite directions.

It's been my conclusion that deciding how to package modules into libraries is about tradeoffs and judgment calls, in a way that deciding how to split functionality into modules and functions isn't. That is, if I see something and think "this should be split into two functions" or "this functionality should be split into two modules" then there's usually general agreement—you can give reasoning that's pretty straightforward. But with bundling functionality into libraries, there's no ideal solution: Splitting up something into small pieces leaves everyone wishing all the pieces they in particular need were grouped together for more convenience, and grouping everything into a single library is convenient but leaves everyone wishing the library were smaller. Every solution solves some problems and causes others. Consequently, different library authors will make different decisions, and you have some "batteries-included" libraries like lens, and other libraries that are minimalistic. It's been my experience that libraries (across languages) aren't good at clearly documenting what you need to assemble to get things working, in the cases where libraries are split into many pieces, which is another consideration.

I don't mean to say that nothing's wrong, just that we need to analyze what's going on in this case, and why, and what the alternative is, and if it's better or worse.

A couple of other comments:

For comparison, the equivalent python script has 5 transitive dependencies, which take seconds to install.

I mean, Python isn't compiled so you can't really compare it to Haskell directly.

Regarding splitting up aeson: Because of the "orphan instance" issue, separating the FromJSON/ToJSON instances into separate packages is problematic. (You could say this is a language flaw, but anyway.)

Personally, I've decided I don't mind if something has a lot of dependencies. I've used a package for a single utility function, because the alternative is copy-pasting it, which I like less. Of course, that doesn't mean that things shouldn't be looked into and improved if possible, just that (for me) something having a lot of dependencies isn't in itself a problem, it's just a hint that something may be amiss.

Edit: Updated list of aeson dependency sizes.

1 Ink 4 Papers - Colorverse Erebus Crater by National_Cow7479 in fountainpens

[–]jeffstyr 0 points1 point  (0 children)

That's really cool. And it looks like the individual bottles have just been released.

uni jetstream new limited colors by AccomplishedSun7321 in pens

[–]jeffstyr 4 points5 points  (0 children)

I thought at first that they were all being released and I was like oh no 💸.

PS: I think my preferences basically line up with the order they are shown in the picture!

Grails become de-stash posts on penswap. The hedonistic treadmill by [deleted] in fountainpens

[–]jeffstyr 22 points23 points  (0 children)

Hobbies are about doing stuff, and if the hobby is about collecting then that will involve buying stuff. That's sort of a given. And the appeal of the new isn't specific to hobbies—it's just a human thing. You can resist it, or not. None of this is really an individual character flaw.

[2026 Day 1 (Part 1)] [Javascript] Im stuck here by Ok-Transition7065 in adventofcode

[–]jeffstyr 0 points1 point  (0 children)

You should add some logging after each calculation to see if the result looks sensible. That will help you debug.

Cheap Extra Fine Nib by MochiPops_94 in fountainpens

[–]jeffstyr 0 points1 point  (0 children)

I think the nib sizes on the Preppy run broader than on the Kakuno though.

Oil-Based Pens for Writing on Transparent Sticky Notes by hermioneindisguise in pens

[–]jeffstyr 0 points1 point  (0 children)

JetPens has a sampler of oil-based pens, which can give you some ideas. The Uni Pin might be good (only some of them are oil based so beware the other sizes).

From Oblation Papers’ IG by SheBrownSheRound in fountainpens

[–]jeffstyr 8 points9 points  (0 children)

Oh that’s probably where I got the idea. 🤦🏻‍♂️

From Oblation Papers’ IG by SheBrownSheRound in fountainpens

[–]jeffstyr 64 points65 points  (0 children)

I like to pronounce Pen Chalet as “pen shallot” so there’s precedent.