haskell-type-designlisted
Install: claude install-skill ivelten/claude-haskell-skills
# Haskell Type Design
Write the types first, then the function falls out. This is the central discipline: the type signature constrains the implementation so tightly that wrong code usually doesn't type-check.
## Type-Driven Design
1. **Domain first, functions second.** Sketch the algebraic data types for the problem before any logic. Sum types (`data Status = Pending | Approved | Rejected Reason`) replace state-tracking booleans and string-typed enums.
2. **Newtypes for every primitive that has meaning.** `newtype UserId = UserId Int64` and `newtype Email = Email Text` cost nothing at runtime and prevent entire classes of bugs at the type level. Use `deriving newtype` for the underlying instances you actually want exposed:
```haskell
newtype UserId = UserId Int64
deriving stock (Show, Eq, Ord)
deriving newtype (FromJSON, ToJSON)
```
3. **Make functions total.** No `head`, no `fromJust`, no `error` in business logic. Return `Maybe a` or `Either MyError a`. The `safe` package provides `headMay` etc. if you want it.
4. **Parse, don't validate.** A validation function returns `Bool`; a parser returns a *narrower type* that carries proof of validity.
- Wrong: `validateEmail :: Text -> Bool`
- Right: `parseEmail :: Text -> Either EmailError Email`
Once you hold an `Email`, you never need to check it again — the type carries the proof. "Make illegal states unrepresentable."
5. **Phantom types for state machines.** When state transitions must b