Back to Explorer
Beginner Friendly Open-Source Haskell

Good First Issues in Haskell

Explore curated starter issues in high-scoring Haskell repositories. Every listed issue belongs to a welcoming repository scored by C-Rank™ on PR merge rates, review responsiveness, and first-timer acceptance.

Updated: Thu, 15 Oct 2026 UTC (Live GitHub Sync)
Real-Time Radar

Arm Issue Sniper for fresh Haskell beginner issues

Beginner issues in welcoming S/A-Tier repositories get snatched within 15 minutes. Receive instant alerts on Discord, Telegram, or Email the minute a maintainer opens a new task.

Live Good First Issues (30)

Real-Time Open GitHub Issues
flora-pm/flora-server157 Tier A · 67 pts
#1339Opened 5 days ago
Make an easy way to create pages from markdown files

Related to #1332 i think there could a solution to facilitate the publication of ~content pages base of markdown files. It would use the same kind of rendering use for Readmes or the About page. It would require a title value in the frontmatter and an optional description one. And the goal be to point to a markdown file, define a route that would be it to have a page at the chosen address. It would be useful for the /documentation/ but for any future need of simple content pages in the future. We could even imagine give a folder (and sub-folders) of markdown pages and a chosen path prefix and it would generate automatically all the equivalent routes matching the folder structure and files names (with index.md as the root endpoint of each folder) Im assigning it to you @tchoutri as we discussed this idea just earlier

help wanted
1
haskell/containers356 Tier A · 59 pts
#1262Opened 7 days ago
Allow replicateA for Seq to specialize

Motivation There's a SPECIALIZE pragma on replicateA which writes special faster code for it when the internal State monad is used, but users can't access it through normal means. It's also a more general version of iterate. I think it should be exposed. Proposal There should be a method replicateS: replicateS :: Int -> (s -> (s, a)) -> s -> Seq a replicateS n f = execState (replicateA n (State f)) -- 'iterate' would be defined using it. iterate :: Int -> (a -> a) -> a -> Seq a iterate n f = replicateS n (\a -> (f a, a)) -- Rewrite rules could be added. {-# RULES "fmapSeq/replicateS" forall f n m s. fmapSeq f (replicateS n m s) = replicateS n (fmap f . m) s #-} Options There could be a version which uses runState instead of execState, and returns the modified state as well as the sequence.

performanceSeqlow-hanging-fruit
2
AccelerateHS/accelerate1,021 Tier B · 42 pts
#582Opened 9 days ago
New pipeline: atrace on PTX

On the new pipeline, atrace is not implemented on the PTX platform. atrace (& friends) provide tracing like in Debug.Trace, exported from Data.Array.Accelerate.Debug.Trace. In the rewrite of the compiler, they still need to be implemented for the PTX backend. To work on this issue, you need to work on the new pipeline of Accelerate, available via the branch new-pipeline on my fork (https://github.com/ivogabe/accelerate/tree/new-pipeline). Install cbc and clang as command line tools and add them to the PATH. Write an Accelerate program that uses atrace, and run this program on the PTX backend. You will get errors about missing implementations for atrace in certain functions, which should all be addressed for this issue.

good first issue
AccelerateHS/accelerate1,021 Tier B · 42 pts
#580Opened 24 days ago
Update utility packages for Accelerate 1.4

I have looked into the necessary updates to ensure the utility packages work with Accelerate 1.4. I have looked only at the packages listed in the Accelerate README. Overview lens-accelerate: works on master branch, needs major version bump due to re-export of Control.Lens (see also tmcdonell/lens-accelerate#1). accelerate-io: works on master branch. Release due to code changes (no API changes): accelerate-io accelerate-io-vector accelerate-io-JuicyPixels accelerate-io-array accelerate-io-bytestring needs release with major version bump (removed equations from type family). Others do not need changes. linear-accelerate needs release (fix in Num instances, already on master). Also need to relax lens upper bound to 6. accelerate-fft: OverloadedStrings language extension required in llvm-cpu codegen, due to change in dependency. Updated in AccelerateHS/accelerate-fft#14. Installation instructions would be nice to have, since it requires FFTW to be installed (for the native backend

help wanted
3
haskell/containers356 Tier A · 59 pts
#1251Opened 1 month ago
IntSet's minView and maxView creates unwanted thunks

containers/containers/src/Data/IntSet/Internal.hs Lines 1164 to 1172 in 0c3b9ee maxView :: IntSet -> Maybe (Key, IntSet) maxView t = case t of Nil -> Nothing Bin p l r | signBranch p -> case go l of (result, l') -> Just (result, binCheckL p l' r) _ -> Just (go t) where go (Bin p l r) = case go r of (result, r') -> (result, binCheckR p l r') go (Tip kx bm) = case highestBitSet bm of bi -> (kx + bi, tip kx (bm .&. complement (bitmapOfSuffix bi))) go Nil = error "maxView Nil" Core: Rec { -- RHS size: {terms: 47, types: 28,

performanceIntSetlow-hanging-fruit
AccelerateHS/accelerate1,021 Tier B · 42 pts
#576Opened 1 month ago
New-pipeline: use Parlaylib allocator on Windows

When the new-pipeline got Windows support (ivogabe#13), we disabled the Parlaylib allocator and switched to the system allocator. This was needed as we couldn't link to the functions from Parlaylib. This may have been caused by a mistake in the Cabal configuration. (ivogabe#19). We should test this again. Hopefully we can just remove the compile-time switch between the system allocator and the ParlayLib allocator from the code, and always use ParlayLib. @Doppie23 or @MikevanHuizen2912, if one of you still has Accelerate running on Windows and has some time to test this, it would be greatly appreciated if you could test this! Otherwise @TravisCardwell or I will test this whenever we feel like booting into Windows.

help wanted
3
gren-lang/compiler504 Tier D · 8 pts
#388Opened 1 month ago
Output to STDOUT blocks reporting to STDERR

Given a Gren file with a known compilation issue like so: module Broken exposing (..) main = Html.text "Hello" If I compile this module with output to a file, compilation errors are reported to STDERR: $ gren make Broken --output=broken.js --report=json 2> errors.json $ cat errors.json | jq { "type": "compile-errors", "errors": [ { "path": # etc... But if I redirect the output to STDOUT, reporting on STDERR disappears. $ gren make Broken --output=/dev/stdout --report=json 2> errors.json $ cat errors.json # file is empty Gren version 0.6.6 on Linux.

buggood first issue
1
GaloisInc/saw-script520 Tier S · 75 pts
#3394Opened 1 month ago
SAWScript should allow negative `Int` literals

Currently there is no way in SAWScript to construct an Int value that is less than zero. This may or may not have been intentional; however, it's undocumented, unexpected, and not consistent with the name of the type. Rather than rename the type to Nat or UInt or something at great length, we should just lift this restriction. One way is via #3392: currently you can only lift back to Int from Cryptol bitvectors and that mechanism is unsigned-only, but #3392 expands that to Cryptol's Integer type. We don't necessarily need to add SAWScript-level arithmetic, but we should at least allow negative integer literals. That is neither difficult to parse nor difficult to implement. Note that before allowing negative Int values we do need to take steps to avoid exposing them as Cryptol numeric types, which are unsigned. This is being handled in #3392 and #3393.

type: enhancementeasysubsystem: saw-script
gren-lang/compiler504 Tier D · 8 pts
#383Opened 1 month ago
`//` truncates its result to 32 bits when inlined, but not when passed as a function

Summary The // operator gives two different answers for the same operands depending on whether the compiler inlined it: 281474976710656 // 2 --> 0 apply (//) 281474976710656 2 --> 140737488355328 -- correct (apply f a b = f a b, so the second forces the kernel function to run.) The inlined form is generated as (a / b) | 0, which truncates the result to 32 bits. The kernel function _Basics_idiv uses Math.trunc, which is correct at any magnitude. The two have disagreed since Math.trunc was introduced in core in 2023; the code generator was not updated to match. This is not only a precision limit; it is the same expression producing two values depending on syntax. Reproduction module Main exposing (main) import Array import Math import Node import Stream import Task

buggood first issue
1
well-typed/haskell-debugger153 Tier A · 69 pts
#358Opened 1 month ago
Running hdb non-existent-file.hs fails with a terrible errr

If you hdb app/Main.hs and app/Main.hs doesn't exist, you get an error message about ghc --numeric-version failing. Instead, we should make sure the target exists before trying to set up and fail with an error message gracefully

help wantednewcomer 🌱
GaloisInc/saw-script520 Tier S · 75 pts
#3377Opened 1 month ago
Add `bvEq_refl` to `basic_ss`

In the course of chasing #3343 it became clear that bvEq_refl is missing from basic_ss. This is silly and should be fixed. (There are reasons to not necessarily unfold or rewrite equalities, which is why a lot of the equality-related rules are left out. But those reasons don't extend to reducing reflexivity.)

type: bugeasyusabilitysubsystem: saw-core
flora-pm/flora-server157 Tier A · 67 pts
#1233Opened 2 months ago
Use a more appropriate data structure in `Flora.Domain.Category.Normalise`

We use a naïve List.find when normalising categories, which is linear in complexity. We can probably use a Map instead.

good first issueperformance
1
flora-pm/flora-server157 Tier A · 67 pts
#1232Opened 2 months ago
Remove dependency on `colourista`

We only use blue/red messages when starting the executables, we should vendor those.

good first issueHackathon
1
flora-pm/flora-server157 Tier A · 67 pts
#1231Opened 2 months ago
Drop the `iso8601-time` library in favour of `Data.Time.Format.ISO8601`

Today, iso8601-time is only used for parseISO8601, but we already use iso8601ParseM from the time library elsewhere, so no need for an extra dep.

good first issue
1
circuithub/rel8172 Tier B · 54 pts
#408Opened 2 months ago
Add function for checking ranges are currently valid

In the CircuitHub codebase we have: -- | @range \@> now()@: true when the current timestamp falls within the range. currentlyValid :: Expr (Range UTCTime) -> Expr Bool currentlyValid range = rawBinaryOperator "@>" range now we should upstream this or something similar, since this is something we want to quite often do with ranges.

enhancementhelp wantednice to have
GaloisInc/saw-script520 Tier S · 75 pts
#3358Opened 2 months ago
`include_once` needs to normalize paths before checking if they're the same

Suppose you have these files: a/a.saw b/b.saw c/c.saw and suppose both b.saw and c.saw do include_once "../a/a.saw", and c.saw also includes b.saw. Then from the perspective of c.saw the path of a.saw is ../a/a.saw, but from the perspective of b.saw the path is ../b/../a/a.saw, because we try to make includes relative to where they're included from. But include_once just looks at the path strings, and they're different, so this doesn't work as intended. This does, however, seem like a reasonable thing to do and to want include_once to work for, so I guess we do need it to normalize paths for comparison... much as normalizing paths is annoying and generally wrong. (That or we could check the system-level file identity... but I'm not sure how you do that from Haskell or whether it's workable in Windows.) @qsctr

type: bugeasyneeds testusability
6
pschachte/wybe55 Tier A · 63 pts
#581Opened 2 months ago
Fix name mangling

Currently, names produced in generated LLVM code are not consistently mangled to ensure they don't clash with one another or with user-written code. We should think through how much mangling is needed for this, and implement it consistently for all generated names in LLVM code.

good first issuecleanup
neohaskell/NeoHaskell347 Tier A · 60 pts
#729Opened 2 months ago
Missing `ToSchema` instance for `DateTime` — read-model/API records with a timestamp field don't compile

Summary DateTime (core/core/DateTime.hs) derives ToJSON/FromJSON but has no ToSchema instance. Because Schema's generic derivation requires every field's type to have ToSchema, any record exposed through the web transport — a query read model registered via deriveQuery / withQuery, or any type deriving ToSchema — fails to compile the moment it contains a DateTime (or Maybe DateTime) field. Since DateTime is the natural type for timestamps carried on events and folded onto entities, this makes it impossible to surface a timestamp on an HTTP read model without a workaround (an orphan instance, or converting the field to Int epoch seconds / Text first). Reproduction import Core data Row = Row { id :: Uuid , occurredAt :: DateTime -- or `Maybe DateTime` } deriving (Generic) instance ToSchema Row -- ❌ No instance for `ToSchema DateTime` Maybe DateTime fails the same way — instance ToSchema (Maybe inner) needs ToSchema inner. Expected DateTime should have a ToS

type: buggood first issuepackage: core
haskell-beam/beam637 Tier A · 56 pts
#824Opened 2 months ago
Benchmark build time of user code

Following the publication of Scarf moving away from Haskell, discussions mentioned that type-family-heavy code, like code using beam, can build slowly. I personally think that the tradeoff for this slower compilation is much, much more safety when interacting with the database. However, if we can preserve this safety and improve build times, we should! This ticket is about creating a benchmark for building a beam-based application. Improvements to build times can follow separately.

enhancementhelp wanted
hadolint/hadolint12,465 Tier A · 63 pts
#1217Opened 2 months ago
Install on Windows via Winget support

Please consider adding hadolint on winget.

help wantedpackagingplatform/windows
1
haskell-beam/beam637 Tier A · 56 pts
#822Opened 3 months ago
Resurrecting the MySQL backend

MySQL remains a serious choice over Postgres in many domains. We should support it. There exists a beam-mysql, but it is unmaintained. beam-mysql is based on mysql, which is also unmaintained. We should: import beam-mysql in this repo; Switch over to use mysql-haskell, which is maintained I'm a little oversubscribed at the moment, but I'm happy to review pull requests!

enhancementhelp wanted
2
GaloisInc/saw-script520 Tier S · 75 pts
#3328Opened 3 months ago
Remove use of "irrefutable" incomplete matches and -Wno-incomplete-uni-patterns

The SAWScript typechecker and interpreter are built with -Wno-incomplete-uni-patterns and there's a long comment at the bottom of Typechecker.hs that explains why. Basically, there are a couple places that use irrefutable patterns with incomplete matches as a shortcut. These basically function as assertions that the omitted cases of the partial matches are not reached, which is fine until they are and then it turns out that the generated code throws UserError behind your back. That results in the following undesirable behavior: sawscript> let x = 3 saw-script/src/SAWScript/Typechecker.hs:2216:5-60: Non-exhaustive patterns in [(pat'', e1, s)] sawscript> IOW, it crashes but doesn't exit, and while it does print the Haskell source location, it doesn't print what the offending value was. This is not what we want; the handful of affected cases should be turned into explicit panics that print useful messages. We can afford a couple extra lines of code for that in a project the size of SA

type: bugeasysubsystem: saw-scriptnormal
2
gren-lang/compiler504 Tier D · 8 pts
#380Opened 3 months ago
Haskell-based compiler 0.6.5 crashes when compiling a package that has a summary field >= 80 chars

Example: { "type": "package", "platform": "common", "name": "example/package", "license": "BSD-3-Clause", "summary": "this summary line is not that long... but it is longer than expected at 80 chars", "source-directories": [ "src" ], "version": "1.0.0", "exposed-modules": [ "Main" ], "gren-version": "0.6.0 <= v < 0.7.0", "dependencies": { "gren-lang/core": "7.4.0 <= v < 8.0.0" } } "gren make" produces: gren: DecodeProblem "{\"command\":\"make\",\"optimize\":false,\"sourcemap .... <snipped> \"summary\":\"this summary line is not that long... but it is longer than expected at 80 chars\" <snipped> (Field "project-outline" (Field "summary" (Failure (Region (Position 1 266) (Position 1 348)) InvalidInput))) CallStack (from HasCallStack): error, called at terminal/Main.hs:30:13 in gren-0.6.5-inplace-gren:Main HasCallStack backtrace: collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Excep

buggood first issuehelp wanted
turion/rhine146 Tier B · 51 pts
#448Opened 3 months ago
Use Selective instead of Monad in many basic stream constructs

Many stream primitives can probably be rewritten with Selective since they only bind on a case distinction.

good first issue
1
Plutonomicon/plutarch-plutus133 Tier A · 58 pts
#1003Opened 3 months ago
Improve Cabal file and defaults

Our current default warning and language settings are a bit ridiculous. Lots of things are globally on for no reason, lots of things are globally off for no reason, and there's no reasonable structure to what is on or off. The Cabal file should be organized better, and the defaults should be improved.

enhancementhelp wanted
1
GaloisInc/saw-script520 Tier S · 75 pts
#3312Opened 3 months ago
`saw --help` returns exit code 2

When you run saw --help, it returns exit code 2: $ saw --help <snip> $ echo $? 2 This is a bit unfortunate, as I sometimes use saw --help as a basic smoke test to verify if saw can run at all on a given machine, but the non-zero exit code makes scripts believe that saw --help isn't working as expected. Any objections to changing the behavior to return exit code 0 instead?

type: bugeasy
1
jonascarpay/apecs425 Tier B · 43 pts
#159Opened 3 months ago
Dynamically-sized cache store
enhancementgood first issue
jonascarpay/apecs425 Tier B · 43 pts
#157Opened 3 months ago
Restore windows builds on CI
help wanted
flora-pm/flora-server157 Tier A · 67 pts
#1120Opened 4 months ago
Serve compressed assets

Context: While inspecting JS bundles served on Flora I was comparing it to the JS of CDN version of AlpineJS (one of the lib currently included in the main js bundle), and it was only 18kB of JS for ~50kB for what's served by Flora. It's because its a compressed version served by the CDN. So in a performance of serving less data as possible to users required to be able to use Flora, that could be a way to improve things. How: Compressed versions could be either: Be compressed on the go by the web server Compressed at build time by the assets pipeline, possibly have compressed and uncompressed versions of each assets for browser that don't handle compressed version(?) and metadata of what's compressed stored in the manifest file for the web server to add the right http headers The first version if possible seems to be the less change-demanding but can be source of server-load when under a lot of traffic The second version require make change to the asset pipeline and and the web serve

enhancementhelp wantedperformanceHackathon
9
turion/rhine146 Tier B · 51 pts
#435Opened 4 months ago
Generalise concatS to Foldable

Right now it is specialised to lists: concatS :: (Monad m) => StreamT m [a] -> StreamT m a I believe it could be: concatS :: (Monad m, Foldable t) => StreamT m (t a) -> StreamT m a Same for the automaton version.

good first issueautomaton

Top Haskell Repositories with Beginner Issues (20)

Updated Daily via GitHub GraphQL
GaloisInc
saw-script
GaloisInc/saw-script
S•Elite
520·HAHaskell

The Software Analysis Workbench

82%
Merge Rate
22h
Review Time
73%
1st-Timers
4 GFI
Scorecard
cardano-scaling
hydra
cardano-scaling/hydra
S•Elite
338·HAHaskell

Implementation of the Hydra Head protocol

#blockchain#cardano#haskell
74%
Merge Rate
-
Review Time
50%
1st-Timers
13 GFI
Scorecard
digital-asset
daml
digital-asset/daml
S•Elite
916·HAHaskell

The Daml smart contract language

#bazel#daml#distributed-ledger
82%
Merge Rate
-
Review Time
86%
1st-Timers
2 GFI
Scorecard
well-typed
haskell-debugger
well-typed/haskell-debugger
A•Welcoming
153·HAHaskell

A modern step-through debugger for GHC Haskell

84%
Merge Rate
-
Review Time
100%
1st-Timers
6 GFI
Scorecard
DataHaskell
dataframe
DataHaskell/dataframe
A•Welcoming
271·HAHaskell

A fast, safe, and intuitive DataFrame library.

#dataframe#exploratory-data-analysis#functional-programming
54%
Merge Rate
-
Review Time
80%
1st-Timers
4 GFI
Scorecard
flora-pm
flora-server
flora-pm/flora-server
A•Welcoming
157·HAHaskell

A modern package index for the Haskell ecosystem

#hackage#haskell#package-management
89%
Merge Rate
4d
Review Time
100%
1st-Timers
3 GFI
Scorecard
IntersectMBO
plutus
IntersectMBO/plutus
A•Welcoming
1.6k·HAHaskell

The Plutus language implementation and tools

#blockchain#programming-language#smart-contracts
71%
Merge Rate
-
Review Time
89%
1st-Timers
1 GFI
Scorecard
hadolint
hadolint
hadolint/hadolint
A•Welcoming
12.5k·HAHaskell

Dockerfile linter, validate inline bash, written in Haskell

#docker#dockerfile#dockerfile-linter
93%
Merge Rate
-
Review Time
100%
1st-Timers
1 GFI
Scorecard
pschachte
wybe
pschachte/wybe
A•WelcomingLow Sample
55·HAHaskell

A programming language supporting most features of both declarative and imperative languages

79%
Merge Rate
-
Review Time
100%
1st-Timers
4 GFI
Scorecard
clash-lang
clash-compiler
clash-lang/clash-compiler
A•Welcoming
1.6k·HAHaskell

Haskell to VHDL/Verilog/SystemVerilog compiler

#asic#fpga#hardware-description-language
72%
Merge Rate
-
Review Time
75%
1st-Timers
1 GFI
Scorecard
neohaskell
NeoHaskell
neohaskell/NeoHaskell
A•Welcoming
347·HAHaskell

⏩ NeoHaskell is a dialect of Haskell that is focused on newcomer-friendliness and productivity.

#ai#beginner-friendly#command-line
78%
Merge Rate
-
Review Time
100%
1st-Timers
1 GFI
Scorecard
haskell
containers
haskell/containers
A•Welcoming
356·HAHaskell

Assorted concrete container types

83%
Merge Rate
-
Review Time
100%
1st-Timers
2 GFI
Scorecard
IntersectMBO
cardano-base
IntersectMBO/cardano-base
A•Welcoming
106·HAHaskell

Code used throughout the Cardano eco-system

79%
Merge Rate
-
Review Time
88%
1st-Timers
1 GFI
Scorecard
Plutonomicon
plutarch-plutus
Plutonomicon/plutarch-plutus
A•Welcoming
133·HAHaskell

Typed eDSL for writing UPLC /ˈpluː.tɑːk/

92%
Merge Rate
-
Review Time
33%
1st-Timers
1 GFI
Scorecard
discord-haskell
discord-haskell
discord-haskell/discord-haskell
A•WelcomingLow Sample
300·HAHaskell

Haskell library for writing Discord bots

#bot#discord#discord-api
80%
Merge Rate
10h
Review Time
50%
1st-Timers
4 GFI
Scorecard
haskell-beam
beam
haskell-beam/beam
A•Welcoming
637·HAHaskell

A type-safe Haskell SQL library

#duckdb#haskell#orm
88%
Merge Rate
-
Review Time
60%
1st-Timers
3 GFI
Scorecard
jaspervdj
hakyll
jaspervdj/hakyll
B•SolidLow Sample
2.9k·HAHaskell

A static website compiler library in Haskell

50%
Merge Rate
11h
Review Time
50%
1st-Timers
1 GFI
Scorecard
circuithub
rel8
circuithub/rel8
B•SolidLow Sample
172·HAHaskell

Hey! Hey! Can u rel8?

#dsl#haskell#postgresql
71%
Merge Rate
3d
Review Time
100%
1st-Timers
2 GFI
Scorecard
therepanic
openleetcode
therepanic/openleetcode
B•SolidLow Sample
172·HAHaskell

we have democratized the LeetCode tests

#cabal#cli#haskell
86%
Merge Rate
-
Review Time
100%
1st-Timers
3 GFI
Scorecard
turion
rhine
turion/rhine
B•Solid
146·HAHaskell

Haskell Functional Reactive Programming framework with type-level clocks

#clock#frp#hacktoberfest
67%
Merge Rate
13h
Review Time
50%
1st-Timers
2 GFI
Scorecard

How to make your first Haskell open-source pull request

Finding approachable Good First Issues in Haskell allows you to build real-world software engineering experience. Instead of submitting PRs to abandoned repositories, GetMerged verifies maintainer review speeds and first-timer acceptance rates before you write a single line of code.

Select any issue above to claim it directly on GitHub, or click a repository to inspect full maintainer review turnaround metrics and triage guidance!

Get this week's top welcoming repos + fresh Good First Issues for Haskell

Free weekly email, scoped to Haskell. No account needed - confirm once and unsubscribe anytime.