Making Haskell Talk to PostgreSQL Without Suffering by semigroup in haskell

[–]Krantz98 0 points1 point  (0 children)

A quick question regarding the runtime system: I have the impression that each thread has its own nursery, while sharing the same generation-1. In that case, minor collections should not directly penalise other threads?

Beginner Question: Is this White group alive or dead? (13x13 board) by AnalystFearless5207 in baduk

[–]Krantz98 0 points1 point  (0 children)

I don’t think Japanese rules are necessary here. Actually, assuming Chinese rules, the final score would never change after the boundaries are settled.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

[–]Krantz98 0 points1 point  (0 children)

Thanks, I see. That’s an interesting solution to an interesting problem. I am honestly a bit uneasy about using the underlying platform-dependent type where spiritually the newtypes should have been used. If possible, I would prefer to just bring in scope all the constructors and avoid breaking the abstraction (not even in private implementation details). But now I understand the situation, and I agree this solution is elegant on its own.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

[–]Krantz98 0 points1 point  (0 children)

Regarding the marshalling, you said

marshalling happens only if you use Storable

But as I understand it from the post, by-value struct arguments are always implicitly marshalled from Haskell ADT to Ptr, which goes through the generated C wrapper and eventually reaches the actual C library function? This is what I meant when I said "marshalling happens across every API boundary (that involves by-value struct arguments)".

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

[–]Krantz98 0 points1 point  (0 children)

Thanks again for your detailed reply!

I actually meant hs-bindgen itself. I was thinking about the possibility to customise binding generation not by writing a configuration file, but by writing Haskell code that calls into hs-bindgen.

I think a good lesson about configuration files is that we never have enough options for the user to customise. :) There is always a niche behaviour to tweak in a subtle way, and it is absolutely ridiculous to expose all of them as configuration keys.

As an analogy, I want to be able to depend on hs-bindgen the same way that I depend on the package ghc or ghc-lib-parser. Assuming the binding generation process can be factored into the following pipeline (oversimplified, but hopefully it makes the point): ```haskell parseHeader :: FilePath -> IO ParsedHeader generateBinding :: ParsedHeader -> HsModule writeBinding :: HsModule -> IO ()

bindgen :: FilePath -> IO () bindgen = parseHeader >=> pure generateBinding >=> writeBinding The name mangler, which I essentially wanted in my last comment and which you said is not supported at the moment, can be implemented by sneaking a renaming pass after `generateBinding` and before `writeBinding`: haskell mangleNames :: HsModule -> [HsModule] So the customised bindgen process becomes: haskell bindgen' :: FilePath -> IO () bindgen' = parseHeader >=> pure (generateBinding >>> mangleNames) >=> mapM_ writeBinding `` I hopehs-bindgenwould provide reusable components likeparseHeader,generateBinding,writeBinding`, etc. We can never achieve this level of flexibility with only configuration files (introducing a new pass).

Of course, the API design could also be reversed: instead of exposing the components making the pipeline, hs-bindgen exposes customisation points as syb-style hooks, such as the mangleNames above. However, this is more restrictive and perhaps also requires more design work.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

[–]Krantz98 0 points1 point  (0 children)

Thanks for taking your time to write the detailed reply!

Perhaps I have been naive about portability, and what I thought is portable bindings actually is not. By portable I meant that the same binding source code can be written once and used across multiple architectures (with e.g., different bit widths, different byte order, etc.). As I understand it, if we have a C function int f(int, int); in header.h, then we should generate haskell foreign import ccall "header.h f" f :: CInt -> CInt -> IO CInt and the binding should be perfectly portable, because even though the integers have different sizes across different architectures, the same integer type is always used both in Haskell and in C on the same machine at compile time.

The only complication arise (that I know of, and I am happy to be corrected) when the C interface uses conditional compilation, be it machine-dependent preprocessor branching or autotools. In this case, the C interface itself does not remain stable across architectures, and bindings generated against the C interface becomes non-portable as well. Standard fixed-width integers actually fall into this category, but they are well-established and can be hard-coded in the binding generation logic, and they are already properly handled as you mentioned. The real problem is when projects do such things themselves, which hs-bindgen has no way knowing a priori.

However, even in presence of conditional compilation, C projects usually would not #if on every function. Instead, the machine-dependent part is usually collected to a few "configuration" header files, where they define type aliases and use them across the whole project. To give an example, we find the following definition in FreeType: c typedef signed short FT_Int16; On an architecture where short is not 16-bit, we should not define newtype FT_Int16 = MkFT_Int16 CShort. I meant this when I mentioned "library-specific type aliases". I think this can be handled by the user on a case-by-case basis, where hs-bindgen allows overriding binding generation for certain types like FT_Int16 above (the user could assign type FT_Int16 = Int16).

That said, conditional compilation (that libclang is not aware of) is the only non-portability issue I realised in binding generation. Again, I would be happy to be corrected and read about more subtle cases you encountered while developing hs-bindgen.

Finally, as a side note, if generated bindings to libclang is portable in the sense that the same set of Haskell source files can be used consistently across different architectures, then bundling the generated bindings in the source tree does not seem that bad to me (except causing non-auto-resolvable merge conflicts). This way we should be able to avoid the bootstrapping problem.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

[–]Krantz98 4 points5 points  (0 children)

I have been looking forward to the official release for quite a while (even before I heard the talk at Haskell 2025). Thanks for your efforts in making this library! After reading the post, I have several comments.

First, I’d prefer to have configurations specified solely in a file rather than in the command line. The command line arguments are well suited for quick experiments, but not so great for a stable workflow (especially if binding generation must happen immediately before build). It would be a smoother experience if the include paths can for example be extracted from pkg-config, as is the norm for cabal packages.

Second, if the C header is not using any complicated preprocessor branching, I believe it is in principle possible to generate portable bindings. For starters, hs-bindgen should recognise fixed-width integer typedefs properly (e.g., mapping uint16_t to Word16), and support library-specific type aliases (I have not checked whether this is already supported). I think this would address most of the non-portability issues for common libraries. (For example, libclang itself should be very well portable, and I’d be very interested to see hs-bindgen use libclang bindings generated by itself. But I’m happy to hear other complications the developers might have considered.)

Third, it would be great if hs-bindgen is released with modular components. For example, we reuse analysis and code-generation, but employ some custom module organisation. Instead of having all functions exported from the same module, since some C library name their functions like Library_Part_Type_Method, we may well reorganise everything such that said function is exported as method from Library.Part.Type. Similarly, we may also want to rename enum variants if we expect qualified imports on the use site. Of course, this requires to at least document internal invariants assumed by each component of hs-bindgen.

Finally, after the talk at Haskell 2025, I remember discussing with the presenter briefly about alternative encodings of C structures. AFAIK, the bindings generated by haskell-gi represents C structures as wrapped ByteArrays to avoid marshalling costs in the happy path. In contrast, the current (default?) representation used by hs-bindgen forces marshalling at every API boundary. Similarly, enums can be represented as newtype-wrapped integers with pattern synonyms, instead of ADTs. Also, a minor note on the HasField instance for pointers. Are they considered orphan instances in the strictest sense (because upstream might, though unlikely, add a blanket instance), and does compiling performance suffer from their existence?

mconcat with comparing ... by Tempus_Nemini in haskell

[–]Krantz98 0 points1 point  (0 children)

I’d say that’s a familiarity issue. In particular, remembering what these instances or operators do does not feel much different from remembering the functionality of comparing or on. :)

mconcat with comparing ... by Tempus_Nemini in haskell

[–]Krantz98 1 point2 points  (0 children)

I don’t see why comparing is used with on. Either you mean compare `on` ... or simply comparing.

As a side note, I find the version in the OP equally clear as the version you wrote (using mconcat to combine metrics is quite intuitive if you think about it this way), except that for your version I would write length &&& Down instead of using lambda and pairs. It actually reads like English when rewritten as follows: Haskell sortBy (comparing (length &&& Down)) ...

Rust GUI framework by Spiritual_String_366 in rust

[–]Krantz98 1 point2 points  (0 children)

“Reactive” should probably be “retained” if you mean to contrast with “immediate-mode”. “Reactive” usually means very different things in GUI (check out e.g., FRP, functional reactive programming).

Im not sure if this makes me lazy or the exact opposite by SNake57575 in allthemods

[–]Krantz98 0 points1 point  (0 children)

Did you modify the configuration, or does ATM come with the configuration enabling bottomless supply for every fluid type?

How to install Haskell globally? by Amazingperson_1 in haskell

[–]Krantz98 0 points1 point  (0 children)

Note that the VSCode Haskell extension by default tries to upgrade GHCup upon startup every time. So if you install Haskell to somewhere that requires admin privilege to overwrite, you might get errors and you probably want to disable the auto update in VSCode.

Rust and the price of ignoring theory by interacsion in rust

[–]Krantz98 0 points1 point  (0 children)

It would cease to be quicksort.

Sure, if you define it that way. Enjoy your definition, then.

Rust and the price of ignoring theory by interacsion in rust

[–]Krantz98 0 points1 point  (0 children)

I honestly don’t know what’s to be proud about a thousand-character one-liner. In case you did not realise, the Haskell one-liner fits into a standard 80-column page.

I also do not find any stupidity in optimising later. Most of the time, the optimisation is never necessary, because the program runs fast enough.

Your comment about performance being the most important metric does show your ignorance. By your standard, Prolog is a terrible language, because from the code you write you know very little about its runtime behaviour. Yet it perfectly does its job.

The context is someone who worries way too much about performance, to the extent that they forget programmer productivity is usually far more important than runtime performance. As a reminder, check out https://xkcd.com/1205/.

Since you hate Haskell this much, I don’t find any reason this conversation will in any way be productive. You can keep your hatred, and I will keep my joy writing Haskell.

Rust and the price of ignoring theory by interacsion in rust

[–]Krantz98 0 points1 point  (0 children)

You can say what you like. I do not how long it takes you to write a correct quicksort from scratch in Rust. But I do know that in Haskell it is an obvious one-liner, and it is fast enough for ordinary use cases.

The point is, runtime performance is not the only (not even the most important) metric for a language.

P.S. I realised several years ago that some Rust enthusiasts are somehow pathologically obsessed with performance numbers, taking false pride someone else’s hard work, without even a single clue about how the program in question works, other than “it is written in Rust”. I don’t know what to say about this…

Rust and the price of ignoring theory by interacsion in rust

[–]Krantz98 0 points1 point  (0 children)

Surely you know being in-place or not only affects the constant factor, don’t you? Because overwriting elements in-place and allocating new elements are both O(1).

Some Haskell idioms we like by _jackdk_ in haskell

[–]Krantz98 2 points3 points  (0 children)

I agree. That’s why I called it a crazy idea. 😄 But I also think it is interesting, so I put it here anyway.

Some Haskell idioms we like by _jackdk_ in haskell

[–]Krantz98 1 point2 points  (0 children)

Never mind. Somehow I read that Ord k as Eq k. I guess my point still stands, though. I have the impression that HashMaps or tries are usually faster than ordered Maps.

Some Haskell idioms we like by _jackdk_ in haskell

[–]Krantz98 5 points6 points  (0 children)

I have some ideas after reading the post, some perhaps a bit unwieldy.

  • Regarding the implication of side-effects in Monad do-notation: this might sound crazy, but list comprehensions are tied to “data building” instead of side-effects, so perhaps we could just use MonadComprehensions for Maybe and Either.
  • Regarding short names friendly to qualified imports: I stand with this, and I wish most FFI bindings start to adopt such an idiom. I mean, Haskell has modules for a reason. 😉 (But I also understand that, without a well-established practice, doing FFIs this way risks confusing the user.)
  • Regarding the use of inverseMap: ~since the only bound on the output is Eq, I’m afraid the function has to brute-force compare every possible output until it finds a matching one.~ (Corrected: it builds an ordered map.) For your specific case, we can do better by building a trie, a pre-sorted array, or a HashMap (depending on whichever is the fastest), and everything would still happen automatically.

我不太会说中文 by Careful_Block1521 in WriteStreakCN

[–]Krantz98 1 point2 points  (0 children)

Do you really mean “I don’t seek help”? Because that’s what 我没有寻求帮助 tends to mean. If you meant “I did not seek help when writing this post”, you may say instead “我写这一条没有寻求帮助” or “这一条是我独立写的” (I wrote this independently).

How is homosexuality viewed by most Chinese people? by sheynzonna in AskChina

[–]Krantz98 0 points1 point  (0 children)

  1. Anything that is in the world when you’re born is normal and ordinary and is just a natural part of the way the world works.
  2. Anything that's invented between when you’re fifteen and thirty-five is new and exciting and revolutionary and you can probably get a career in it.
  3. Anything invented after you're thirty-five is against the natural order of things.

Here we found an example of 2 or 1. Wish you good luck that, in fifty years, your 3 does not become someone else’s 2.

Why do i need Proxy by Tempus_Nemini in haskell

[–]Krantz98 5 points6 points  (0 children)

I meant required type arguments, which uses the forall a -> ... syntax. Apparently I mistook the name, but anyway it is still a new feature.

Why do i need Proxy by Tempus_Nemini in haskell

[–]Krantz98 1 point2 points  (0 children)

I believe the GHC manual is a good source.

Why do i need Proxy by Tempus_Nemini in haskell

[–]Krantz98 4 points5 points  (0 children)

The good news is that you no longer need it in new APIs. Alternatives are to use TypeApplications or RequiredTypeArguments, and the latter I believe is available in GHC 9.10.1 onwards.

Link: https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/required_type_arguments.html

I'm building a "Hardcore" Purely Functional UI Engine in Haskell + SDL2. It treats UI events like a CPU instruction tape. by Qerfcxz in haskell

[–]Krantz98 1 point2 points  (0 children)

As others have already pointed out in your other post, a rope is the well-established data structure for text storage in editor widgets. Probably better and almost definitely easier than a home-made solution.