Reusing Existing Instances with Haskell’s DerivingVia Extension
Use Haskell’s DerivingVia to automatically reuse existing class instances for newtypes. Learn the mechanism, see a concrete example, and avoid common pitfalls such as coercibility errors and orphan instances.
23 Aug 2026, 13:07 UTC

Why DerivingVia Is Useful
When you create a newtype wrapper, you often want to give it the same class instances as the wrapped type. Writing boilerplate instance declarations or enabling orphan instances can clutter your code. DerivingVia lets you write a single line that tells GHC to reuse an existing instance from a helper type that is representation‑compatible with your newtype.
How DerivingVia Works
DerivingVia relies on Haskell’s coercible type class. Two types are coercible if they have the same runtime representation, typically when one is a newtype over the other. GHC can then replace a call to the instance’s method with a coerce of the helper type’s method, avoiding any runtime cost.
The syntax is:
newtype T = T Int
deriving (Show) via (Sum Int)
Here Sum Int is a helper type that already has a Show instance. Because T and Sum Int are coercible, GHC generates an instance for T that simply coerces the value to Sum Int and delegates to show.
Concrete Example: Deriving Show
{-# LANGUAGE DerivingVia, GeneralizedNewtypeDeriving #-}
newtype Quiet = Quiet Int
deriving (Show) via (Sum Int)
main :: IO ()
main = print (Quiet 42)
Running this prints Sum 42, the same output as show (Sum 42). The compiler rewrites the show call as:
show (Quiet 42) -- becomes
show (coerce (Quiet 42) :: Sum Int)
Because Quiet and Sum Int share the same representation, the coerce is free.
Practical Use: JSON Derivation via a Wrapper
Suppose you have a library that provides a ToJSON instance for Text but you want a distinct type UserId that should be encoded as a string. You can write:
{-# LANGUAGE DerivingVia #-}
newtype UserId = UserId Text
deriving (Show, Eq) via Text
Now UserId inherits Show and Eq from Text. If you also need ToJSON, you can enable the appropriate package and add:
deriving (ToJSON) via Text
GHC will generate the instance by coercing UserId to Text and calling the existing ToJSON implementation.
Checking That Derivation Worked
- Enable the extension:
{-# LANGUAGE DerivingVia #-}. - Compile the module with
ghc -Wall -Werrorto surface any coercion errors. - Run a small test:
print (UserId "alice")and verify the output matches"alice"or the helper’s representation. - If you see a compile‑time error like
Couldn't match type ‘UserId’ with ‘Text’, the types are not coercible; adjust the helper type or use a manual instance.
Limits and Common Pitfalls
- Coercibility Requirement: DerivingVia only works when the newtype and helper type are representation‑compatible. Abstract types, type families, or wrappers that add new fields break this guarantee.
- Polymorphic Helper Types: Using a helper like
Maybe amay requireUndecidableInstancesand can increase compile time. - Orphan Instances: If the helper type’s instance is defined in a different module, you may inadvertently create an orphan instance for your newtype. Keep helper instances in the same module if possible.
- GHC Version Sensitivity: The extension was introduced in GHC 8.6. Later versions tightened coercion rules; code that compiles on 8.6 may fail on 9.x if the representation changed.
- Behavior Changes: Your newtype’s instance will change if the helper type’s instance changes. Document this dependency to avoid surprises.
Common Mistakes to Avoid
- Assuming DerivingVia works for any type pair. Always verify coercibility with
:type coercein GHCi. - Neglecting
UndecidableInstanceswhen the helper type is polymorphic. GHC will reject the derivation otherwise. - Overlooking orphan instance warnings. Use
-Worphansto catch them early. - Forgetting to enable
StandaloneDerivingwhen you need to derive in a separate module.
Conclusion
DerivingVia is a powerful tool for reducing boilerplate and maintaining consistency across newtype wrappers. By reusing existing, well‑tested instances, you keep your code concise and avoid subtle bugs. Just remember the coercibility requirement, be mindful of orphan instances, and test the derived behavior against the helper type’s implementation.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.