A Newcomers Friction and Fun

I’m quite new in my journey into Haskell and want to share some points of friction and enjoyment

  • The interaction of ghcup, stack, cabal and the language server have been my biggest time sink when moving between projects, cloning others repos. I found initial set up was quite straight forward following ghcup guides and helix is my preferred editor and the language server just worked initially. As soon as I started cloning other repos or trying out different projects with cabal and stack the pain commenced. Guilty confession, I’ve done multiple nukes.
  • The import conventions, pragma, preludes, modules, etc. is something I’m a little nervous about having to deal with as it doesn’t seem intuitive at this stage.
  • Hoogle is great but as a newcomer it is information overload at times. Often I wish I could just find an example code snippet but am lost somewhere deep in a series of -> -> -> entries. I am assuming this will get better with familiarity.
  • I find Haskell code is often really nice to read and that has been a big motivator in keeping on with learning the language.
  • I don’t know whether I have to opt in to some of the ghc compiler flags that would appear to have no downside (-Wincomplete-uni-patterns for example) when switching between ghc versions.
  • Analysis paralysis about packages has been quite real for me. For example, I have used the fpcomplete haskell articles and they espouse the benefits of rio but it’s failing tests and the most recent issue is from 2023 so did the community move away from that or did the base library adopt/change things? I hope I feel more comfortable with these decisions in time.
  • Indentation has been a frequent source of errors; I am indebted to ormolu.
  • :t in ghci is the best thing since sliced bread
    Thanks for having me and hopefully in time I can get up to speed and become a contributor not just a consumer.
28 Likes

Can you be more specific?

What exactly didn’t work as expected?

+1 Can we make exposed functions without examples in the docstring a compiler error? :wink:

There is also :i for even more info.

3 Likes

Welcome to Haskell :wave: Hope you have a great time with the language!

  • The import conventions, pragma, preludes, modules, etc. is something I’m a little nervous about having to deal with as it doesn’t seem intuitive at this stage.

I’d honestly not worry about any of those at this stage. By the time you start to feel the pain of any missteps on those fronts, you’ll be much better equipped to make decisions. You can go quite far just having a single module with a wall of imports and language extensions at the top.

  • Hoogle is great but as a newcomer it is information overload at times. Often I wish I could just find an example code snippet but am lost somewhere deep in a series of -> -> -> entries. I am assuming this will get better with familiarity.

Yeah, reading Haskell type signatures is pretty much like learning to ride a bike. Very scary at first, doesn’t actually take long to get used to and once you’re used to it, you don’t even notice it anymore. And the same goes for indentation.

All of that said, this made me realize how awesome an LLM-powered Hoogle could be. I.e. an LLM between the user and Hoogle’s search feature.

7 Likes

Welcome! These are great getting-started-experience notes, so thanks! You are a contributor already. I’ll share my 2c:

The interaction of ghcup, stack, cabal and the language server have been my biggest time sink when moving between projects, cloning others repos. I found initial set up was quite straight forward following ghcup guides and helix is my preferred editor and the language server just worked initially. As soon as I started cloning other repos or trying out different projects with cabal and stack the pain commenced. Guilty confession, I’ve done multiple nukes.

I can certainly believe this.
The full details are probably lost in time and/or far too much work to recount, but I’m sure any more you remember would be interesting.

The import conventions, pragma, preludes, modules, etc. is something I’m a little nervous about having to deal with as it doesn’t seem intuitive at this stage.

  • pragmas: I assume this mainly means GHC language extensions. I have never paid much attention to them; I just learned the most useful ones lazily when GHC told me which one to add, to permit some code I had written. I’d do a little research at that time to check that extension’s reputation, since I know not all of them are wise to use, eg because they have been superseded or because they make error messages more obscure. If writing new code, I’d probably stick GHC2024 in my cabal file or wherever to be sure I’m using modern defaults.

  • preludes: As a learner, just stick with the standard prelude. None of the others have achieved widespread use.

  • modules: The way GHCI in particular handles packages, files, modules, and namespaces is pretty confusing. If that’s causing problems, I would study the GHC(I) user guide once for background knowledge. (I strongly recommend this for GHC, cabal and stack generally, also.)

  • imports: The variations of import syntax, can be a bit confusing in the beginning. I’d keep import’s doc, and/or a bunch of existing Haskell code examples handy. The location (package and hierarchical module name) of things you may want to import, can also be confusing; keep hoogle handy, plus skim some of the module outlines and haddocks of core packages like base, containers, time, etc. Be aware that you can occasionally find the same module name provided by multiple packages - it’s rare, but confusing when it happens; that’s when the PackageImports extension is useful.

Hoogle is great but as a newcomer it is information overload at times. Often I wish I could just find an example code snippet but am lost somewhere deep in a series of → -> → entries. I am assuming this will get better with familiarity.

Perhaps collecting a few code bases with similar level / topic to what you’re doing can be a good source of examples. Github code search might also be worthwhile.

I don’t know whether I have to opt in to some of the ghc compiler flags that would appear to have no downside (-Wincomplete-uni-patterns for example) when switching between ghc versions.

As a learner, I wouldn’t bother with anything non-default unless you hit some real need. When you are shipping complex packages and needing to prevent bugs and build failures, that’s a good time to crank up the warnings and add -Werror.

Analysis paralysis about packages has been quite real for me. For example, I have used the fpcomplete haskell articles and they espouse the benefits of rio but it’s failing tests and the most recent issue is from 2023 so did the community move away from that or did the base library adopt/change things? I hope I feel more comfortable with these decisions in time.

Yes, rio hasn’t achieved much traction in the wider haskell sphere. I’d guess you’d see it used quietly in industrial codebases. Like custom preludes feel free to use it for learning or building but you’ll be a bit apart from the mainstream learning resources.

Generally to get a sense of what’s being actively used, check the hackage page for recent upload dates and reverse dependencies. You can also ask in chat, or you can check what’s packaged in stackage LTS.

Indentation has been a frequent source of errors; I am indebted to ormolu.

You do get used to this. I use simple two-space indents in VS Code, and simply add more or less when it shows me red squiggles.

:t in ghci is the best thing since sliced bread

So is ghcid for rapid compiler feedback, and so is mouse-over in VS Code + HLS if you get those set up.

5 Likes

As the original poster mentioned helix, the equivalent to show type signatures of expressions and names would be space + k. Also. some other useful lsp features are found in the ‘space’ namespace, like space+s to search symbols (bindings in the current module), and others in the “g” namespace. like gd (go to definition, sadly this only works for the current package’s binding, at least for hls)

EDIT: Some more tips.

You (@greyMonads) mentioned issues with hls regarding switching between projects, here are some tips that have worked for me (keep in mind this is only as a hobbyist):

  • Before loading a whole new project (just after a git clone for example), check what’s the recommended tool (cabal/stack) for building it, and which ghc versions it supports.
  • After that, I’d do a full build from the cli (stack build/cabal build), sometimes it can take a bit long due to a new compiler and/or different library versions that might not be cached in your system.
  • Then, if the build works, hls should also work. When you open the project with helix, any lps issues now would be due to the hls setup and not the project itself.
  • If there are issues check the helix log (:log-open), and try to run haskell-language-server-wrapper from the root of your project to debug issues.
2 Likes

Hi @greyMonads, thanks so much for writing this up. There is a very narrow window in which a new user (of anything) can describe their experience, because after a short period they stop being a new user and easily forget what it was like :slight_smile:

10 Likes

Yes, certainly. I had written a small command line app in Rust prior to this so had come in fairly used to cargo new, cargo add, cargo run, cargo build (that’s not to say it’s not without it’s warts but for a new user cargo was straight forward to use). As a result, I think a lot of my pain was from making incorrect assumptions instead of readingtfm. Here are some of the notes from my haskell diary that I think relate to what you’re asking about,
“Does setting base in build-depends .cabal automatically adjust ghc to suit. Maybe ghc-options set ghc version?”
“If I set a specific compiler version with ghcup does that mean it’s then the one that’s on the PATH? Ghcup command to check which is currently set?”
“Can you make a project with both cabal and stack and they both know of each others existence and can build the same project and have the same structure???”
“So many 10+ year old cabal questions on stack, don’t think they’re relevant any more but not sure”
“Stack sits on top of cabal? Stack not just dependency management but can build too. People using stack install for packages: do these not download the code from some repository automatically? Is this separate from projects?”
“VScode HLS extension wants to use GHC 9.8.4 even when I over ride with settings.json - don’t know if vscode extension, HLS, or ghcup incorrectly setting that version???”
“Helix worked with HLS on first installation, fk ye”
there are more (where’s an embarrassed emoji?)

3 Likes

I really appreciate those tips for switching between projects and will get to have a try later this week so am looking forward to that.

1 Like

They are all in PATH. E.g. ghc-9.4.8. The one you set will be the one that is “unqualified”: ghc.

4 Likes

Helix is great, however browsing other’s projects with it due to the immediately kicking in language server can be a pain and a huge resource hog. For that reason I disable it by default in my helix config and mapped two keys to start/quit any LSP

[editor.lsp]
display-inlay-hints = true
display-messages = true
# disable by default to make browsing source files quick and easy
enable = false

[keys.normal]
# toggle LSP
A-q = [":lsp-stop", ":set-option lsp.enable false"]
A-l = [":set-option lsp.enable true", ":lsp-restart"]

This way I can browse anything without fear of starting a huge background compilation. The small price is that sometimes I need to start the LSP twice to get helix into the right state.
Another advantage is that if the LSP crashes or misbehaves it is easy to restart it without losing the editor’s full state.

3 Likes