Haskell implementation of LangChain
See the codelangchain-hs)The Pure Functional, Effect-Polymorphic AI Agent & Multi-Agent Graph Engine in Haskell
A strictly typed, effect-polymorphic, AI ecosystem built on pure AST pipelines (
RunnableTree), cyclic state machines (StateGraph), Model Context Protocol (MCP), and production observability.
langchain-hs?Modern AI orchestration frameworks often struggle with race conditions, hidden side-effects, fragile dynamic schemas, and uninspectable opaque execution chains. langchain-hs brings mathematical precision and functional programming principles to AI development:
RunnableTree): Every component—models, prompts, tools, chains, retrievers, and parsers—implements the Runnable typeclass. Connect components into trees or graphs using type-safe operators:
|>> : Sequential composition (data flows from left to right).&>& : Parallel fan-out (concurrent evaluation of independent branches).>>># : Fallback chains (automatic failover if the primary branch errors).StateGraph): Full cyclic state machine engine with pure monoidal state reducers (StateReducer s), thread-safe STM memory checkpointers (TVar), persistent SQLite checkpointers, Human-in-the-Loop (HITL) interrupts, and Time-Travel state replay.| Package | Directory | Version | Description |
|---|---|---|---|
langchain-hs-core | langchain-hs-core/ | 0.0.5.0 | Zero-dependency pure core: RunnableTree, ChatModel, ContentBlock, Tool, and LangchainT. |
langchain-hs-graph | langchain-hs-graph/ | 0.0.5.0 | Stateful graph engine: StateGraph s m, checkpointers, HITL, time-travel, and parallel nodes. |
langchain-hs | ./ | 0.0.5.0 | Production ecosystem: Ollama/OpenAI providers, Agents, MCP, Vector Stores, Chains, Observability. |
examples | examples/ | - | 41 runnable executables covering all 20 components for Ollama and OpenAI. |
site | site/ | - | Hakyll documentation website with live provider toggle and component reference. |
| # | Component | Package Layer | Ollama Executable | OpenAI Executable | Documentation |
|---|---|---|---|---|---|
| 1 | Chat Models | Langchain.Core.Model | stack run simpleollama | stack run simpleopenai | Docs |
| 2 | Conduit Streaming | Langchain.Core.Stream | stack run streamollama | stack run streamopenai | Docs |
| 3 | Langchain Monad | Langchain.Core.Monad | stack run monadollama | stack run monadopenai | Docs |
| 4 | Tools & Function Calling | Langchain.Core.Tool | stack run toolollama | stack run toolopenai | Docs |
| 5 | Structured Outputs | Langchain.OutputParser | stack run jsonollama | stack run jsonopenai | Docs |
| 6 | RAG & Embeddings | Langchain.Embedding | stack run ragollama | stack run ragopenai | Docs |
| 7 | Hybrid Retrievers | Langchain.Retriever | stack run retrieverollama | stack run retrieveropenai | Docs |
| 8 | Memory Systems | Langchain.Memory | stack run memoryollama | stack run memoryopenai | Docs |
| 9 | Retrieval QA Chains | Langchain.Chain.RetrievalQA | stack run retrievalqaollama | stack run retrievalqaopenai | Docs |
| 10 | Map-Reduce Processing | Langchain.Chain.MapReduce | stack run mapreduceollama | stack run mapreduceopenai | Docs |
| 11 | ReAct Agent | Langchain.Agent.ReAct | stack run reactollama | stack run reactopenai | Docs |
| 12 | Plan-and-Execute Agent | Langchain.Agent.PlanAndExecute | stack run planandexecuteollama | stack run planandexecuteopenai | Docs |
| 13 | Guardrails & Safety | Langchain.Guardrails | stack run guardrailollama | stack run guardrailopenai | Docs |
| 14 | Resilience & Retries | Langchain.Resilience | stack run resilienceollama | stack run resilienceopenai | Docs |
| 15 | Observability & Tracing | Langchain.Observability | stack run observabilityollama | stack run observabilityopenai | Docs |
| 16 | Model Context Protocol | Langchain.MCP.Client | stack run mcpollama | stack run mcpopenai | Docs |
| 17 | StateGraph Workflows | Langchain.Graph | stack run stategraphollama | stack run stategraphopenai | Docs |
| 18 | Multi-Agent Systems | Langchain.Graph.MultiAgent | stack run multiagentollama | stack run multiagentopenai | Docs |
| 19 | Human-in-the-Loop (HITL) | Langchain.Graph.Checkpointer | stack run hitlollama | stack run hitlopenai | Docs |
| 20 | Runnables & AST Composition | Langchain.Core.Runnable | stack run runnableollama | stack run runnableopenai | Docs |
Compose complex multi-stage pipelines using typed operators without executing any IO until interpretation:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Langchain.Prelude
-- Compose pure AST pipelines with (|>>), (&>&), and (>>>#)
pipeline :: RunnableTree IO Text Text
pipeline =
runLambda (\q -> (q, q)) -- duplicate input query
|>> (fetchDocuments &>& generateFollowup) -- parallel branch fan-out
|>> runLambda (\(docs, fup) -> renderPrompt docs fup) -- pure prompt synthesis
|>> (invokeLLM primaryModel >>># invokeLLM backupModel) -- fallback resilience
|>> parseStructuredResponse -- JSON parser
main :: IO ()
main = do
output <- interpret pipeline "Explain Monads in Haskell"
print output
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to local Ollama instance (DeepSeek, Llama 3, Gemma)
model <- newOllama "gemma3" defaultConfig
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleollama
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
import OpenAI.Common (defaultModelName, getOpenRouterModel)
main :: IO ()
main = do
-- Connect to OpenAI or OpenRouter using environment API key
model <- getOpenRouterModel defaultModelName
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleopenai
StateGraph): Cyclic Multi-Agent Workflow{-# LANGUAGE OverloadedStrings #-}
import Langchain.Graph.StateGraph
import Langchain.Prelude
-- Pure state with a list-append reducer
data AgentState = AgentState { messages :: [Message], loopCount :: Int }
-- Build the graph using pure combinators
workflow :: StateGraph AgentState IO
workflow =
addEdge "reviewer" "planner" -- cyclic feedback loop!
$ addConditionalEdge "executor"
(\s -> pure $ if done s then Right endNodeId else Right "reviewer")
$ addEdge "planner" "executor"
$ addEdge startNodeId "planner"
$ addNode "reviewer" (Node reviewerNode replaceFieldReducer)
$ addNode "executor" (Node executorNode replaceFieldReducer)
$ addNode "planner" (Node plannerNode replaceFieldReducer)
$ emptyStateGraph
main :: IO ()
main = do
checkpointer <- newMemoryCheckpointer
case compileGraph workflow of
Left err -> print err
Right compiled -> do
result <- runGraph compiled initialState (Just checkpointer)
print result
Run: stack run stategraphollama or stack run stategraphopenai
Connect Haskell agents to any external MCP server (e.g., Hackage doc search, SQLite, Filesystem, GitHub) over stdio:
{-# LANGUAGE OverloadedStrings #-}
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to any MCP server via stdio JSON-RPC 2.0
client <- newStdioMcpClient "docker" ["run", "-i", "--rm", "mcp/hackage-doc"]
-- Discover available tools from server
mcpTools <- listMcpTools client
let nativeTools = map mcpToolToLangchainTool mcpTools
-- Bind tools to your ReAct or Plan-and-Execute Agent
let agent = createReActAgent model nativeTools defaultAgentConfig
res <- runReActAgent agent "Search Hoogle for the signature of 'traverse'"
print res
Run: stack run mcpollama or stack run mcpopenai
Add to your stack.yaml:
extra-deps:
- langchain-hs-core-0.0.5.0
- langchain-hs-graph-0.0.5.0
- langchain-hs-0.0.5.0
Then in your .cabal or package.yaml:
dependencies:
- langchain-hs # full ecosystem (providers, agents, MCP, vector stores)
- langchain-hs-core # pure core only (no HTTP dependencies)
- langchain-hs-graph # graph engine only
cabal install langchain-hs
The repository enforces strict code quality and formatting via make:
# Build the entire monorepo and all 41 example executables
stack build
# Run unit and property-based test suites
stack test
# Run HLint across all source trees (zero hints policy)
make lint
# Check code formatting with Fourmolu
make format-check
# Format all files in-place
make format
# Build the documentation website (Hakyll)
make site-build
# Run live documentation server with auto-reload (port 8000)
make site-watch
| Resource | Description |
|---|---|
| Hackage Docs | Full Haddock API reference for all exported modules |
| Whitepaper | Deep technical dive: category theory foundations, algebraic laws, effect-polymorphic design, and advanced multi-agent patterns |
| Documentation Website | Hakyll site with 20 component pages, live provider toggle, and instant search (Cmd+K) |
| Examples | 41 runnable executables covering every component for Ollama and OpenAI |
To build the Haddock API docs locally:
make docs
# Opens in .stack-work/install/.../doc/index.html
Distributed under the MIT License. See LICENSE for details.
Haskell
87.8%
CSS
4.6%
HTML
4.1%
JavaScript
3.4%
Haskell implementation of LangChain
See the codelangchain-hs)The Pure Functional, Effect-Polymorphic AI Agent & Multi-Agent Graph Engine in Haskell
A strictly typed, effect-polymorphic, AI ecosystem built on pure AST pipelines (
RunnableTree), cyclic state machines (StateGraph), Model Context Protocol (MCP), and production observability.
langchain-hs?Modern AI orchestration frameworks often struggle with race conditions, hidden side-effects, fragile dynamic schemas, and uninspectable opaque execution chains. langchain-hs brings mathematical precision and functional programming principles to AI development:
RunnableTree): Every component—models, prompts, tools, chains, retrievers, and parsers—implements the Runnable typeclass. Connect components into trees or graphs using type-safe operators:
|>> : Sequential composition (data flows from left to right).&>& : Parallel fan-out (concurrent evaluation of independent branches).>>># : Fallback chains (automatic failover if the primary branch errors).StateGraph): Full cyclic state machine engine with pure monoidal state reducers (StateReducer s), thread-safe STM memory checkpointers (TVar), persistent SQLite checkpointers, Human-in-the-Loop (HITL) interrupts, and Time-Travel state replay.| Package | Directory | Version | Description |
|---|---|---|---|
langchain-hs-core | langchain-hs-core/ | 0.0.5.0 | Zero-dependency pure core: RunnableTree, ChatModel, ContentBlock, Tool, and LangchainT. |
langchain-hs-graph | langchain-hs-graph/ | 0.0.5.0 | Stateful graph engine: StateGraph s m, checkpointers, HITL, time-travel, and parallel nodes. |
langchain-hs | ./ | 0.0.5.0 | Production ecosystem: Ollama/OpenAI providers, Agents, MCP, Vector Stores, Chains, Observability. |
examples | examples/ | - | 41 runnable executables covering all 20 components for Ollama and OpenAI. |
site | site/ | - | Hakyll documentation website with live provider toggle and component reference. |
| # | Component | Package Layer | Ollama Executable | OpenAI Executable | Documentation |
|---|---|---|---|---|---|
| 1 | Chat Models | Langchain.Core.Model | stack run simpleollama | stack run simpleopenai | Docs |
| 2 | Conduit Streaming | Langchain.Core.Stream | stack run streamollama | stack run streamopenai | Docs |
| 3 | Langchain Monad | Langchain.Core.Monad | stack run monadollama | stack run monadopenai | Docs |
| 4 | Tools & Function Calling | Langchain.Core.Tool | stack run toolollama | stack run toolopenai | Docs |
| 5 | Structured Outputs | Langchain.OutputParser | stack run jsonollama | stack run jsonopenai | Docs |
| 6 | RAG & Embeddings | Langchain.Embedding | stack run ragollama | stack run ragopenai | Docs |
| 7 | Hybrid Retrievers | Langchain.Retriever | stack run retrieverollama | stack run retrieveropenai | Docs |
| 8 | Memory Systems | Langchain.Memory | stack run memoryollama | stack run memoryopenai | Docs |
| 9 | Retrieval QA Chains | Langchain.Chain.RetrievalQA | stack run retrievalqaollama | stack run retrievalqaopenai | Docs |
| 10 | Map-Reduce Processing | Langchain.Chain.MapReduce | stack run mapreduceollama | stack run mapreduceopenai | Docs |
| 11 | ReAct Agent | Langchain.Agent.ReAct | stack run reactollama | stack run reactopenai | Docs |
| 12 | Plan-and-Execute Agent | Langchain.Agent.PlanAndExecute | stack run planandexecuteollama | stack run planandexecuteopenai | Docs |
| 13 | Guardrails & Safety | Langchain.Guardrails | stack run guardrailollama | stack run guardrailopenai | Docs |
| 14 | Resilience & Retries | Langchain.Resilience | stack run resilienceollama | stack run resilienceopenai | Docs |
| 15 | Observability & Tracing | Langchain.Observability | stack run observabilityollama | stack run observabilityopenai | Docs |
| 16 | Model Context Protocol | Langchain.MCP.Client | stack run mcpollama | stack run mcpopenai | Docs |
| 17 | StateGraph Workflows | Langchain.Graph | stack run stategraphollama | stack run stategraphopenai | Docs |
| 18 | Multi-Agent Systems | Langchain.Graph.MultiAgent | stack run multiagentollama | stack run multiagentopenai | Docs |
| 19 | Human-in-the-Loop (HITL) | Langchain.Graph.Checkpointer | stack run hitlollama | stack run hitlopenai | Docs |
| 20 | Runnables & AST Composition | Langchain.Core.Runnable | stack run runnableollama | stack run runnableopenai | Docs |
Compose complex multi-stage pipelines using typed operators without executing any IO until interpretation:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Langchain.Prelude
-- Compose pure AST pipelines with (|>>), (&>&), and (>>>#)
pipeline :: RunnableTree IO Text Text
pipeline =
runLambda (\q -> (q, q)) -- duplicate input query
|>> (fetchDocuments &>& generateFollowup) -- parallel branch fan-out
|>> runLambda (\(docs, fup) -> renderPrompt docs fup) -- pure prompt synthesis
|>> (invokeLLM primaryModel >>># invokeLLM backupModel) -- fallback resilience
|>> parseStructuredResponse -- JSON parser
main :: IO ()
main = do
output <- interpret pipeline "Explain Monads in Haskell"
print output
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to local Ollama instance (DeepSeek, Llama 3, Gemma)
model <- newOllama "gemma3" defaultConfig
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleollama
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad.Except (runExceptT)
import qualified Data.Text.IO as T
import Langchain.Prelude
import OpenAI.Common (defaultModelName, getOpenRouterModel)
main :: IO ()
main = do
-- Connect to OpenAI or OpenRouter using environment API key
model <- getOpenRouterModel defaultModelName
let msg = [userMessage "Write a poem about functional programming"]
res <- runExceptT $ invoke model msg Nothing
case res of
Left err -> T.putStrLn $ errorMessage err
Right m -> T.putStrLn $ extractMessageText m
Run: stack run simpleopenai
StateGraph): Cyclic Multi-Agent Workflow{-# LANGUAGE OverloadedStrings #-}
import Langchain.Graph.StateGraph
import Langchain.Prelude
-- Pure state with a list-append reducer
data AgentState = AgentState { messages :: [Message], loopCount :: Int }
-- Build the graph using pure combinators
workflow :: StateGraph AgentState IO
workflow =
addEdge "reviewer" "planner" -- cyclic feedback loop!
$ addConditionalEdge "executor"
(\s -> pure $ if done s then Right endNodeId else Right "reviewer")
$ addEdge "planner" "executor"
$ addEdge startNodeId "planner"
$ addNode "reviewer" (Node reviewerNode replaceFieldReducer)
$ addNode "executor" (Node executorNode replaceFieldReducer)
$ addNode "planner" (Node plannerNode replaceFieldReducer)
$ emptyStateGraph
main :: IO ()
main = do
checkpointer <- newMemoryCheckpointer
case compileGraph workflow of
Left err -> print err
Right compiled -> do
result <- runGraph compiled initialState (Just checkpointer)
print result
Run: stack run stategraphollama or stack run stategraphopenai
Connect Haskell agents to any external MCP server (e.g., Hackage doc search, SQLite, Filesystem, GitHub) over stdio:
{-# LANGUAGE OverloadedStrings #-}
import Langchain.Prelude
main :: IO ()
main = do
-- Connect to any MCP server via stdio JSON-RPC 2.0
client <- newStdioMcpClient "docker" ["run", "-i", "--rm", "mcp/hackage-doc"]
-- Discover available tools from server
mcpTools <- listMcpTools client
let nativeTools = map mcpToolToLangchainTool mcpTools
-- Bind tools to your ReAct or Plan-and-Execute Agent
let agent = createReActAgent model nativeTools defaultAgentConfig
res <- runReActAgent agent "Search Hoogle for the signature of 'traverse'"
print res
Run: stack run mcpollama or stack run mcpopenai
Add to your stack.yaml:
extra-deps:
- langchain-hs-core-0.0.5.0
- langchain-hs-graph-0.0.5.0
- langchain-hs-0.0.5.0
Then in your .cabal or package.yaml:
dependencies:
- langchain-hs # full ecosystem (providers, agents, MCP, vector stores)
- langchain-hs-core # pure core only (no HTTP dependencies)
- langchain-hs-graph # graph engine only
cabal install langchain-hs
The repository enforces strict code quality and formatting via make:
# Build the entire monorepo and all 41 example executables
stack build
# Run unit and property-based test suites
stack test
# Run HLint across all source trees (zero hints policy)
make lint
# Check code formatting with Fourmolu
make format-check
# Format all files in-place
make format
# Build the documentation website (Hakyll)
make site-build
# Run live documentation server with auto-reload (port 8000)
make site-watch
| Resource | Description |
|---|---|
| Hackage Docs | Full Haddock API reference for all exported modules |
| Whitepaper | Deep technical dive: category theory foundations, algebraic laws, effect-polymorphic design, and advanced multi-agent patterns |
| Documentation Website | Hakyll site with 20 component pages, live provider toggle, and instant search (Cmd+K) |
| Examples | 41 runnable executables covering every component for Ollama and OpenAI |
To build the Haddock API docs locally:
make docs
# Opens in .stack-work/install/.../doc/index.html
Distributed under the MIT License. See LICENSE for details.
Haskell
87.8%
CSS
4.6%
HTML
4.1%
JavaScript
3.4%