Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Lang Haskell Library Dev

ASecurity

Haskell-specific library development patterns. Use when creating Haskell libraries, designing type-safe public APIs, organizing Cabal/Stack projects, writing property-based tests with QuickCheck, generating Haddock documentation, or publishing to Hackage. Extends meta-library-dev with Haskell tooling and idioms.

8 stars
0 votes
0 copies
0 views
Added 2/8/2026
documentationgobashtestinggitapidocumentation

Works with

api

Security Analysis

A93/100
highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned 2/12/2026

$npx -y skills add aRustyDev/ai --skill lang-haskell-library-dev --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lang Haskell Library Dev?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Lang Haskell Library Dev
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/arustydev-lang-haskell-library-dev/badge)](https://www.skillsdirectory.com/skills/arustydev-lang-haskell-library-dev)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: lang-haskell-library-dev
description: Haskell-specific library development patterns. Use when creating Haskell libraries, designing type-safe public APIs, organizing Cabal/Stack projects, writing property-based tests with QuickCheck, generating Haddock documentation, or publishing to Hackage. Extends meta-library-dev with Haskell tooling and idioms.
---

# Haskell Library Development

Haskell-specific patterns for library development. This skill extends `meta-library-dev` with Haskell tooling, type-driven design principles, and ecosystem practices.

## This Skill Extends

- `meta-library-dev` - Foundational library patterns (API design, versioning, testing strategies)
- `lang-haskell-dev` - Core Haskell language patterns and idioms

For general library concepts like semantic versioning and testing pyramids, see `meta-library-dev`. For Haskell fundamentals like type classes and monads, see `lang-haskell-dev`.

## This Skill Adds

- **Build tooling**: Cabal, Stack, package.yaml configuration
- **Type-driven API design**: Leveraging Haskell's type system for library interfaces
- **Module organization**: Best practices for exposing clean public APIs
- **Property-based testing**: QuickCheck patterns for library validation
- **Haddock documentation**: API documentation standards
- **Hackage publishing**: Package distribution and maintenance

## This Skill Does NOT Cover

- General library patterns - see `meta-library-dev`
- Core Haskell language features - see `lang-haskell-dev`
- Advanced type system features (GADTs, Type Families) - see `lang-haskell-advanced-dev`
- Web frameworks (Servant, Yesod) - see framework-specific skills
- Application development - see `lang-haskell-app-dev`

---

## Quick Reference

| Task | Command/Pattern |
|------|-----------------|
| New library (Cabal) | `cabal init --lib <name>` |
| New library (Stack) | `stack new <name> simple-library` |
| Build | `cabal build` / `stack build` |
| Test | `cabal test` / `stack test` |
| Documentation | `cabal haddock` / `stack haddock` |
| REPL with library | `cabal repl` / `stack ghci` |
| Publish (dry run) | `cabal sdist` / `stack sdist` |
| Upload to Hackage | `cabal upload <tarball>` |
| Check package | `cabal check` |
| Format code | `fourmolu` or `ormolu` |

---

## Project Structure

### Standard Library Layout

```
my-library/
├── my-library.cabal          # Cabal package description
├── stack.yaml                # Stack configuration (optional)
├── package.yaml              # hpack configuration (Stack alternative)
├── LICENSE
├── README.md
├── CHANGELOG.md
├── src/
│   ├── MyLibrary.hs          # Main module (re-exports public API)
│   ├── MyLibrary/
│   │   ├── Types.hs          # Public types
│   │   ├── Core.hs           # Core functionality
│   │   └── Internal.hs       # Internal implementation
│   └── MyLibrary/Internal/   # Private modules
│       └── Helpers.hs
├── test/
│   ├── Spec.hs               # Test entry point
│   ├── MyLibrary/
│   │   ├── TypesSpec.hs      # Unit tests
│   │   └── CoreSpec.hs
│   └── Properties.hs         # QuickCheck properties
├── benchmark/
│   └── Main.hs               # Criterion benchmarks
└── examples/
    └── Basic.hs              # Usage examples

```

### Module Visibility

```haskell
-- src/MyLibrary.hs (main entry point)
module MyLibrary
  ( -- * Core Types
    Config(..)
  , Document
  , ParseResult

    -- * Construction
  , defaultConfig
  , mkDocument

    -- * Operations
  , parse
  , render
  , validate

    -- * Error Types
  , ParseError(..)
  , ValidationError(..)

    -- * Re-export specific modules for advanced use
  , module MyLibrary.Types
  ) where

import MyLibrary.Types
import MyLibrary.Core
import qualified MyLibrary.Internal as Internal

-- Re-export selected functions
parse = Internal.parseImpl
render = Internal.renderImpl
```

---

## Cabal Configuration

### Required Fields (.cabal file)

```cabal
cabal-version:      3.0
name:               my-library
version:            0.1.0.0
synopsis:           A brief one-line description
description:
    A longer description of what this library does.
    .
    Multiple paragraphs are separated by a single dot line.

homepage:           https://github.com/username/my-library
bug-reports:        https://github.com/username/my-library/issues
license:            BSD-3-Clause
license-file:       LICENSE
author:             Your Name
maintainer:         you@example.com
copyright:          2025 Your Name
category:           Data
build-type:         Simple
tested-with:        GHC == 9.4.8
                  , GHC == 9.6.3
                  , GHC == 9.8.1

extra-doc-files:
    CHANGELOG.md
    README.md

extra-source-files:
    examples/*.hs
```

### Library Stanza

```cabal
library
  exposed-modules:
      MyLibrary
      MyLibrary.Types
      MyLibrary.Core

  other-modules:
      MyLibrary.Internal
      MyLibrary.Internal.Helpers

  -- Modules included but not exposed
  reexported-modules:
      Data.Text as MyLibrary.Text

  hs-source-dirs:      src
  default-language:    Haskell2010
  default-extensions:
      OverloadedStrings
      DeriveGeneric
      LambdaCase

  ghc-options:
      -Wall
      -Wcompat
      -Widentities
      -Wincomplete-record-updates
      -Wincomplete-uni-patterns
      -Wmissing-home-modules
      -Wpartial-fields
      -Wredundant-constraints

  build-depends:
      base              >= 4.14 && < 5
    , text              >= 1.2  && < 2.2
    , containers        >= 0.6  && < 0.8
    , bytestring        >= 0.10 && < 0.13
```

### Test Suite Stanza

```cabal
test-suite my-library-test
  type:                exitcode-stdio-1.0
  hs-source-dirs:      test
  main-is:             Spec.hs
  other-modules:
      MyLibrary.TypesSpec
      MyLibrary.CoreSpec
      Properties

  default-language:    Haskell2010
  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N

  build-depends:
      base
    , my-library
    , hspec             >= 2.7  && < 3
    , QuickCheck        >= 2.14 && < 3
    , hspec-discover    >= 2.7  && < 3

  build-tool-depends:
      hspec-discover:hspec-discover
```

### Benchmark Stanza

```cabal
benchmark my-library-bench
  type:                exitcode-stdio-1.0
  hs-source-dirs:      benchmark
  main-is:             Main.hs
  default-language:    Haskell2010
  ghc-options:         -Wall -O2 -threaded -rtsopts -with-rtsopts=-N

  build-depends:
      base
    , my-library
    , criterion         >= 1.5 && < 2
```

---

## Stack Configuration

### stack.yaml

```yaml
resolver: lts-22.7  # GHC 9.6.3

packages:
  - .

extra-deps: []

# Recommended flags
flags: {}

# Build options
ghc-options:
  "$locals": -Wall -Werror=incomplete-patterns

# Testing options
test:
  arguments:
    additional-args:
      - --color
      - --format=progress
```

### package.yaml (hpack alternative to .cabal)

```yaml
name: my-library
version: 0.1.0.0
synopsis: A brief one-line description
description: |
  A longer description of what this library does.

  Multiple paragraphs are supported.

github: username/my-library
license: BSD-3-Clause
author: Your Name
maintainer: you@example.com
copyright: 2025 Your Name
category: Data

extra-source-files:
  - README.md
  - CHANGELOG.md

dependencies:
  - base >= 4.14 && < 5
  - text >= 1.2 && < 2.2
  - containers >= 0.6 && < 0.8

ghc-options:
  - -Wall
  - -Wcompat
  - -Widentities
  - -Wincomplete-record-updates

default-extensions:
  - OverloadedStrings
  - DeriveGeneric
  - LambdaCase

library:
  source-dirs: src
  exposed-modules:
    - MyLibrary
    - MyLibrary.Types
    - MyLibrary.Core

tests:
  my-library-test:
    main: Spec.hs
    source-dirs: test
    ghc-options:
      - -threaded
      - -rtsopts
      - -with-rtsopts=-N
    dependencies:
      - my-library
      - hspec
      - QuickCheck
    build-tools:
      - hspec-discover

benchmarks:
  my-library-bench:
    main: Main.hs
    source-dirs: benchmark
    ghc-options:
      - -O2
      - -threaded
      - -rtsopts
    dependencies:
      - my-library
      - criterion
```

---

## Type-Driven API Design

### Smart Constructors

```haskell
-- Hide constructor, export smart constructor
module MyLibrary.Types
  ( Email       -- Type exported without constructor
  , mkEmail     -- Smart constructor
  , emailText   -- Accessor
  ) where

import Data.Text (Text)
import qualified Data.Text as T

-- Opaque type
newtype Email = Email Text
  deriving (Show, Eq)

-- Smart constructor with validation
mkEmail :: Text -> Either String Email
mkEmail input
  | T.null input = Left "Email cannot be empty"
  | '@' `T.elem` input = Right (Email input)
  | otherwise = Left "Invalid email format"

-- Safe accessor
emailText :: Email -> Text
emailText (Email txt) = txt
```

### Phantom Types for Type Safety

```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}

-- State machine encoded in types
data State = Draft | Published

newtype Document (s :: State) = Document Text

-- Only drafts can be edited
editDocument :: Text -> Document 'Draft -> Document 'Draft
editDocument newText _ = Document newText

-- Only drafts can be published
publishDocument :: Document 'Draft -> Document 'Published
publishDocument (Document txt) = Document txt

-- Published documents can be rendered
renderDocument :: Document 'Published -> Html
renderDocument (Document txt) = toHtml txt

-- Type-safe workflow
workflow :: Html
workflow =
  renderDocument $
    publishDocument $
      editDocument "Updated content" initialDraft
```

### Builder Pattern with Phantom Types

```haskell
data Incomplete
data Complete

data ConfigBuilder (s :: Type) = ConfigBuilder
  { _timeout :: Maybe Int
  , _retries :: Maybe Int
  , _endpoint :: Maybe String
  }

-- Start with incomplete config
emptyConfig :: ConfigBuilder Incomplete
emptyConfig = ConfigBuilder Nothing Nothing Nothing

-- Builder functions return incomplete
setTimeout :: Int -> ConfigBuilder s -> ConfigBuilder Incomplete
setTimeout t cfg = cfg { _timeout = Just t }

setRetries :: Int -> ConfigBuilder s -> ConfigBuilder Incomplete
setRetries r cfg = cfg { _retries = Just r }

-- Only setEndpoint returns Complete
setEndpoint :: String -> ConfigBuilder s -> ConfigBuilder Complete
setEndpoint e cfg = cfg { _endpoint = Just e }

-- Can only build from Complete
build :: ConfigBuilder Complete -> Config
build (ConfigBuilder (Just t) (Just r) (Just e)) =
  Config t r e
build _ = error "Impossible: Complete builder guarantees all fields set"

-- Usage: Type system enforces all fields are set
config = build $ setEndpoint "https://api.example.com"
              $ setTimeout 30
              $ setRetries 3 emptyConfig
```

### Leveraging Type Classes for Polymorphism

```haskell
-- Generic serialization interface
class Serialize a where
  serialize :: a -> ByteString
  deserialize :: ByteString -> Either String a

-- Provide instances for your types
instance Serialize Document where
  serialize = encodeDocument
  deserialize = decodeDocument

-- Functions polymorphic over Serialize
saveToFile :: Serialize a => FilePath -> a -> IO ()
saveToFile path value = BS.writeFile path (serialize value)

loadFromFile :: Serialize a => FilePath -> IO (Either String a)
loadFromFile path = deserialize <$> BS.readFile path
```

---

## Module Organization Patterns

### Internal Modules

```haskell
-- MyLibrary/Internal.hs
-- This module is in other-modules, not exposed-modules
module MyLibrary.Internal where

-- Internal functions used across the library
-- but not part of public API
internalHelper :: Text -> Result
internalHelper = ...
```

### Hierarchical Re-exports

```haskell
-- MyLibrary.hs (main entry point)
module MyLibrary
  ( -- * Re-export everything from Types
    module MyLibrary.Types
    -- * Re-export selected functions from Core
  , parse
  , validate
  , render
  ) where

import MyLibrary.Types
import MyLibrary.Core (parse, validate, render)
```

### Qualified Re-exports

```haskell
-- For users who want namespaced access
import qualified MyLibrary as ML
import qualified MyLibrary.Advanced as ML.Advanced

document = ML.parse input
result = ML.Advanced.complexOperation document
```

---

## Property-Based Testing with QuickCheck

### Arbitrary Instances

```haskell
{-# LANGUAGE DeriveGeneric #-}

import Test.QuickCheck
import Test.QuickCheck.Arbitrary.Generic

data Document = Document
  { docTitle :: Text
  , docContent :: Text
  , docTags :: [Text]
  } deriving (Show, Eq, Generic)

-- Automatic Arbitrary instance
instance Arbitrary Document where
  arbitrary = genericArbitrary

-- Or custom generators
instance Arbitrary Document where
  arbitrary = Document
    <$> genTitle
    <*> genContent
    <*> listOf genTag
    where
      genTitle = T.pack <$> listOf1 (choose ('a', 'z'))
      genContent = T.pack <$> listOf (choose ('a', 'z'))
      genTag = elements ["haskell", "library", "testing"]

-- Constrained generators
genValidEmail :: Gen Email
genValidEmail = do
  user <- listOf1 (choose ('a', 'z'))
  domain <- elements ["example.com", "test.org"]
  return $ Email (T.pack $ user ++ "@" ++ domain)
```

### Properties

```haskell
-- test/Properties.hs
import Test.Hspec
import Test.QuickCheck
import MyLibrary

spec :: Spec
spec = describe "Document properties" $ do

  describe "parse . render = id" $
    it "roundtrips successfully" $
      property $ \doc ->
        parse (render doc) === Right doc

  describe "parse validates input" $
    it "rejects empty titles" $
      property $ \content tags ->
        let doc = Document "" content tags
        in parse (render doc) `shouldSatisfy` isLeft

  describe "tag operations are idempotent" $
    it "adding same tag twice = adding once" $
      property $ \doc tag ->
        addTag tag (addTag tag doc) === addTag tag doc

  describe "parsing is total (never throws)" $
    it "handles arbitrary input" $
      property $ \(input :: Text) ->
        case parse input of
          Left _ -> True
          Right _ -> True
```

### Conditional Properties

```haskell
prop_sortedListHead :: [Int] -> Property
prop_sortedListHead xs =
  not (null xs) ==>  -- Precondition
  head (sort xs) === minimum xs

-- Better: Use forAll with constrained generator
prop_sortedListHead' :: Property
prop_sortedListHead' =
  forAll (listOf1 arbitrary) $ \xs ->
    head (sort xs) === minimum xs
```

### Invariants

```haskell
-- Check invariants hold after operations
prop_balancedAfterInsert :: Key -> Value -> Tree -> Bool
prop_balancedAfterInsert k v tree =
  isBalanced (insert k v tree)

prop_sizeAfterInsert :: Key -> Value -> Tree -> Property
prop_sizeAfterInsert k v tree =
  k `notMember` tree ==>
  size (insert k v tree) === size tree + 1
```

---

## Haddock Documentation

### Module Documentation

```haskell
{-|
Module      : MyLibrary
Description : Brief description of module purpose
Copyright   : (c) Your Name, 2025
License     : BSD-3-Clause
Maintainer  : you@example.com
Stability   : experimental
Portability : POSIX

Longer description of what this module provides.

= Usage

Basic usage example:

>>> import MyLibrary
>>> let doc = mkDocument "Hello"
>>> render doc
"<document>Hello</document>"

= Advanced Usage

More complex patterns and use cases.
-}
module MyLibrary where
```

### Function Documentation

```haskell
-- | Parse a document from text.
--
-- This function validates the input and returns either
-- a parse error or a valid document.
--
-- ==== Examples
--
-- Basic usage:
--
-- >>> parse "title: Hello\ncontent: World"
-- Right (Document {docTitle = "Hello", docContent = "World"})
--
-- Invalid input:
--
-- >>> parse ""
-- Left "Empty input"
--
-- ==== Notes
--
-- * Input must be UTF-8 encoded
-- * Title is required
-- * Content may be empty
--
parse :: Text -> Either ParseError Document
parse = ...

-- | Render a document to text.
--
-- The output format is compatible with 'parse':
--
-- prop> parse (render doc) == Right doc
--
render :: Document -> Text
render = ...
```

### Documenting Types

```haskell
-- | Configuration for the parser.
--
-- Use 'defaultConfig' or the builder pattern to construct.
data Config = Config
  { configTimeout :: Int
    -- ^ Timeout in seconds (must be positive)
  , configStrict :: Bool
    -- ^ Enable strict parsing mode
  , configEncoding :: Encoding
    -- ^ Character encoding to use
  } deriving (Show, Eq)

-- | Default configuration.
--
-- Equivalent to:
--
-- @
-- Config
--   { configTimeout = 30
--   , configStrict = False
--   , configEncoding = UTF8
--   }
-- @
defaultConfig :: Config
defaultConfig = Config 30 False UTF8
```

### Sections and Organization

```haskell
module MyLibrary
  ( -- * Types
    Document(..)
  , ParseError(..)

    -- * Construction
  , mkDocument
  , defaultDocument

    -- * Operations
    -- ** Parsing
  , parse
  , parseStrict
    -- ** Rendering
  , render
  , renderPretty

    -- * Utilities
  , validate
  , normalize
  ) where
```

### Code Examples in Documentation

```haskell
-- | Batch process multiple documents.
--
-- >>> let docs = [mkDocument "A", mkDocument "B"]
-- >>> mapM_ (print . render) docs
-- "<document>A</document>"
-- "<document>B</document>"
--
-- __Warning:__ This loads all documents into memory.
-- For large batches, use 'streamProcess' instead.
processBatch :: [Document] -> IO ()
processBatch = ...
```

---

## Publishing to Hackage

### Pre-publish Checklist

- [ ] Version bumped in .cabal (follow PVP)
- [ ] CHANGELOG.md updated
- [ ] All tests pass: `cabal test --test-show-details=direct`
- [ ] Documentation builds: `cabal haddock`
- [ ] Package builds: `cabal build all`
- [ ] No warnings: `cabal build -Wall -Werror`
- [ ] `cabal check` passes with no errors
- [ ] README.md is current and accurate
- [ ] LICENSE file included
- [ ] Tested with multiple GHC versions
- [ ] Hackage account credentials configured

### Package Versioning Policy (PVP)

Haskell uses PVP (A.B.C.D):

| Change Type | Version Update | Example |
|-------------|----------------|---------|
| Breaking API change | A.B → (A+1).0 | 1.2.0.0 → 2.0.0.0 |
| New functionality (compatible) | A.B.C → A.(B+1).0 | 1.2.3.0 → 1.3.0.0 |
| Bug fix (no API change) | A.B.C.D → A.B.C.(D+1) | 1.2.3.0 → 1.2.3.1 |

```cabal
-- Before: version 0.1.0.0
-- After adding compatible function: version 0.2.0.0
-- After breaking change: version 1.0.0.0
```

### Version Bounds

```cabal
build-depends:
    base              >= 4.14 && < 5
    -- Allow major version 4.14 through 4.x, but not 5.x

  , text              >= 1.2  && < 1.3
    -- Allow 1.2.x versions only

  , containers        >= 0.6  && < 0.8
    -- Allow 0.6.x and 0.7.x
```

### Building Distribution Tarball

```bash
# Check package is ready
cabal check

# Build source distribution
cabal sdist

# Check the tarball builds
cabal upload --publish <dist-newstyle/sdist/my-library-0.1.0.0.tar.gz> --dry-run

# Extract and test the tarball
cd /tmp
tar xzf my-library-0.1.0.0.tar.gz
cd my-library-0.1.0.0
cabal build
cabal test
```

### Uploading to Hackage

```bash
# First-time setup: Create ~/.cabal/config with Hackage credentials
# Or use environment variable
export HACKAGE_USERNAME=yourusername
export HACKAGE_PASSWORD=yourpassword

# Upload as candidate (test on Hackage but not published)
cabal upload path/to/my-library-0.1.0.0.tar.gz

# Publish from candidate
cabal upload --publish path/to/my-library-0.1.0.0.tar.gz

# Check package page
open https://hackage.haskell.org/package/my-library
```

### Documentation Upload

```bash
# Build documentation
cabal haddock --haddock-for-hackage

# Upload to Hackage
cabal upload -d <dist-newstyle/.../my-library-0.1.0.0-docs.tar.gz>
```

### Deprecating Packages

```cabal
-- In .cabal file
x-deprecated: Please use better-library instead
```

---

## Testing Patterns

### Unit Tests with HSpec

```haskell
-- test/MyLibrary/CoreSpec.hs
module MyLibrary.CoreSpec (spec) where

import Test.Hspec
import MyLibrary

spec :: Spec
spec = describe "Core functionality" $ do

  describe "parse" $ do
    it "parses valid input" $ do
      parse "title: Hello" `shouldBe` Right expectedDoc

    it "rejects empty input" $ do
      parse "" `shouldSatisfy` isLeft

    it "handles unicode" $ do
      parse "title: こんにちは" `shouldSatisfy` isRight

  describe "render" $ do
    it "produces valid output" $ do
      let doc = mkDocument "Test"
      render doc `shouldContain` "Test"

    context "with empty document" $ do
      it "returns empty string" $ do
        render emptyDocument `shouldBe` ""
```

### Test Organization

```haskell
-- test/Spec.hs
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

-- hspec-discover automatically finds all *Spec.hs files
```

### Testing with Temporary Files

```haskell
import System.IO.Temp (withSystemTempFile)

spec = describe "File operations" $
  it "saves and loads documents" $
    withSystemTempFile "test.doc" $ \path handle -> do
      hClose handle
      saveDocument path doc
      loaded <- loadDocument path
      loaded `shouldBe` Right doc
```

---

## Common Dependencies

### Core Libraries

```cabal
build-depends:
    base              >= 4.14 && < 5
  , text              >= 1.2  && < 2.2
  , bytestring        >= 0.10 && < 0.13
  , containers        >= 0.6  && < 0.8
```

### Parsing

```cabal
  , attoparsec        >= 0.13 && < 0.15
  , megaparsec        >= 9.0  && < 10
  , parser-combinators >= 1.2 && < 2
```

### Error Handling

```cabal
  , exceptions        >= 0.10 && < 0.11
  , transformers      >= 0.5  && < 0.7
```

### Testing

```cabal
  , hspec             >= 2.7  && < 3
  , QuickCheck        >= 2.14 && < 3
  , hspec-discover    >= 2.7  && < 3
```

### JSON

```cabal
  , aeson             >= 2.0  && < 2.3
```

---

## Anti-Patterns

### 1. Exposing Too Much

```haskell
-- Bad: Exposes internal implementation
module MyLibrary (module X) where
import MyLibrary.Internal as X

-- Good: Selective exports
module MyLibrary
  ( Document
  , parse
  , render
  ) where
```

### 2. Partial Functions in Public API

```haskell
-- Bad: Can throw exception
head' :: [a] -> a
head' (x:_) = x

-- Good: Total function
headMaybe :: [a] -> Maybe a
headMaybe (x:_) = Just x
headMaybe [] = Nothing
```

### 3. Over-Constrained Version Bounds

```haskell
-- Bad: Too restrictive
build-depends: text == 1.2.4.0

-- Good: PVP-compatible range
build-depends: text >= 1.2 && < 1.3
```

### 4. Missing Upper Bounds

```haskell
-- Bad: No upper bound (will break on major updates)
build-depends: aeson >= 2.0

-- Good: PVP upper bound
build-depends: aeson >= 2.0 && < 2.3
```

---

## Troubleshooting

### Cabal Hell (Dependency Conflicts)

**Problem:** Cannot satisfy dependency requirements

```
Resolving dependencies...
Error: Could not resolve dependencies
```

**Fix:** Use cabal's new-style builds (default in modern Cabal):
```bash
# Clear cache and rebuild
cabal clean
rm -rf dist-newstyle
cabal build

# Or use Stack which uses curated snapshots
stack build
```

### Haddock Fails to Build

**Problem:** Haddock parse errors

**Fix:** Check for:
- Unbalanced delimiters in documentation comments
- Invalid Haddock syntax (`>>>` for examples, `@` for code)
- Missing closing brackets in sections

```bash
# Build with verbose output
cabal haddock --haddock-options="--verbose"
```

### Package Check Errors

**Problem:** `cabal check` reports warnings/errors

**Fix:** Address each error:
- Add missing fields (synopsis, description, license)
- Fix version bounds
- Include all necessary files in extra-source-files

### Tests Pass Locally but Fail in CI

**Problem:** Different GHC versions or dependencies

**Fix:**
- Test locally with multiple GHC versions using Stack
- Use matrix builds in CI
- Pin resolver versions in stack.yaml

```yaml
# .github/workflows/ci.yml
strategy:
  matrix:
    ghc: ['9.2.8', '9.4.8', '9.6.3']
```

---

## References

- `meta-library-dev` - Foundational library patterns
- `lang-haskell-dev` - Core Haskell fundamentals
- [Haskell Package Versioning Policy](https://pvp.haskell.org/)
- [Cabal User Guide](https://cabal.readthedocs.io/)
- [Stack User Guide](https://docs.haskellstack.org/)
- [Hackage](https://hackage.haskell.org/)
- [Haddock Documentation](https://haskell-haddock.readthedocs.io/)
- [QuickCheck Manual](https://hackage.haskell.org/package/QuickCheck)

Attribution

aRustyDevaRustyDev
View sourceSee grades on GitHubMore from aRustyDev →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Context Fundamentals

Understand the components, mechanics, and constraints of context in agent systems. Use when designing agent architectures, debugging context-related failures, or optimizing context usage.

179001 votes

Architecture Diagram Creator

Create comprehensive HTML architecture diagrams with data flows, business context, and system architecture.

6661 votes

release-notes

Draft release notes and changelog entries from git history or merged PRs between two refs (tags/SHAs/branches), including breaking changes, migrations, and upgrade steps. Use when the user asks for release notes, changelog updates, or a GitHub Release draft.

1301 votes

docs-style-guide

Documentation style guide enforcer by @planetabhi. Applies and reviews the writing style guide when authoring or editing product documentation and tutorials. Use to check prose for voice, tense, word choice, inclusive language, formatting, code block, UI, Markdown, and number/date conventions.

11 votes

Docx

Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', '.dotx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx or .dotx files, inserting or replacing images in documents, performing find-and-replace in W...

1798860 votes
View all in documentation →