
haskell-ecosystem
by takeokunn
takeokunn's nixos-configuration
SKILL.md
name: Haskell Ecosystem description: This skill should be used when working with Haskell projects, "cabal.project", "stack.yaml", "ghc", "cabal build/test/run", "stack build/test/run", or Haskell language patterns. Provides comprehensive Haskell ecosystem patterns and best practices. version: 0.1.0
<haskell_language> <type_system> Sum types (Either, Maybe) and product types (tuples, records) data Maybe a = Nothing | Just a data Either a b = Left a | Right b data Person = Person { name :: String, age :: Int }
<concept name="type_classes">
<description>Define behavior for types; similar to interfaces but more powerful</description>
<common_classes>
<class name="Eq">Equality comparison (==, /=)</class>
<class name="Ord">Ordering comparison (compare, <, >, <=, >=)</class>
<class name="Show">String representation (show)</class>
<class name="Read">Parse from string (read)</class>
<class name="Functor">Mappable containers (fmap, <$>)</class>
<class name="Applicative">Apply functions in context (<*>, pure)</class>
<class name="Monad">Sequence computations (>>=, return, do-notation)</class>
<class name="Foldable">Reducible structures (foldr, foldl, toList)</class>
<class name="Traversable">Traverse with effects (traverse, sequenceA)</class>
<class name="Semigroup">Associative binary operation (<>)</class>
<class name="Monoid">Semigroup with identity (mempty, mappend)</class>
</common_classes>
<example>
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
instance Eq Person where
p1 == p2 = name p1 == name p2 && age p1 == age p2
</example>
</concept>
<concept name="type_level_programming">
<description>Advanced type system features for compile-time guarantees</description>
<pattern name="gadts">
<description>Generalized Algebraic Data Types - refine types in pattern matching</description>
<pragma>GADTs</pragma>
<example>
{-# LANGUAGE GADTs #-}
data Expr a where
LitInt :: Int -> Expr Int
LitBool :: Bool -> Expr Bool
Add :: Expr Int -> Expr Int -> Expr Int
If :: Expr Bool -> Expr a -> Expr a -> Expr a
eval :: Expr a -> a
eval (LitInt n) = n
eval (LitBool b) = b
eval (Add e1 e2) = eval e1 + eval e2
eval (If c t e) = if eval c then eval t else eval e
</example>
</pattern>
<pattern name="type_families">
<description>Type-level functions; compute types from types</description>
<pragma>TypeFamilies</pragma>
<example>
{-# LANGUAGE TypeFamilies #-}
type family Element c where
Element [a] = a
Element (Set a) = a
Element Text = Char
class Container c where
type Elem c
empty :: c
insert :: Elem c -> c -> c
</example>
</pattern>
<pattern name="data_kinds">
<description>Promote data types to kinds for type-level programming</description>
<pragma>DataKinds</pragma>
<example>
{-# LANGUAGE DataKinds, KindSignatures #-}
data Nat = Zero | Succ Nat
data Vec (n :: Nat) a where
VNil :: Vec 'Zero a
VCons :: a -> Vec n a -> Vec ('Succ n) a
</example>
</pattern>
<pattern name="phantom_types">
<description>Type parameters that don't appear in value constructors</description>
<example>
newtype Tagged tag a = Tagged { unTagged :: a }
data Validated
data Unvalidated
validateEmail :: Tagged Unvalidated String -> Maybe (Tagged Validated String)
</example>
</pattern>
</concept>
<concept name="higher_kinded_types">
<description>Type constructors as parameters; enables Functor, Monad abstractions</description>
<example>
class Functor f where
fmap :: (a -> b) -> f a -> f b
-- f is a type constructor (* -> *)
-- Functor operates on type constructors, not concrete types
</example>
</concept>
</type_system>
<monad_transformers> Compose monadic effects using transformers from mtl/transformers
<pattern name="transformers_stack">
<description>Build custom monad stacks with transformers</description>
<example>
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Control.Monad.Trans.Except
type App a = ReaderT Config (StateT AppState (ExceptT AppError IO)) a
runApp :: Config -> AppState -> App a -> IO (Either AppError (a, AppState))
runApp cfg st app = runExceptT (runStateT (runReaderT app cfg) st)
</example>
</pattern>
<pattern name="mtl_style">
<description>Use mtl type classes for polymorphic effect handling</description>
<example>
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Except
doSomething :: (MonadReader Config m, MonadState AppState m, MonadError AppError m) => m Result
doSomething = do
cfg <- ask
st <- get
when (invalid cfg) $ throwError InvalidConfig
pure (compute cfg st)
</example>
</pattern>
<common_transformers>
<transformer name="ReaderT">Read-only environment; ask, local</transformer>
<transformer name="StateT">Mutable state; get, put, modify</transformer>
<transformer name="ExceptT">Error handling; throwError, catchError</transformer>
<transformer name="WriterT">Accumulate output; tell, listen</transformer>
<transformer name="MaybeT">Short-circuit on Nothing</transformer>
<transformer name="ListT">Non-determinism (use list-t or logict for correct semantics)</transformer>
</common_transformers>
</monad_transformers>
<pattern name="lens_basics">
<description>Focus on parts of data structures</description>
<example>
import Control.Lens
data Person = Person { _name :: String, _age :: Int }
makeLenses ''Person
-- name :: Lens' Person String
-- age :: Lens' Person Int
getName :: Person -> String
getName p = p ^. name
setName :: String -> Person -> Person
setName n p = p & name .~ n
modifyAge :: (Int -> Int) -> Person -> Person
modifyAge f p = p & age %~ f
</example>
</pattern>
<pattern name="optic_types">
<description>Different optic types for different access patterns</description>
<optics_hierarchy>
<optic name="Lens">Get and set exactly one value</optic>
<optic name="Prism">Focus on one branch of a sum type</optic>
<optic name="Traversal">Focus on zero or more values</optic>
<optic name="Iso">Bidirectional transformation</optic>
<optic name="Getter">Read-only access</optic>
<optic name="Fold">Read-only traversal</optic>
</optics_hierarchy>
</pattern>
<pattern name="lens_operators">
<description>Common lens operators</description>
<operators>
<operator name="^.">View through lens (view)</operator>
<operator name=".~">Set value (set)</operator>
<operator name="%~">Modify value (over)</operator>
<operator name="&">Apply function (flip ($))</operator>
<operator name="^?">View through prism (preview)</operator>
<operator name="^..">View all through traversal (toListOf)</operator>
</operators>
</pattern>
<alternative name="optics">
<description>Alternative to lens with better type errors and composition</description>
<package>optics</package>
<note>Considered more modern; lens has larger ecosystem</note>
</alternative>
<error_handling> Optional values; prefer over null findUser :: UserId -> Maybe User findUser uid = lookup uid users
-- Safe chaining with Monad
getUserEmail :: UserId -> Maybe Email
getUserEmail uid = do
user <- findUser uid
pure (userEmail user)
</example>
</pattern>
<pattern name="either">
<description>Computations that may fail with error information</description>
<example>
parseConfig :: Text -> Either ParseError Config
parseConfig input = do
json <- parseJSON input
validateConfig json
</example>
</pattern>
<pattern name="exceptt">
<description>Error handling in monadic contexts</description>
<example>
import Control.Monad.Except
data AppError = NotFound | InvalidInput String | IOError IOException
loadUser :: MonadError AppError m => UserId -> m User
loadUser uid = do
mUser <- findUser uid
case mUser of
Nothing -> throwError NotFound
Just u -> pure u
</example>
</pattern>
</error_handling>
<common_patterns> Zero-cost wrapper for type safety newtype UserId = UserId { unUserId :: Int } deriving (Eq, Ord, Show)
newtype Email = Email { unEmail :: Text }
deriving (Eq, Show)
</example>
</pattern>
<pattern name="smart_constructors">
<description>Validate data at construction time</description>
<example>
module Email (Email, mkEmail, unEmail) where
newtype Email = Email Text
mkEmail :: Text -> Maybe Email
mkEmail t
| isValidEmail t = Just (Email t)
| otherwise = Nothing
</example>
</pattern>
<pattern name="records">
<description>Named fields with accessor functions</description>
<example>
{-# LANGUAGE RecordWildCards #-}
data Config = Config
{ configHost :: String
, configPort :: Int
, configTimeout :: Int
}
-- Using RecordWildCards
mkConnection :: Config -> IO Connection
mkConnection Config{..} = connect configHost configPort
</example>
</pattern>
</common_patterns>
<anti_patterns> Functions that crash on some inputs (head, tail, fromJust, read) Use safe alternatives (headMay, listToMaybe) or pattern matching
<avoid name="string_type">
<description>Using String ([Char]) for text processing</description>
<instead>Use Text or ByteString for performance</instead>
</avoid>
<avoid name="lazy_io">
<description>Using lazy IO (readFile, getContents) in production</description>
<instead>Use strict IO or streaming (conduit, pipes, streaming)</instead>
</avoid>
<avoid name="orphan_instances">
<description>Defining type class instances outside the module of the type or class</description>
<instead>Use newtype wrappers or define instances in appropriate modules</instead>
</avoid>
</anti_patterns> </haskell_language>
<cabal_file> <basic_structure> cabal-version: 3.0 name: my-project version: 0.1.0.0 synopsis: Short description license: MIT author: Your Name maintainer: your@email.com
common warnings
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates
-Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints
library
import: warnings
exposed-modules: MyProject
build-depends: base ^>=4.18,
text ^>=2.0,
containers ^>=0.6
hs-source-dirs: src
default-language: GHC2021
executable my-project
import: warnings
main-is: Main.hs
build-depends: base ^>=4.18,
my-project
hs-source-dirs: app
default-language: GHC2021
test-suite my-project-test
import: warnings
type: exitcode-stdio-1.0
main-is: Spec.hs
build-depends: base ^>=4.18,
my-project,
hspec ^>=2.11,
QuickCheck ^>=2.14
hs-source-dirs: test
default-language: GHC2021
</basic_structure>
<version_bounds>
-- Caret (^>=): major version compatible
base ^>=4.18 -- 4.18.x.x
-- Range
text >=2.0 && <2.2
-- Any version (avoid in published packages)
containers
</version_bounds>
<language_extensions>
default-extensions:
OverloadedStrings
LambdaCase
RecordWildCards
DerivingStrategies
GeneralizedNewtypeDeriving
TypeApplications
default-language: GHC2021 -- Recommended for new projects
</language_extensions>
</cabal_file>
<cabal_project> Multi-package project configuration packages: . ./subpackage
-- Use local package
optional-packages: ../local-dependency
-- Optimization
optimization: 2
-- Documentation
documentation: True
-- Test options
tests: True
-- Allow newer dependencies
allow-newer: base
</example>
</cabal_project>
<stack_yaml> <basic_structure> resolver: lts-22.0 # Stackage LTS snapshot
packages:
- .
- ./subpackage
extra-deps:
- some-package-1.0.0
- github: owner/repo
commit: abc123
ghc-options:
"$locals": -Wall -Werror
</basic_structure>
</stack_yaml>
<package_yaml> hpack format; generates .cabal file name: my-project version: 0.1.0.0
dependencies:
- base >= 4.18 && < 5
- text
- containers
ghc-options:
- -Wall
- -Wcompat
default-extensions:
- OverloadedStrings
- LambdaCase
library:
source-dirs: src
executables:
my-project:
main: Main.hs
source-dirs: app
dependencies:
- my-project
tests:
my-project-test:
main: Spec.hs
source-dirs: test
dependencies:
- my-project
- hspec
- QuickCheck
</example>
</package_yaml>
<decision_tree name="cabal_vs_stack"> Which build tool should I use? Stack with LTS resolver Cabal (native format) Cabal with cabal.project Stack (simpler getting started) Cabal with haskell.nix or nixpkgs </decision_tree>
<common_options>
<option name="-Wall">Enable all warnings</option>
<option name="-Werror">Treat warnings as errors</option>
<option name="-O2">Optimization level 2</option>
<option name="-threaded">Enable threaded runtime</option>
<option name="-rtsopts">Enable runtime system options</option>
<option name="-with-rtsopts">Set default RTS options</option>
</common_options>
<language_standards>
<standard name="Haskell2010">Previous standard</standard>
<standard name="GHC2021">Default edition; enables common extensions</standard>
<standard name="GHC2024">Current recommended for new code; extends GHC2021</standard>
</language_standards>
<configuration>
<file_reference>hls.yaml or hie.yaml</file_reference>
cradle:
cabal:
- path: "src"
component: "lib:my-project"
- path: "app"
component: "exe:my-project"
- path: "test"
component: "test:my-project-test"
</configuration>
<formatter name="ormolu">
<description>Minimal configuration formatter</description>
<usage>ormolu -i src/**/*.hs</usage>
</formatter>
<formatter name="stylish-haskell">
<description>Configurable import organization and formatting</description>
<usage>stylish-haskell -i src/**/*.hs</usage>
</formatter>
<linter name="stan">
<description>Static analysis for Haskell</description>
<usage>stan</usage>
</linter>
<linter name="weeder">
<description>Detect dead code</description>
<usage>weeder</usage>
</linter>
main :: IO ()
main = hspec $ do
describe "Calculator" $ do
it "adds two numbers" $ do
add 1 2 `shouldBe` 3
it "handles negative numbers" $ do
add (-1) 1 `shouldBe` 0
describe "Parser" $ do
context "when input is valid" $ do
it "parses successfully" $ do
parse "valid" `shouldSatisfy` isRight
context "when input is invalid" $ do
it "returns error" $ do
parse "invalid" `shouldSatisfy` isLeft
</example>
<matchers>
<matcher name="shouldBe">Equality check</matcher>
<matcher name="shouldSatisfy">Predicate check</matcher>
<matcher name="shouldReturn">IO action result</matcher>
<matcher name="shouldThrow">Exception check</matcher>
<matcher name="shouldContain">List containment</matcher>
</matchers>
prop_reverseReverse :: [Int] -> Bool
prop_reverseReverse xs = reverse (reverse xs) == xs
prop_sortIdempotent :: [Int] -> Bool
prop_sortIdempotent xs = sort (sort xs) == sort xs
-- With preconditions
prop_headLast :: NonEmptyList Int -> Bool
prop_headLast (NonEmpty xs) = head xs == head xs
-- Custom generators
newtype PositiveInt = PositiveInt Int deriving Show
instance Arbitrary PositiveInt where
arbitrary = PositiveInt . abs <$> arbitrary
</example>
<integration>
-- With HSpec
describe "reverse" $ do
it "is its own inverse" $ property $
\xs -> reverse (reverse xs) == (xs :: [Int])
</integration>
prop_reverse :: Property
prop_reverse = property $ do
xs <- forAll $ Gen.list (Range.linear 0 100) Gen.alpha
reverse (reverse xs) === xs
</example>
<best_practices> Use QuickCheck for properties; HSpec for examples Test edge cases: empty lists, zero, negative numbers Use type-driven development; write types first Use doctest for documentation examples </best_practices>
<context7_integration> Use Context7 MCP for up-to-date Haskell documentation
<haskell_libraries> </haskell_libraries>
<usage_patterns> resolve-library-id libraryName="optics haskell" get-library-docs context7CompatibleLibraryID="/websites/hackage_haskell_package_optics-0_4_2_1" topic="lenses"
<pattern name="testing_framework">
<step>get-library-docs context7CompatibleLibraryID="/websites/hackage_haskell_package_hspec-2_11_12" topic="expectations"</step>
</pattern>
<pattern name="web_framework">
<step>get-library-docs context7CompatibleLibraryID="/haskell-servant/servant" topic="server"</step>
</pattern>
</usage_patterns> </context7_integration>
<best_practices> Let types guide design; use the type system to prevent errors Avoid partial functions; use safe alternatives Run hlint and fix suggestions before committing Use Text/ByteString instead of String for performance Prefer mtl-style type class constraints over concrete monad stacks Write property-based tests for core logic Document exported functions with Haddock comments Use newtypes for type safety Enable GHC2021 or explicit commonly-used extensions </best_practices>
<error_escalation> HLint suggestion about style Apply suggestion, maintain idiomatic code Type error or missing instance Review types, add instance or adjust design Breaking change in public API Stop, present migration options to user Partial function usage or unsafe code in library Block operation, require safe alternatives </error_escalation>
<related_skills> Navigate type class hierarchies and module structure Fetch Haskell documentation and library references Debug type errors, missing instances, and performance issues haskell.nix integration and nixpkgs Haskell infrastructure </related_skills>
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


