There is a particular kind of frustration in knowing exactly what a function should do, knowing its input and output types, and still spending ten minutes scanning through docs.rs trying to find its name. You want something that turns a Vec<Option<T>> into an Option<Vec<T>>, you vaguely remember a function like that exists, but you cannot recall whether it lives in the standard library, in itertools, or somewhere else entirely. This is the problem that Roogle is built to solve.
Roogle is a type-directed search engine for Rust APIs, taking direct inspiration from Hoogle, the long-standing Haskell tool that lets you search by type signature rather than function name. The concept is simple: describe the shape of the function you want, and let the search engine find things that match.
Where the Idea Comes From
Hoogle has been around since roughly 2004, created by Neil Mitchell, and it remains one of the most practically useful tools in the Haskell ecosystem. The core insight is that in a strongly typed functional language, a type signature tells you a great deal about what a function does. If you want a function of type [a] -> [a], you know it takes a list and returns a list without changing the element type. That signature matches reverse, sort, tail, init, and several others. Searching by that shape is a legitimate way to discover APIs.
Hoogle’s matching algorithm normalizes type variable names before comparing, so a search for a -> a -> a will match functions with signatures like b -> b -> b. It handles typeclass constraints to some degree, and it ranks results by how closely they match the query. The underlying mechanism is type unification: finding a substitution that makes two type expressions equal.
This works remarkably well in Haskell because the type system, while sophisticated, has one key property that makes search tractable: types are relatively self-contained. A Haskell type signature says most of what you need to know about a function’s interface. There are no lifetimes, no explicit ownership annotations, and while typeclasses add constraints, they slot into the system cleanly enough that a search tool can reason about them.
Rust’s type system does not make the same tradeoffs.
What Roogle Does
Roogle indexes Rust functions and lets you query by type signature. A query like (String, u32) -> bool will return functions that take a String and a u32 and return a bool. Queries with generic type parameters work too, so Vec<T> -> usize will surface functions like Vec::len and similar. The tool performs type unification between your query and the indexed function signatures, returning matches ranked by similarity.
The repository demonstrates the basic workflow: point it at a set of crates, build the index, then query it. The search interface accepts Rust-like type syntax, and the engine does the work of matching across potentially thousands of function signatures.
This fills a real gap. The search on docs.rs is name-based: it helps you when you know what something is called, not when you know what it should do. The rustdoc-generated search embedded in local documentation has historically been similar, though it has improved in recent releases to handle some degree of type-aware matching. But cross-crate, type-directed search of the kind Hoogle provides for Haskell has simply not been a first-class feature of the Rust toolchain.
The Hard Parts of Rust’s Type System
The reason Roogle is a research-grade project rather than a polished production tool comes down to what makes Rust’s type system different from Haskell’s.
Lifetimes are the most obvious complication. A function signature like fn longest<'a>(x: &'a str, y: &'a str) -> &'a str carries information that has no analog in Haskell. When you search for a function of type (&str, &str) -> &str, you might or might not care about the lifetime relationships. Deciding how to match these, whether to treat lifetimes as constraints to unify or to elide them in search, is not a trivial design decision. Eliding them makes search more practical but less precise.
Trait bounds add another layer. The signature fn max<T: PartialOrd>(a: T, b: T) -> T has a bound that affects correctness but may or may not matter for a search query. If you search for (T, T) -> T, should functions with bounds on T appear? Almost certainly yes, but ranking becomes more complex: a fully generic (T, T) -> T is different from one constrained to T: Clone + Debug.
Associated types mean that a type like Iterator::Item is not a free type variable but is determined by the implementing type. Searching for functions that return an iterator where the item type is u32 requires reasoning about trait implementations, not just syntactic type matching.
impl Trait and dyn Trait in function positions add further ambiguity. A function returning impl Display is opaque at the type level; its concrete return type is determined by the function body, not its signature. Matching these against concrete types in search queries requires approximations.
Hoogle sidesteps most of this because Haskell does not have ownership semantics, and typeclass constraints, while powerful, follow rules that are simpler to encode in a search algorithm. Roogle has to make pragmatic decisions about which parts of Rust’s type system to model fully and which to approximate, and those decisions affect every result the tool returns.
rustdoc’s Own Evolution
It is worth noting that the problem Roogle addresses has not gone entirely unnoticed within the official Rust toolchain. In late 2023, rustdoc gained meaningful improvements to its built-in search, moving toward type-aware matching rather than pure name-based search. The rustdoc book documents a query syntax that lets you search by argument and return types within a single crate’s documentation. You can write queries like str -> String or usize, usize -> usize and get relevant results.
This is significant, but it operates at the crate level, not across the entire crate ecosystem. If you are reading the standard library documentation, rustdoc’s search helps you find standard library functions by type. Roogle’s ambition is cross-crate: a single index across many crates that you can search the way you would search Hackage with Hoogle.
The two approaches are complementary. rustdoc’s type search is deeply integrated into the documentation experience and covers whatever crate you happen to be reading. Roogle is a separate tool with broader scope. Whether the two will eventually converge, either through rustdoc gaining ecosystem-wide search or Roogle reaching production maturity, is an open question.
The API Discovery Problem in Context
Understanding why tools like Roogle matter requires acknowledging something about how large API surfaces actually work. The Rust ecosystem on crates.io contains well over 100,000 crates. The standard library alone defines hundreds of methods across its types, and many of those methods do closely related things with subtly different semantics. Iterator::collect, Iterator::partition, Iterator::unzip: these exist, they are well-documented, but knowing they exist requires having encountered them before or stumbling on them during browsing.
Type-directed search inverts the discovery process. Instead of requiring you to know names before you can find documentation, it lets you reason about the shape of the problem and ask whether anything in the ecosystem matches that shape. This is especially powerful for iterator combinators, collection transformations, and numeric operations, where the type signatures are specific enough to meaningfully constrain the search space.
For someone learning Rust, this kind of search could materially reduce the time spent wondering whether a standard library function exists for a common operation. For experienced Rust developers exploring unfamiliar crates, it provides a way to orient around types rather than names.
What Roogle Signals
Roogle is not production infrastructure. The project is a proof of concept and a research artifact, and it has the rough edges that implies. But its existence points at something real about how we interact with typed APIs and how underdeveloped the tooling for type-directed search remains outside of Haskell.
The right comparison is not Hoogle’s twenty-plus years of polish against Roogle’s current state. It is the observation that the underlying idea, searching by type signature, is sound and practically useful, and that Rust’s rich type system makes it both more valuable and more technically demanding than in languages with simpler types. The lifetimes and trait bounds that make Rust’s type signatures expressive are the same features that make indexing and matching them correctly a genuine research problem.
If the project matures, or if its ideas inform future versions of rustdoc’s cross-crate search, Rust developers will spend less time guessing at function names and more time writing code. That is a straightforward win for a language where the type system is already doing so much expressive work.