cabal repl <package>          # Interactive development
cabal build <package>         # Build specific package
cabal test <package>          # Run tests for package

Use the custom ghci-capture tool instead of raw tmux capture:

# Use relative path to the tool
./ghci-capture session-name

# Shows intelligent context - if last prompt is empty, shows previous command output
# Much better than raw tmux capture for GHCi sessions

Core Philosophy: Optimize for clarity and safety over conciseness. Code should be explicit, readable, and resistant to runtime errors.

Never use these dangerous functions - they crash on edge cases:

-- BAD: Partial functions that crash
head [1,2,3]          -- crashes on []
tail [1,2,3]          -- crashes on []
maximum [1,2,3]       -- crashes on []
minimum [1,2,3]       -- crashes on []
fromJust (Just 42)    -- crashes on Nothing
fromRight (Left err)  -- crashes on Left

-- GOOD: Explicit pattern matching
case xs of
  [] -> handleEmpty
  (x:rest) -> useHead x

case myMaybe of
  Nothing -> handleNothing  
  Just value -> useValue value

Use safe alternatives:

Use modern equivalents:

-- OLD           -> NEW
return x         -> pure x
mapM f xs        -> traverse f xs  
mapM_ f xs       -> traverse_ f xs
forM xs f        -> for xs f
forM_ xs f       -> for_ xs f
undefined        -> todo  -- shows warnings until removed

Prefer explicit code over point-free style:

-- BAD: Point-free style (hard to read)
f = map (+1) . filter even . concat

-- GOOD: Explicit pipeline  
f xs = xs
  & concat
  & filter even
  & map (+1)

-- BAD: const obscures intent
const True

-- GOOD: Explicit lambda with type information
\(_ :: Request) -> True

Avoid helper functions that hide logic:

-- BAD: fromMaybe hides the Nothing case
fromMaybe defaultValue myMaybe

-- GOOD: Explicit pattern matching
case myMaybe of
  Nothing -> defaultValue
  Just value -> value

Use specific length functions:

-- BAD: Generic length is dangerous
length (3,4)        -- equals 1 (surprising!)
length (Just 42)    -- equals 1 (surprising!)

-- GOOD: Type-specific length
List.length [1,2,3]
Map.length myMap
Set.length mySet

Use strict containers:

-- BAD: Lazy containers cause space leaks
import Data.Map

-- GOOD: Strict containers
import Data.Map.Strict as Map
import Data.HashMap.Strict as HashMap

-- BAD: O(n²) nub
nub [1,2,1,3,2]

-- GOOD: O(n log n) nubOrd  
nubOrd [1,2,1,3,2]

Use my-prelude conversion functions:

-- BAD: Raw encoding functions
Data.Text.Encoding.encodeUtf8
Data.Text.Encoding.decodeUtf8

-- GOOD: Explicit error handling variants
textToBytesUtf8           -- safe conversion
bytesToTextUtf8           -- safe with Either result
bytesToTextUtf8Lenient    -- replacement chars for invalid UTF-8
bytesToTextUtf8Unsafe     -- crashes on invalid UTF-8 (discouraged)

-- Lazy/strict conversions
toStrict      -- Text.Lazy -> Text
toLazy        -- Text -> Text.Lazy  
toStrictBytes -- ByteString.Lazy -> ByteString
toLazyBytes   -- ByteString -> ByteString.Lazy

Prefer data flow left-to-right:

-- BAD: Backward composition (right-to-left reading)
result = f . g . h $ input

-- GOOD: Forward pipeline (left-to-right reading)
result = input
  & h
  & g  
  & f

-- GOOD: Bind chain for monadic operations
result <- input
  >>= h
  >>= g
  >>= f

Use Data.Error.Tree for structured errors:

-- GOOD: Structured error collection
parseUser :: Json.Value -> Either ErrorTree User
parseUser = Json.parse $ do
  name <- Json.key "name" Json.asText
  age <- Json.key "age" Json.asInt
  pure User{..}

-- GOOD: Error annotation
result <- computation
  & annotate "Failed to process user data"  
  & orAppThrow span

Use qualified imports for common modules:

import Data.Map.Strict as Map
import Data.HashMap.Strict as HashMap  
import Data.Set as Set
import Data.Text as Text
import Data.Aeson as Json
import Data.ByteString.Char8 as Char8

For comprehensive Haskell library documentation research:

# Function signatures and documentation
hoogle search --json "functionName"

# Module-level architecture and guidance  
hoogle search --json "Module.Name"

# Type definitions and constructors
hoogle search --json "TypeName"

  1. Discover functions: Use grep to find what exists in documentation files

    grep -r "functionPattern" /nix/store/*-doc/share/doc/*/html/
    
  2. Get precise details: Use hoogle search --json for exact signatures and comprehensive documentation

  3. Cross-reference: Validate implementation approaches against library design patterns

For unrestricted documentation access with rich HTML content:

Setup:

# Start documentation server in tmux
tmux new-session -d -s hoogle-docs
tmux send-keys -t hoogle-docs "hoogle server --local --port 9090" Enter

# Verify server is running
sleep 3 && curl -s http://localhost:9090 | head -10

Research Commands:

# Search for modules - comprehensive architectural documentation
curl -s "http://localhost:9090/?hoogle=Network.HTTP.Client" | head -100

# Search for functions - exact signatures and usage examples  
curl -s "http://localhost:9090/?hoogle=setQueryString" | grep -A 20 -B 5 "setQueryString"

# Search for types - constructors and cross-package usage
curl -s "http://localhost:9090/?hoogle=defaultRequest" | grep -A 15 -B 5 "defaultRequest"

# Use byte ranges for large responses
curl -s -r 0-2047 "http://localhost:9090/?hoogle=searchTerm"

Key Benefits:

Proven Workflow: Start server → curl search → grep filter → validate with hoogle search --json

Research methodology: Always verify library functions via Hoogle before implementation to ensure accurate, idiomatic Haskell code.