A rigorously structured, formally verified Haskell project template designed for mission-critical industrial applications. This template provides a comprehensive foundation for projects requiring high reliability, mathematical correctness, strong compile-time guarantees, and systematic error handling.
This template embodies industrial best practices for Haskell development:
- Formal Verification: Mathematical correctness through LiquidHaskell refinement types
- Comprehensive Type Safety: Advanced GHC features and strict type checking
- Systematic Error Handling: Explicit, type-safe error handling with complete context
- Clean Architecture: Hexagonal design with pure domain core and effectful boundaries
- Domain-Driven Design: Business logic expressed in types with strong invariants
- Production Readiness: Industry-tested patterns for robust, maintainable systems
Its primary goal is to provide a reliable starting point for developers building new mission-critical Haskell applications where correctness and maintainability are paramount.
- LiquidHaskell Integration: Refinement types for compile-time property verification
- Extensive Static Checking: Advanced GHC options with -Wall and custom warnings
- Linear Types: Resource tracking and consumption verification
- Domain Invariants: Business rules encoded at the type level
- Type-First Error Handling: Explicitly typed errors in all operations
- Rich Error Context: Complete debugging information in structured error types
- No Partial Functions: Total functions with explicit failure cases
- Error Boundaries: Clear separation between pure validation and effectful error handling
- Hexagonal Architecture: Pure domain core with adapters at boundaries
- Module Hierarchy: Structured organization of domain, components, and infrastructure
- Component Isolation: Well-defined interfaces with proper encapsulation
- Effect Separation: Pure core with effects isolated to boundaries
- Mission Statement: Template for defining project purpose and commitments
- Operational Context: Framework for defining operational scope and constraints
- User Experience Specification: Structure for comprehensive UX documentation
- Technical Guides: Templates for implementation details and standards
- Property-Based Testing: QuickCheck for mathematical property verification
- Error Path Testing: Comprehensive testing of error conditions and handling
- Environment Generators: Test utilities for component environments
- Error Assertions: Custom matchers for error validation in tests
- GHC 9.10.1: Latest Glasgow Haskell Compiler with GHC2024 language standard
- Cabal 3.14.1.1: Modern build system and package manager
- HLS 2.9.0.1: Haskell Language Server with IDE integration
- Z3 SMT Solver: For LiquidHaskell verification
- Cursor IDE Rules: Includes a comprehensive set of rules in
.cursor/rules/
specifically designed to guide AI assistants within the Cursor IDE. - Enforced Standards: These rules ensure AI contributions adhere to the template's strict standards for code quality, architecture, formal verification, error handling, and documentation.
- Consistent Development: Promotes consistent, high-quality, AI-assisted development aligned with the project's rigorous requirements.
-
Ensure you have GHCup installed to manage the Haskell toolchain.
-
Install required tools (exact versions required for reproducible builds):
# Core toolchain ghcup install ghc 9.10.1 ghcup install cabal 3.14.1.1 ghcup install hls 2.9.0.1 # Build tools cabal install happy-2.1.5 # Parser generator for LiquidHaskell cabal install alex-3.5.2.0 # Lexer generator cabal install hspec-discover # Test discovery tool
-
Verify Z3 installation (required for LiquidHaskell):
z3 --version # Should output version 4.14.0 or later
If Z3 is not installed, follow your system's package manager instructions or download from Z3's releases page.
-
Clone and customize the template:
git clone https://github.com/rbeauchamp/industrial-haskell-template.git my-project cd my-project
-
Initial Project Customization Checklist
After cloning, please complete the following steps to tailor the template to your project:
- Rename Project:
- Update
name:
inpackage.yaml
(e.g.,my-awesome-project
). - Update executable name (
industrial-haskell-template-exe:
) inpackage.yaml
(e.g.,my-awesome-project-exe:
). - Update library reference in executable dependencies (
industrial-haskell-template
) inpackage.yaml
if you changed the library name. - Consider renaming the
.cabal
file (after runninghpack
) if desired.
- Update
- Update Metadata (
package.yaml
):- Set
version:
appropriately (e.g.,0.1.0.0
). - Verify
license:
matches your intended license (currentlyUnlicense
). - Replace
author:
placeholder. - Replace
maintainer:
placeholder. - Update
copyright:
placeholder. - Update
git:
URL placeholder (e.g., tohttps://github.com/your-username/your-repo-name.git
). - Update
description:
placeholder (ensure link points to your final repo URL).
- Set
- Core Documentation:
- Adapt/replace
docs/mission-statement-template.md
with your project's mission. (Consider renaming the file). - Adapt/replace
docs/operational-context-template.md
with your project's context. (Consider renaming the file). - Adapt/replace
docs/user-experience-spec-template.md
with your project's UX spec. (Consider renaming the file).
- Adapt/replace
- Review Configuration (Optional but Recommended):
- Review dependency versions in
package.yaml
. - Review enabled GHC extensions in
package.yaml
. - Review
ghc-options
inpackage.yaml
for library, executable, and tests. - Review linting rules in
hlint.yaml
.
- Review dependency versions in
- Rename Project:
-
Build the project:
cabal build
-
Run the test suite:
# On Windows test.bat # On Linux/macOS ./test.sh
project-root/
├── app/
│ └── Main.hs - Application entry point
├── src/ - Source code
│ ├── Control/ - Effect management and error handling
│ │ └── Error.hs - Unified error handling framework
│ ├── Data/ - Core data types and pure implementations
│ │ ├── NonEmptyText.hs - Non-empty text type with compile-time verification
│ │ └── VerifiedText.hs - Example of runtime validation for refined types (NonEmptyText)
│ ├── Domain/ - Domain types with business rule validation
│ └── Config/ - Application environment and configuration
│ ├── AppEnv.hs - Environment composition
│ └── AppM.hs - Application monad with error handling
├── test/ - Test suite
│ ├── Spec.hs - Test entry point
│ ├── Control/ - Tests for effect management
│ ├── Data/ - Tests for data types
│ ├── Config/ - Tests for configuration
│ └── TestUtils/ - Test utilities and generators
│ ├── AppEnvGenerator.hs - Test environment generators
│ └── ErrorAssertions.hs - Error testing utilities
├── docs/ - Documentation
│ ├── mission-statement-template.md - Project purpose template
│ ├── operational-context-template.md - System constraints template
│ ├── user-experience-spec-template.md - User experience specification
│ └── guides/ - Implementation guides
│ ├── idiomatic-error-handling-guide.md - Error handling patterns
│ └── math-notation-guide.md - Mathematical documentation standards
├── .cursor/rules/ - Cursor AI coding assistant rules
│ ├── code-quality.mdc - Code quality standards
│ ├── formal-verification.mdc - Verification requirements
│ ├── idiomatic-error-handling.mdc - Error handling patterns
│ ├── module-architecture.mdc - Module organization rules
│ └── no-linter-suppressions.mdc - Linter compliance requirements
├── .vscode/ - VS Code configuration
│ ├── settings.json - Editor settings
│ └── launch.json - Debugger configuration
├── package.yaml - Package definition (source of truth)
├── cabal.project - Cabal project configuration
├── hlint.yaml - HLint configuration
├── test.bat - Windows test script
└── test.sh - Linux/macOS test script
# Build all components
cabal build
# Run tests (important: use the test scripts for proper .tix file handling)
# On Windows:
test.bat
# On Linux/macOS:
./test.sh
# Interactive development with REPL
cabal repl
The project uses Hspec for testing with support for property-based tests via QuickCheck.
The recommended way to run the full test suite is using the provided scripts:
# On Windows: test.bat
# On Linux/macOS: ./test.sh
For more specific test runs, you can use cabal test
directly:
# Run tests with detailed output
cabal test --test-show-details=direct
# Run specific tests with pattern matching
cabal test --test-option='--match' --test-option="PATTERN"
# Run only focused specs (marked with 'fit' or 'focus')
cabal test --test-option='--focused-only'
# Rerun failed tests
cabal test --test-option='--rerun'
# Reproducible test runs with specific seed
cabal test --test-option='--seed' --test-option=SEED_NUMBER
The template implements a robust error handling approach that:
- Makes errors explicit in function signatures
- Provides rich context for debugging
- Maintains pure error handling in domain logic
- Preserves referential transparency
-- Core error type with rich context
data AppError = AppError
{ errorMessage :: !Text -- Human-readable message
, errorContext :: !Text -- Function or operation name
, errorDetails :: !(Map Text Text) -- Additional debugging info
, errorCallStack :: !CallStack -- Source location tracking
}
-- Application monad with error handling
type AppM a = ExceptT AppError IO a
-- Pure validation with explicit errors
validateInput :: Input -> Either AppError ValidInput
LiquidHaskell refinement types express invariants at compile time:
-- Example refinement types
{-@ type NonNegative a = {v:a | v >= 0} @-}
{-@ type Percentage = {v:Double | 0.0 <= v && v <= 1.0} @-}
{-@ type SizedList a n = {v:[a] | len v == n} @-}
-- Functions with refinement type specifications
{-@ dividePositive :: Positive Double -> Positive Double -> Positive Double @-}
dividePositive :: Double -> Double -> Double
dividePositive x y = x / y
Domain types with built-in validation:
-- Smart constructor with validation
mkEntityId :: Text -> Either AppError EntityId
mkEntityId txt =
if isValidEntityId txt
then Right (EntityId txt)
else Left $ mkAppError "Invalid entity ID" "mkEntityId"
(Map.singleton "value" txt)
To adapt this template for your specific domain:
-
Define your domain types in the
src/Domain/
directory- Use smart constructors with validation
- Apply LiquidHaskell refinements for invariants
- Follow the error handling patterns
-
Create components following the module architecture
- Domain components for pure business logic
- Integration components for external systems
- Follow the hexagonal architecture pattern
-
Implement test coverage for all components
- Unit tests for basic functionality
- Property tests for mathematical properties
- Consider state machine testing for complex behaviors
-
Document architectural decisions
- Update the mission statement with your project's purpose
- Define your operational context
- Specify your user experience requirements
This template includes comprehensive documentation:
- Mission Statement Template: Define your project's purpose and goals
- Operational Context Template: Specify your system's constraints and boundaries
- User Experience Specification Template: Document interaction patterns and interfaces
- Idiomatic Error Handling Guide: Learn best practices for error management
- Mathematics Notation Guide: Standards for mathematical documentation
- Code Quality Rules: Comprehensive standards for code quality
- Module Architecture Rules: Guidelines for module organization
This project is released into the public domain under the Unlicense - see the LICENSE file for details.