Overlapping instances
Two instances overlap when a type matches both of their heads[1][2]. Instance resolution is not a backtracking search: GHC matches the constraint against instance heads, ignoring their contexts, and commits to the one that matches[7]. With two candidates and no way to know which is intended, it reports an error rather than guess. The OVERLAPPING and OVERLAPPABLE pragmas resolve the conflict by declaring that the most specific instance wins, which is how a library can treat String specially while still providing an instance for every list[1]. The choice is then made wherever the constraint happens to be solved, so the result can depend on which instances were in scope there, and on whether the type was known; INCOHERENT removes the remaining check. Overlap was used heavily in type-level programming[3], and closed type families now provide ordered matching without it[4].
Example
The classic case: [Char] matches both list instances.
{-# LANGUAGE FlexibleInstances #-}import Data.List (intercalate)class Pretty a where pp :: a -> Stringinstance Pretty Char where pp c = [c]instance Pretty a => Pretty [a] where pp xs = "[" ++ intercalate ", " (map pp xs) ++ "]"instance Pretty String where pp s = show s -- String = [Char]main :: IO ()main = putStrLn (pp "abc")
GHC's error at the use.
noprag.hs:11:18: error:* Overlapping instances for Pretty Stringarising from a use of `pp'Matching instances:instance Pretty String -- Defined at noprag.hs:8:10instance Pretty a => Pretty [a] -- Defined at noprag.hs:7:10* In the first argument of `putStrLn', namely `(pp "abc")'In the expression: putStrLn (pp "abc")In an equation for `main': main = putStrLn (pp "abc")|11 | main = putStrLn (pp "abc")
The declarations are accepted; the error appears only when a constraint needs to choose. GHC checks overlap lazily, at the point of use[1].
Most specific wins
Marking the general instance OVERLAPPABLE, or the specific one OVERLAPPING, allows the overlap. When several instances match a constraint, GHC picks the one whose head is strictly more specific than all the others, meaning it is a substitution instance of them, and reports an error if there is no such instance[1].
The same instances with pragmas.
{-# LANGUAGE FlexibleInstances #-}import Data.List (intercalate)class Pretty a where pp :: a -> Stringinstance Pretty Char where pp c = [c]instance Pretty Int where pp = showinstance {-# OVERLAPPABLE #-} Pretty a => Pretty [a] wherepp xs = "[" ++ intercalate ", " (map pp xs) ++ "]"instance {-# OVERLAPPING #-} Pretty String wherepp s = show smain :: IO ()main = doputStrLn (pp "abc") -- the String instanceputStrLn (pp [1, 2, 3 :: Int]) -- the list instanceputStrLn (pp ["ab", "cd"]) -- list of String: both, nested
Running it.
"abc"[1, 2, 3]["ab", "cd"]
In the last line both instances are used: the outer list is not a String, so the general instance applies, and its elements are.
Unknown types
Resolution can be asked to choose before the type is known. Inside a function polymorphic in a, the constraint Pretty [a] matches the general instance, but it would match the String instance if a were Char. Committing to the general instance would give an answer that is wrong for some callers, so GHC rejects the program[1].
A function whose instance depends on its caller.
{-# LANGUAGE FlexibleInstances #-}import Data.List (intercalate)class Pretty a where pp :: a -> Stringinstance Pretty Char where pp c = [c]instance {-# OVERLAPPABLE #-} Pretty a => Pretty [a] wherepp xs = "[" ++ intercalate ", " (map pp xs) ++ "]"instance {-# OVERLAPPING #-} Pretty String wherepp s = show s-- Which instance? It depends on a, which is not known here.twice :: Pretty a => [a] -> Stringtwice xs = pp xs ++ pp xs
GHC's error.
poly.hs:14:12: error:* Overlapping instances for Pretty [a] arising from a use of `pp'Matching instance:instance [overlappable] Pretty a => Pretty [a]-- Defined at poly.hs:7:31Potentially matching instance:instance [overlapping] Pretty String -- Defined at poly.hs:9:30(The choice depends on the instantiation of `a'To pick the first instance above, use IncoherentInstanceswhen compiling the other instance declarations)* In the first argument of `(++)', namely `pp xs'In the expression: pp xs ++ pp xsIn an equation for `twice': twice xs = pp xs ++ pp xs
The usual fix is to leave the constraint to the caller, writing Pretty [a] => in the signature so that it is solved at the call site where the type is known. Marking an instance INCOHERENT instead tells GHC to pick the general instance anyway and not complain: the function then prints strings as lists of characters even when called at String.
Coherence across modules
Overlap is only checked among the instances visible where a constraint is solved. A module that sees only the general instance solves Pretty [Char] with it, and compiled code keeps that choice; a module that also sees the specific instance solves the same constraint differently[1][6]. The same expression, at the same type, then has two meanings in one program.
A library with the general instance, which solves Pretty [Char] in label.
{-# LANGUAGE FlexibleInstances #-}module General (Pretty (..), label) whereimport Data.List (intercalate)class Pretty a where pp :: a -> Stringinstance Pretty Char where pp c = [c]instance {-# OVERLAPPABLE #-} Pretty a => Pretty [a] wherepp xs = "[" ++ intercalate ", " (map pp xs) ++ "]"-- Pretty [Char] is solved here, where only the general instance exists.label :: String -> Stringlabel s = "label: " ++ pp s
Another module adds the specific instance.
{-# LANGUAGE FlexibleInstances #-}module Specific () whereimport Generalinstance {-# OVERLAPPING #-} Pretty String where pp s = show s
A program that uses both.
import Generalimport Specific ()main :: IO ()main = doputStrLn (pp "abc") -- solved here: the String instanceputStrLn (label "abc") -- solved in General: the list instance
Running it: the same string, printed two ways.
"abc"label: [a, b, c]
This is the same failure of global uniqueness that orphan instances cause, and the two often occur together, since the specific instance is frequently an orphan. It does not break type safety, but it breaks the property that a class method means the same thing at the same type everywhere, which libraries relying on class laws, such as sets ordered by Ord, depend on[6].
Alternatives
Closed type families have ordered equations: GHC tries them from top to bottom, and an equation is used only if no earlier one could apply to the arguments, even after further instantiation[4]. A type-level test such as “is this type Char?” can therefore be written without overlap, and a class indexed by its result dispatches to the right instance.
The String special case with a closed type family.
{-# LANGUAGE DataKinds, TypeFamilies, MultiParamTypeClasses, FlexibleInstances,FlexibleContexts, UndecidableInstances, ScopedTypeVariables,KindSignatures, AllowAmbiguousTypes, TypeApplications #-}import Data.List (intercalate)import Data.Kind (Type)-- A closed type family's equations are tried in order, so it can express-- "Char, or anything else" without overlapping instances.type family IsChar (a :: Type) :: Bool whereIsChar Char = 'TrueIsChar a = 'Falseclass PrettyList (flag :: Bool) a where ppList :: [a] -> Stringinstance PrettyList 'True Char where ppList s = show sinstance Pretty a => PrettyList 'False a where ppList xs = "[" ++ intercalate ", " (map pp xs) ++ "]"class Pretty a where pp :: a -> Stringinstance Pretty Char where pp c = [c]instance Pretty Int where pp = showinstance PrettyList (IsChar a) a => Pretty [a] where pp = ppList @(IsChar a)main :: IO ()main = doputStrLn (pp "abc")putStrLn (pp [1, 2, 3 :: Int])putStrLn (pp ["ab", "cd"])
Running it.
"abc"[1, 2, 3]["ab", "cd"]
Instance chains, proposed by Morris and Jones, build ordered alternatives and explicit failure into the instance language itself[5]. The simplest alternative is a newtype: newtype Quoted = Quoted String with its own instance makes the special treatment a choice made at the call site, visible in the types, rather than an effect of resolution order.
Rules
For a constraint , GHC finds all instances whose head matches by one-way matching, ignoring their contexts[1]. Instances that are overlapped by a more specific candidate are discarded if either is marked appropriately. If exactly one non-incoherent candidate remains, it is chosen only if no other instance unifies with without matching it, meaning no instance could apply after further instantiation of type variables; incoherent instances are exempt from this check. Contexts are checked only after the choice, so instance Show a => Pretty a overlaps every other instance of Pretty, whatever the context says.
History
Wadler and Blott's type classes of 1989 required instances not to overlap[7]. Overlapping instances were implemented in Gofer and Hugs and surveyed as a design option by Peyton Jones, Jones and Meijer in 1997[2]. GHC's OverlappingInstances and IncoherentInstances extensions applied to whole modules; GHC 7.10 in 2015 replaced them with per-instance pragmas. Overlap was central to early type-level programming such as the HList library of heterogeneous collections[3]. Instance chains in 2010[5] and closed type families in GHC 7.8 in 2014[4] gave ordered alternatives without overlap.
see also
- Orphan instanceAn orphan instance is a type class instance declared in a module that defines neither the class nor the type. Because instance resolution is global but imports are not, two orphans for the same class and type can coexist in one program, and code compiled against different ones can disagree: a Set built under one ordering and searched under another silently loses elements. GHC warns about orphans, and Rust forbids them outright with its orphan rule. The usual fix is a newtype, which gives the instance a type of its own.
- Dictionary passingDictionary passing is the standard way to implement type classes. Each class becomes a record type whose fields are its methods, each instance becomes a value of that record type, and each function with a class constraint receives the record, the dictionary, as an extra argument, which the compiler supplies at every call site after resolving which instance applies. An instance that itself has a context, such as equality on lists given equality on elements, becomes a function from dictionaries to a dictionary, and a superclass becomes a field. The same technique written by hand is the usual way to get type-class-like overloading in OCaml, with records, first-class modules or functors.
- Constraint kindsConstraintKinds is the GHC extension that gives constraints their own kind, Constraint, so that the thing to the left of => becomes a first-class type-level entity that can be named with a synonym, passed as a parameter, returned by a type family, and stored in a data type. It lets a class leave to each instance what that instance needs of its element types, as when a container class requires Ord for sets and nothing for lists, and it lets dictionaries be packaged as ordinary values with Dict.
- Deriving strategyA deriving strategy is an explicit choice of how GHC produces a derived type class instance: stock, generated by the compiler from the constructors; newtype, reusing the wrapped type's instance by coercion; anyclass, an empty instance that takes the class's default methods; or via, reusing the instance of another type with the same representation. Several strategies can apply to the same declaration, with different results, so naming the strategy removes the ambiguity. The two coercing strategies are sound only when the class's methods can be coerced, which GHC checks with type roles.
- Type-directed disambiguationType-directed disambiguation is OCaml's rule, since version 4.01, for deciding which record type a field label, or which variant type a constructor, belongs to when several in scope share the name: if the expected type is already known at that point of type inference, it decides; otherwise the most recently defined type with that name wins. It also lets labels and constructors be used without being in scope when the type is known. Because the outcome depends on what inference knows at each point, the -principal flag warns when a choice relied on information that a different inference order might not have had.
referenced by
further reading
- [1]GHC User’s Guide, “Overlapping instances”.
- [2]S. Peyton Jones, M. Jones, E. Meijer, “Type classes: an exploration of the design space”, Haskell Workshop (1997).
- [3]O. Kiselyov, R. Lämmel, K. Schupke, “Strongly typed heterogeneous collections”, Haskell Workshop (2004).
- [4]R. A. Eisenberg, D. Vytiniotis, S. Peyton Jones, S. Weirich, “Closed type families with overlapping equations”, POPL (2014).
- [5]J. G. Morris, M. P. Jones, “Instance chains: type class programming without overlapping instances”, ICFP (2010).
- [6]E. Z. Yang, “Type classes: confluence, coherence and global uniqueness”, blog post (2014).
- [7]P. Wadler, S. Blott, “How to make ad-hoc polymorphism less ad hoc”, POPL (1989).
last updated