nw-fp-haskell
Haskell language-specific patterns, GADTs, type classes, and effect systems
Best use case
nw-fp-haskell is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Haskell language-specific patterns, GADTs, type classes, and effect systems
Teams using nw-fp-haskell should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/nw-fp-haskell/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How nw-fp-haskell Compares
| Feature / Agent | nw-fp-haskell | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Haskell language-specific patterns, GADTs, type classes, and effect systems
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# FP in Haskell -- Functional Software Crafter Skill
Cross-references: [fp-principles](../nw-fp-principles/SKILL.md) | [fp-domain-modeling](../nw-fp-domain-modeling/SKILL.md) | [pbt-haskell](../nw-pbt-haskell/SKILL.md)
## When to Choose Haskell
- Best for: correctness-critical systems | compiler-enforced purity | maximum type safety | financial systems
- Not ideal for: teams needing fast onboarding | rapid prototyping | .NET/JVM platform requirements
## [STARTER] Quick Setup
```bash
# Install GHCup (manages GHC, cabal, stack, HLS)
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
# Create project
mkdir order-service && cd order-service && cabal init --interactive
# Or: stack new order-service simple && stack build && stack test
```
**Test runner**: `cabal test` or `stack test`. Add `hspec`, `QuickCheck`, `hedgehog` to `build-depends`.
## [STARTER] Type System for Domain Modeling
### Choice Types (Sum Types)
```haskell
data PaymentMethod
= CreditCard CardNumber ExpiryDate
| BankTransfer AccountNumber
| Cash
deriving (Eq, Show)
```
### Record Types and Newtypes
```haskell
data Customer = Customer
{ customerId :: CustomerId
, customerName :: CustomerName
, customerEmail :: EmailAddress
} deriving (Eq, Show)
newtype OrderId = OrderId Int deriving (Eq, Ord, Show)
newtype EmailAddress = EmailAddress Text deriving (Eq, Show)
```
`newtype` is erased at compile time -- zero runtime overhead, full type safety.
### [STARTER] Validated Construction (Smart Constructors)
```haskell
module Domain.Email (EmailAddress, mkEmailAddress, emailToText) where
import Data.Text (Text)
import qualified Data.Text as T
newtype EmailAddress = EmailAddress Text deriving (Eq, Show)
mkEmailAddress :: Text -> Either ValidationError EmailAddress
mkEmailAddress raw
| "@" `T.isInfixOf` raw = Right (EmailAddress raw)
| otherwise = Left (InvalidEmail raw)
```
Export the type but not the constructor. Only `mkEmailAddress` can create values.
## [INTERMEDIATE] Composition Style
### Function Composition (Right-to-Left)
```haskell
-- (.) composes right-to-left
processOrder :: RawOrder -> Either OrderError Confirmation
processOrder = confirmOrder . priceOrder . validateOrder
```
### Monadic Chaining with do-notation
```haskell
placeOrder :: RawOrder -> Either OrderError Confirmation
placeOrder raw = do
validated <- validateOrder raw
priced <- priceOrder validated
confirmOrder priced
```
### Applicative for Independent Validation
```haskell
mkCustomer :: Text -> Text -> Either ValidationError Customer
mkCustomer rawName rawEmail =
Customer
<$> mkCustomerId 0
<*> mkCustomerName rawName
<*> mkEmailAddress rawEmail
```
### Error-Accumulating Validation
```haskell
import Data.Validation (Validation, failure, success)
mkCustomerV :: Text -> Text -> Validation [ValidationError] Customer
mkCustomerV rawName rawEmail =
Customer
<$> validateName rawName -- Validation [ValidationError] CustomerName
<*> validateEmail rawEmail -- all errors collected, not short-circuited
```
Unlike `Either` which stops at first error, `Validation` accumulates all failures via its `Applicative` instance.
## [INTERMEDIATE] Effect Management
Haskell enforces purity at the compiler level. `IO` in return type means side effects.
```haskell
calculateTotal :: Order -> Money -- Pure: compiler guarantees no side effects
calculateTotal order = sumOf (orderLines order)
saveOrder :: Order -> IO () -- Impure: IO in the type
saveOrder order = writeToDatabase order
-- calculateTotal CANNOT call saveOrder -- compiler error
```
### [ADVANCED] Three Layers Pattern (Hexagonal Architecture)
```haskell
-- Layer 1: Pure domain (no IO, no effects)
module Domain.Order (calculateDiscount, validateOrder) where
calculateDiscount :: Order -> Discount
calculateDiscount order
| totalLines order > 10 = Discount 0.1
| otherwise = Discount 0.0
-- Layer 2: Effect interfaces (type classes as ports)
class Monad m => OrderRepo m where
findOrder :: OrderId -> m (Maybe Order)
saveOrder :: Order -> m ()
-- Layer 3: IO implementations (adapters)
instance OrderRepo IO where
findOrder orderId = queryDatabase orderId
saveOrder order = insertDatabase order
```
**Effect libraries**: Effectful (recommended starting point, best performance) | mtl (existing codebases) | Polysemy (algebraic effect semantics).
## [INTERMEDIATE] Testing
**Frameworks**: QuickCheck (original PBT) | Hedgehog (integrated shrinking) | Hspec (BDD) | tasty (composable test tree). See [pbt-haskell](../nw-pbt-haskell/SKILL.md) for detailed PBT patterns.
### Property Test Example
```haskell
import Test.Hspec
import Test.QuickCheck
spec :: Spec
spec = describe "validateOrder" $ do
it "round-trips through serialization" $
property $ \order ->
deserializeOrder (serializeOrder order) === Right order
it "validated orders always have positive totals" $
property $ \rawOrder ->
case validateOrder rawOrder of
Left _ -> discard
Right valid -> orderTotal valid > Money 0
```
### Custom Generator
```haskell
import Data.Text (pack)
import Test.QuickCheck
genValidEmail :: Gen EmailAddress
genValidEmail = do
user <- listOf1 (elements ['a'..'z'])
domain <- listOf1 (elements ['a'..'z'])
pure (EmailAddress (pack (user ++ "@" ++ domain ++ ".com")))
```
## [ADVANCED] Idiomatic Patterns
### GADTs for State Machines
```haskell
{-# LANGUAGE GADTs, DataKinds #-}
data OrderState = Unvalidated | Validated | Priced
data Order (s :: OrderState) where
UnvalidatedOrder :: RawData -> Order 'Unvalidated
ValidatedOrder :: ValidData -> Order 'Validated
PricedOrder :: PricedData -> Order 'Priced
-- Type-safe transitions: only validated orders can be priced
priceOrder :: Order 'Validated -> Either PricingError (Order 'Priced)
priceOrder (ValidatedOrder d) = Right (PricedOrder (addPricing d))
```
### Lazy Evaluation for Decoupled Pipelines
```haskell
eligibleOrders :: [Order] -> [Order]
eligibleOrders = take 10 . filter isEligible . sortBy orderDate
```
## Maturity and Adoption
- **Steep learning curve**: Monads, type classes, category-theory vocabulary create significant onboarding barrier. Budget extra ramp-up time.
- **GHC extensions confusion**: Over 100 language extensions; knowing which to enable requires experience. Start with `GHC2021` defaults.
- **Space leaks from laziness**: Default lazy evaluation causes subtle memory issues. Requires profiling discipline and strict annotations.
- **Smaller talent pool**: Hiring Haskell developers harder than mainstream languages. Consider team sustainability before committing.
## Common Pitfalls
1. **Lazy space leaks**: Use `foldl'` (strict) instead of `foldl`. Use `BangPatterns` for strict accumulators.
2. **String vs Text**: Never use `String` ([Char]) for real data. Use `Data.Text` / `Data.ByteString`.
3. **Orphan instances**: Define instances in the module of the type or class. Use newtype wrappers otherwise.
4. **Over-abstracting with type-level programming**: GADTs and type families increase compile times and error complexity. Use for genuine safety gains.Related Skills
nw-pbt-haskell
Haskell property-based testing with QuickCheck and Hedgehog frameworks
nw-ux-web-patterns
Web UI design patterns for product owners. Load when designing web application interfaces, writing web-specific acceptance criteria, or evaluating responsive designs.
nw-ux-tui-patterns
Terminal UI and CLI design patterns for product owners. Load when designing command-line tools, interactive terminal applications, or writing CLI-specific acceptance criteria.
nw-ux-principles
Core UX principles for product owners. Load when evaluating interface designs, writing acceptance criteria with UX requirements, or reviewing wireframes and mockups.
nw-ux-emotional-design
Emotional design and delight patterns for product owners. Load when designing onboarding flows, empty states, first-run experiences, or evaluating the emotional quality of an interface.
nw-ux-desktop-patterns
Desktop application UI patterns for product owners. Load when designing native or cross-platform desktop applications, writing desktop-specific acceptance criteria, or evaluating panel layouts and keyboard workflows.
nw-user-story-mapping
User story mapping for backlog management and outcome-based prioritization. Load during Phase 2.5 (User Story Mapping) to produce story-map.md and prioritization.md.
nw-tr-review-criteria
Review dimensions and scoring for root cause analysis quality assessment
nw-tlaplus-verification
TLA+ formal verification for design correctness and PBT pipeline integration
nw-test-refactoring-catalog
Detailed refactoring mechanics with step-by-step procedures, and test code smell catalog with detection patterns and before/after examples
nw-test-organization-conventions
Test directory structure patterns by architecture style, language conventions, naming rules, and fixture placement. Decision tree for selecting test organization strategy.
nw-test-design-mandates
Four design mandates for acceptance tests - hexagonal boundary enforcement, business language abstraction, user journey completeness, walking skeleton strategy, and pure function extraction