/nw-fp-haskell
Haskell language-specific patterns, GADTs, type classes, and effect systems
$ npx -y skills add nWave-ai/nWave --skill nw-fp-haskell --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/nw-fp-haskell
Context preview
The summary Claude sees to decide when to auto-load this skill.
Haskell language-specific patterns, GADTs, type classes, and effect systems
SKILL.md
nw-fp-haskell.SKILL.mdname: nw-fp-haskell
agent: nw-functional-software-crafter
description: Haskell language-specific patterns, GADTs, type classes, and effect systems
user-invocable: false
disable-model-invocation: true
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
# 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)
data PaymentMethod
= CreditCard CardNumber ExpiryDate
| BankTransfer AccountNumber
| Cash
deriving (Eq, Show)
Record Types and Newtypes
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)
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)
-- (.) composes right-to-left
processOrder :: RawOrder -> Either OrderError Confirmation
processOrder = confirmOrder . priceOrder . validateOrder
Monadic Chaining with do-notation
placeOrder :: RawOrder -> Either OrderError Confirmation
placeOrder raw = do
validated <- validateOrder raw
priced <- priceOrder validated
confirmOrder priced
Applicative for Independent Validation
mkCustomer :: Text -> Text -> Either ValidationError Customer
mkCustomer rawName rawEmail =
Customer
<$> mkCustomerId 0
<*> mkCustomerName rawName
<*> mkEmailAddress rawEmailError-Accumulating Validation
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-circuitedUnlike `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.
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)
-- 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
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 0Custom Generator
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
{-# 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-Read more
name: nw-fp-haskell agent: nw-functional-software-crafter description: Haskell language-specific patterns, GADTs, type classes, and effect systems user-invocable: false disable-model-invocation: true
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
# 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)
data PaymentMethod = CreditCard CardNumber ExpiryDate | BankTransfer AccountNumber | Cash deriving (Eq, Show)
Record Types and Newtypes
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)
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)
-- (.) composes right-to-left processOrder :: RawOrder -> Either OrderError Confirmation processOrder = confirmOrder . priceOrder . validateOrder
Monadic Chaining with do-notation
placeOrder :: RawOrder -> Either OrderError Confirmation placeOrder raw = do validated <- validateOrder raw priced <- priceOrder validated confirmOrder priced
Applicative for Independent Validation
mkCustomer :: Text -> Text -> Either ValidationError Customer
mkCustomer rawName rawEmail =
Customer
<$> mkCustomerId 0
<*> mkCustomerName rawName
<*> mkEmailAddress rawEmailError-Accumulating Validation
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-circuitedUnlike `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.
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)
-- 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
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 0Custom Generator
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
{-# 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-AI agents that guide you from idea to working code, with human judgment at every gate. nWave runs inside Claude Code. It breaks feature delivery into seven waves (discover, diverge, discuss, design, devops, distill, deliver).
Repo: nWave-ai/nWave
Other skills on nwave.
- /nw-ab-critique-dimensions
Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation
Open skill - /nw-abr-critique-dimensions
Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation
Open skill - /nw-ad-critique-dimensions
Review dimensions for acceptance test quality - happy path bias, GWT compliance, business language purity, coverage completeness, walking skeleton user-centricity, priority validation, observable behavior assertions, traceability coverage, and walking skeleton boundary proof
Open skill - /nw-agent-creation-workflow
Detailed 5-phase workflow for creating agents - from requirements analysis through validation and iterative refinement
Open skill - /nw-agent-testing
5-layer testing approach for agent validation including adversarial testing, security validation, and prompt injection resistance
Open skill - /nw-architectural-styles-tradeoffs
Architectural style selection decision matrices, trade-off analysis, structural enforcement rules, and combination patterns. Load when choosing or evaluating architecture styles.
Open skill

