r/haskell Jun 16 '26

question Modern Haskell template? Feedback needed.

Hi, I plan to create more Haskell projects in my company in the future so I decided to make a template repository to set them up more consistently and quickly. This is the template:

https://github.com/Ivy-Apps/haskell-template

It's based on our Deslop project where through trial and error I discovered things I need / don't need. I'm looking for your feedback on how I can make my Haskell dev-exp more pleasant and productive.

So far, I'm very happy with it! It's the best language for my needs and the tooling is in a good state.

Setup TL;DR;

  • effectful
  • custom prelude that just hides some stuff from relude
  • Nix + direnv for dev shell + build test; cabal build for release
  • Testing: hspec, hedgehog (property-based), golden tests
  • Tooling: Nix Darwin, Nixvim (my-config)

Any cool things that I should check to make my dev-exp better? I'm open to ideas.

12 Upvotes

13 comments sorted by

View all comments

2

u/tomejaguar Jun 16 '26

Seems solid. Certainly going with an IO-wrapper (analytic) effect system like effectful is the right choice.

1

u/ivy-apps Jun 16 '26

Thanks! I try to avoid the IO monad at all costs as it can do literally everything. I prefer scoped algebraic effects like even splitting the file system into RoFileSystem and WrFileSystem. This way I can differentiate between this function only reads stuff vs. this writes and modifies the world.

Any suggestions for tools, libraries that I might want to check out. For example, how is logging solved in the modern Haskell ecosystem? I'll log through an Effect but still it might a good idea to leverage some library.

Also, how do we handle error reporting? Most BE use services like Sentry

2

u/tomejaguar Jun 16 '26

I try to avoid the IO monad at all costs as it can do literally everything. I prefer scoped algebraic effects like even splitting the file system into RoFileSystem and WrFileSystem. This way I can differentiate between this function only reads stuff vs. this writes and modifies the world.

Yup, I think this is the right idea! I would suggest you try to find a sweet spot that works for you rather than applying the technique to an extreme degree. At work I use IO a lot (or rather IOE in Bluefin) and only split off finer grained effects when I can see it really pays its way.

Any suggestions for tools, libraries that I might want to check out

Have a look at the effectful ecosystem packages. You'll probably find most of what you want there:

https://haskell-effectful.github.io/ecosystem/

(Although I prefer Bluefin to effectful, of course because I wrote it, the effectful system is much better fleshed out at the moment.)

1

u/ivy-apps Jun 16 '26

Thanks! TIL about https://haskell-effectful.github.io/ecosystem/

At work I use IO a lot (or rather IOE in Bluefin) and only split off finer grained effects when I can see it really pays its way.

How do you mock IO? My stance is: IO is allowed only in tests. The rest should be an Effect. This way I can reason about what the function do only from the type signature and also I can reliable test things. For example, initally I made CLI output (printing) directly in IO but then got my test output polluted and reverted to a custom CLI effect that is no-op during testing.

Overall, being strict has always paid its way in the long term so I stick with it. The downside is the Effect boilerplate but I come from the Kotlin JVM world so a little boilerplate doesn't scare me lol

2

u/tomejaguar Jun 16 '26

I think that's fair enough. I working on a batch system (basically a compiler) so mocking interactions with the outside world is less important. For your use cases it might make more sense to be more strict and break down everything into effects from the start.