liveBook · Manning

Breadth-first search

As explained in Learn Haskell by Example

Breadth-first search explores a graph level by level from a starting node, visiting all nodes at one distance before proceeding to the next.

Breadth-first search solves the ladder game by exploring a graph in layers, ensuring the first discovered solution is shortest when every edge has equal cost. section 6.0 section 6.1

Implement the search by maintaining a frontier and recording how each node was reached:

  • Start with the graph and starting node as the initial frontier. section 6.1.1
  • Collect neighboring nodes for every node in the current frontier. section 6.1.1
  • Delete the current frontier from the graph so nodes are not visited twice. section 6.1.1
  • Record each frontier node as the predecessor of its newly discovered neighbors. section 6.1.1
  • Check whether the target appears among the newly discovered neighbors, then backtrack through predecessors to recover the path. section 6.1.1 section 6.2.3

Solving a word ladder

Given a graph of possible word transformations, search outward from the starting word. Because every transformation has equal cost, the first route reaching the target gives an optimal word ladder. A predecessor graph preserves the route for reconstruction. section 6.0 section 6.1 section 6.2.3

Listing 6.5 Determining the shortest paths in directed graphs with uniform cost
type SearchState a = ([a], DiGraph a, DiGraph a)   #1

data SearchResult a = Unsuccessful |
 Successful (DiGraph a)                       #2

bfsSearch :: forall a. Eq a => DiGraph a
 -> a -> a -> Maybe [a]              #3
bfsSearch graph start end
  | start == end = Just [start]     #4
  | otherwise =
    case bfsSearch' ([start], graph, empty) of          #5
          Successful preds -> Just (findSolution preds)   #6
          Unsuccessful -> Nothing
  where
    findSolution :: DiGraph a -> [a]
    findSolution g = L.reverse (go end)   #7
      where
        go x =
          case children x g of    #8
            [] -> [x]                      #9
            (v : _) -> x : go v   #10

    addMultiplePredecessors :: [(a, [a])] -> DiGraph a -> DiGraph a
    addMultiplePredecessors [] g = g
    addMultiplePredecessors ((n, ch) : xs) g =
      addMultiplePredecessors xs (go n ch g)        #11
      where
        go n [] g = g
        go n (x : xs) g = go n xs (addEdge (x, n) g)    #12

    bfsSearch' :: SearchState a -> SearchResult a
    bfsSearch' ([], _, preds) = Unsuccessful     #13
    bfsSearch' (frontier, g, preds) =
      let g' = deleteNodes frontier g   #14
          ch =
            L.map
              (\n -> (n, L.filter (`M.member` g')
 (children n g)))                            #15
              frontier
          frontier' = L.concatMap snd ch              #16
          preds' = addMultiplePredecessors ch preds     #17
       in if end `L.elem` frontier'      #18
            then Successful preds'        #19
            else bfsSearch' (frontier', g', preds')   #20

Inspect a complete Haskell implementation that represents search state, distinguishes successful and unsuccessful searches, and reconstructs the path from predecessors. section 6.2.3

How Learn Haskell by Example covers it

How deep it goes
Defines layered exploration, visited-node deletion, predecessor tracking, and path reconstruction through a complete implementation.
Examples
Uses a word-ladder graph, layered graph figures, predecessor diagrams, and Haskell search listings.
What it assumes
Assumes a graph representing possible game outcomes and develops the search procedure needed to solve it.
What you can do after
Build the algorithm and reconstruct shortest paths from predecessor data in directed graphs with uniform cost.
How it connects
Connects graph search with shortest paths, predecessor graphs, depth-first search, and bidirectional breadth-first search.

Also explained in

Compare how 8 books explain breadth-first search →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.