(config?: SearchConfig): <N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => NodeWalker<N>
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
config?: SearchConfig
): NodeWalker<N>Creates a lazy depth-first postorder traversal iterator from the configured start nodes.
Details
Nodes are emitted after their reachable descendants have been processed. If
no start nodes are supplied, the iterator is empty. The direction option
chooses whether to follow outgoing or incoming edges.
Example (Traversing in postorder)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const root = Graph.addNode(mutable, "root")
const child1 = Graph.addNode(mutable, "child1")
const child2 = Graph.addNode(mutable, "child2")
Graph.addEdge(mutable, root, child1, 1)
Graph.addEdge(mutable, root, child2, 1)
})
// Postorder: children before parents
const postOrder = Graph.dfsPostOrder(graph, { start: [0] })
for (const node of postOrder) {
console.log(node) // 1, 2, 0
}export const const dfsPostOrder: {
(config?: SearchConfig): <
N,
E,
T extends Kind = "directed"
>(
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => NodeWalker<N>
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
config?: SearchConfig
): NodeWalker<N>
}
Creates a lazy depth-first postorder traversal iterator from the configured
start nodes.
Details
Nodes are emitted after their reachable descendants have been processed. If
no start nodes are supplied, the iterator is empty. The direction option
chooses whether to follow outgoing or incoming edges.
Example (Traversing in postorder)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const root = Graph.addNode(mutable, "root")
const child1 = Graph.addNode(mutable, "child1")
const child2 = Graph.addNode(mutable, "child2")
Graph.addEdge(mutable, root, child1, 1)
Graph.addEdge(mutable, root, child2, 1)
})
// Postorder: children before parents
const postOrder = Graph.dfsPostOrder(graph, { start: [0] })
for (const node of postOrder) {
console.log(node) // 1, 2, 0
}
dfsPostOrder: {
(
config: SearchConfigconfig?: SearchConfig
): <function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>T>) => type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>): NodeWalker<N>N>
<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T>,
config: SearchConfigconfig?: SearchConfig
): type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N>
} = import dualdual((args: anyargs) => const isGraph: (
u: unknown
) => u is Graph<unknown, unknown>
Returns true if a value has the graph runtime type identifier, narrowing
it to a Graph.
When to use
Use to narrow an unknown value before treating it as a graph value.
Gotchas
This guard checks the shared graph runtime type identifier and does not
distinguish immutable graphs from mutable graphs.
isGraph(args: anyargs[0]), <function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T extends type Kind = "directed" | "undirected"Graph type for distinguishing directed and undirected graphs.
When to use
Use when writing graph-polymorphic types or helpers that need to preserve
whether a graph is directed or undirected.
Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>graph: interface Graph<out N, out E, T extends Kind = "directed">Immutable graph interface.
When to use
Use as the immutable graph model for code that queries, traverses,
transforms, or analyzes graph structure without mutating it.
Graph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T> | interface MutableGraph<out N, out E, T extends Kind = "directed">Mutable graph interface.
When to use
Use when adding, removing, or updating nodes and edges inside a graph
mutation scope.
MutableGraph<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N, function (type parameter) E in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>E, function (type parameter) T in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>T>,
config: SearchConfig(parameter) config: {
start: Array<NodeIndex>;
direction: Direction;
}
config: SearchConfig = {}
): type NodeWalker<N> = Walker<number, N>Type alias for node iteration using Walker.
NodeWalker is represented as Walker<NodeIndex, N>.
When to use
Use as the shared node walker type returned by graph traversal and node
listing APIs.
NodeWalker<function (type parameter) N in <N, E, T extends Kind = "directed">(graph: Graph<N, E, T> | MutableGraph<N, E, T>, config?: SearchConfig): NodeWalker<N>N> => {
const const start: number[]start = config: SearchConfig(parameter) config: {
start: Array<NodeIndex>;
direction: Direction;
}
config.SearchConfig.start?: Array<NodeIndex>start ?? []
const const direction: Directiondirection = config: SearchConfig(parameter) config: {
start: Array<NodeIndex>;
direction: Direction;
}
config.SearchConfig.direction?: Directiondirection ?? "outgoing"
// Validate that all start nodes exist
for (const const nodeIndex: numbernodeIndex of const start: number[]start) {
if (!const hasNode: {
(nodeIndex: NodeIndex): <
N,
E,
T extends Kind = "directed"
>(
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => boolean
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
nodeIndex: NodeIndex
): boolean
}
hasNode(graph: Graph<N, E, T> | MutableGraph<N, E, T>graph, const nodeIndex: numbernodeIndex)) {
throw const missingNode: (
node: number
) => GraphError
missingNode(const nodeIndex: numbernodeIndex)
}
}
return new constructor Walker<number, N>(visit: <U>(f: (index: number, data: N) => U) => Iterable<U>): Walker<number, N>Represents an iterable wrapper used by graph traversal and listing APIs.
Details
A Walker yields [index, data] pairs lazily and can be viewed as just the
indices, just the values, or mapped entries with indices, values,
entries, and visit.
Example (Working with node walkers)
import { Graph } from "effect"
const graph = Graph.directed<string, number>((mutable) => {
const a = Graph.addNode(mutable, "A")
const b = Graph.addNode(mutable, "B")
Graph.addEdge(mutable, a, b, 1)
})
// Both traversal and element iterators return NodeWalker
const dfsNodes: Graph.NodeWalker<string> = Graph.dfs(graph, { start: [0] })
const allNodes: Graph.NodeWalker<string> = Graph.nodes(graph)
// Common interface for working with node iterables
function processNodes<N>(nodeIterable: Graph.NodeWalker<N>): Array<number> {
return Array.from(Graph.indices(nodeIterable))
}
// Access node data using values() or entries()
const nodeData = Array.from(Graph.values(dfsNodes)) // ["A", "B"]
const nodeEntries = Array.from(Graph.entries(allNodes)) // [[0, "A"], [1, "B"]]
Walker((f: (index: number, data: N) => Uf) => ({
[var Symbol: SymbolConstructorSymbol.SymbolConstructor.iterator: typeof Symbol.iteratorA method that returns the default iterator for an object. Called by the semantics of the
for-of statement.
iterator]: () => {
const const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack: interface Array<T>Array<{ node: NodeIndexnode: type NodeIndex = numberNode index for node identification using plain numbers.
When to use
Use when storing or passing the stable identifier of a graph node between
Graph operations.
Details
addNode allocates node identifiers from the graph's next node index.
Gotchas
A NodeIndex is an identifier, not an array offset. Removed node identifiers
are not reused.
NodeIndex; visitedChildren: booleanvisitedChildren: boolean }> = []
const const discovered: Set<number>discovered = new var Set: SetConstructor
new <number>(iterable?: Iterable<number> | null | undefined) => Set<number> (+1 overload)
Set<type NodeIndex = numberNode index for node identification using plain numbers.
When to use
Use when storing or passing the stable identifier of a graph node between
Graph operations.
Details
addNode allocates node identifiers from the graph's next node index.
Gotchas
A NodeIndex is an identifier, not an array offset. Removed node identifiers
are not reused.
NodeIndex>()
const const finished: Set<number>finished = new var Set: SetConstructor
new <number>(iterable?: Iterable<number> | null | undefined) => Set<number> (+1 overload)
Set<type NodeIndex = numberNode index for node identification using plain numbers.
When to use
Use when storing or passing the stable identifier of a graph node between
Graph operations.
Details
addNode allocates node identifiers from the graph's next node index.
Gotchas
A NodeIndex is an identifier, not an array offset. Removed node identifiers
are not reused.
NodeIndex>()
// Initialize stack with start nodes
for (let let i: numberi = const start: number[]start.Array<number>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length - 1; let i: numberi >= 0; let i: numberi--) {
const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack.function Array(...items: Array<{ node: NodeIndex; visitedChildren: boolean }>): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ node: numbernode: const start: number[]start[let i: numberi], visitedChildren: booleanvisitedChildren: false })
}
const const nextMapped: () =>
| {
done: boolean
value: U
}
| {
readonly done: true
readonly value: undefined
}
nextMapped = () => {
while (const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack.Array<T>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length > 0) {
const const current: {
node: NodeIndex
visitedChildren: boolean
}
current = const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack[const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack.Array<T>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length - 1]
if (!const discovered: Set<number>discovered.Set<number>.has(value: number): booleanhas(const current: {
node: NodeIndex
visitedChildren: boolean
}
current.node: NodeIndexnode)) {
const discovered: Set<number>discovered.Set<number>.add(value: number): Set<number>Appends a new element with a specified value to the end of the Set.
add(const current: {
node: NodeIndex
visitedChildren: boolean
}
current.node: NodeIndexnode)
const current: {
node: NodeIndex
visitedChildren: boolean
}
current.visitedChildren: booleanvisitedChildren = false
}
if (!const current: {
node: NodeIndex
visitedChildren: boolean
}
current.visitedChildren: booleanvisitedChildren) {
const current: {
node: NodeIndex
visitedChildren: boolean
}
current.visitedChildren: booleanvisitedChildren = true
const const neighbors: number[]neighbors = const getTraversalNeighbors: <
N,
E,
T extends Kind
>(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
nodeIndex: NodeIndex,
direction: Direction
) => Array<NodeIndex>
getTraversalNeighbors(graph: Graph<N, E, T> | MutableGraph<N, E, T>graph, const current: {
node: NodeIndex
visitedChildren: boolean
}
current.node: NodeIndexnode, const direction: Directiondirection)
for (let let i: numberi = const neighbors: number[]neighbors.Array<number>.length: numberGets or sets the length of the array. This is a number one higher than the highest index in the array.
length - 1; let i: numberi >= 0; let i: numberi--) {
const const neighbor: numberneighbor = const neighbors: number[]neighbors[let i: numberi]
if (!const discovered: Set<number>discovered.Set<number>.has(value: number): booleanhas(const neighbor: numberneighbor) && !const finished: Set<number>finished.Set<number>.has(value: number): booleanhas(const neighbor: numberneighbor)) {
const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack.function Array(...items: Array<{ node: NodeIndex; visitedChildren: boolean }>): numberAppends new elements to the end of an array, and returns the new length of the array.
push({ node: numbernode: const neighbor: numberneighbor, visitedChildren: booleanvisitedChildren: false })
}
}
} else {
const const nodeToEmit: numbernodeToEmit = const stack: Array<{
node: NodeIndex
visitedChildren: boolean
}>
stack.function Array(): { node: NodeIndex; visitedChildren: boolean } | undefinedRemoves the last element from an array and returns it.
If the array is empty, undefined is returned and the array is not modified.
pop()!.node: NodeIndexnode
if (!const finished: Set<number>finished.Set<number>.has(value: number): booleanhas(const nodeToEmit: numbernodeToEmit)) {
const finished: Set<number>finished.Set<number>.add(value: number): Set<number>Appends a new element with a specified value to the end of the Set.
add(const nodeToEmit: numbernodeToEmit)
const const nodeData: Option.Option<N>nodeData = const getNode: {
<N, E, T extends Kind = "directed">(
nodeIndex: NodeIndex
): (
graph: Graph<N, E, T> | MutableGraph<N, E, T>
) => Option.Option<N>
<N, E, T extends Kind = "directed">(
graph: Graph<N, E, T> | MutableGraph<N, E, T>,
nodeIndex: NodeIndex
): Option.Option<N>
}
getNode(graph: Graph<N, E, T> | MutableGraph<N, E, T>graph, const nodeToEmit: numbernodeToEmit)
if (import OptionOption.const isSome: <A>(
self: Option<A>
) => self is Some<A>
Checks whether an Option contains a value (Some).
When to use
Use when you need to branch on a present Option before accessing .value.
Details
- Acts as a type guard, narrowing to
Some<A>
Example (Checking for Some)
import { Option } from "effect"
console.log(Option.isSome(Option.some(1)))
// Output: true
console.log(Option.isSome(Option.none()))
// Output: false
isSome(const nodeData: Option.Option<N>nodeData)) {
return { done: booleandone: false, value: Uvalue: f: (index: number, data: N) => Uf(const nodeToEmit: numbernodeToEmit, const nodeData: Option.Some<N>const nodeData: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: A;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
nodeData.Some<N>.value: Nvalue) }
}
return const nextMapped: () =>
| {
done: boolean
value: U
}
| {
readonly done: true
readonly value: undefined
}
nextMapped()
}
}
}
return { done: truedone: true, value: undefinedvalue: var undefinedundefined } as type const = {
readonly done: true;
readonly value: undefined;
}
const
}
return { Iterator<U, any, any>.next(...[value]: [] | [any]): IteratorResult<U, any>next: const nextMapped: () =>
| {
done: boolean
value: U
}
| {
readonly done: true
readonly value: undefined
}
nextMapped }
}
}))
})