diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # Revision history for haskell-debugger-view
 
+## 0.2.0.0 -- 2026-01-05
+
+* Add support for more complex debug visualizations using the Program abstraction
+    * API change: `debugValue` and `debugFields` now return `Program`-wrapped
+      values, rather than `VarFields/VarValue` directly.
+* Introduce new functions `isThunk` and `ifP` for conditional debugging behavior
+* Enhance list visualization to show up to 50 forced elements
+* Add improved handling for lazy values in debug views
+* Update documentation and examples for custom DebugView instances
+
 ## 0.1.0.0 -- 2025-11-18
 
 * First version. Released on an unsuspecting world.
diff --git a/haskell-debugger-view.cabal b/haskell-debugger-view.cabal
--- a/haskell-debugger-view.cabal
+++ b/haskell-debugger-view.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.12
 name:            haskell-debugger-view
-version:         0.1.0.0
+version:         0.2.0.0
 license:         BSD-3-Clause
 author:          Matthew Pickering, Rodrigo Mesquita
 maintainer:      matthewtpickering@gmail.com, rodrigo@well-typed.com
diff --git a/src/GHC/Debugger/View/ByteString.hs b/src/GHC/Debugger/View/ByteString.hs
--- a/src/GHC/Debugger/View/ByteString.hs
+++ b/src/GHC/Debugger/View/ByteString.hs
@@ -6,6 +6,6 @@
 import qualified Data.ByteString    as BS
 
 instance DebugView BS.ByteString where
-  debugValue  t = VarValue (show t) False
-  debugFields _ = VarFields []
+  debugValue  t = simpleValue (show t) False
+  debugFields _ = pure (VarFields [])
 
diff --git a/src/GHC/Debugger/View/Class.hs b/src/GHC/Debugger/View/Class.hs
--- a/src/GHC/Debugger/View/Class.hs
+++ b/src/GHC/Debugger/View/Class.hs
@@ -20,7 +20,16 @@
   , VarValue(..)
   , VarFields(..)
   , VarFieldValue(..)
+  , simpleValue
 
+
+    -- * A 'Program' can describe a more complicated visualisation method which
+    -- can query some information from the debugger.
+  , Program(..)
+  , isThunk
+  , ifP
+
+
   -- * Utilities
   --
   -- | These can make it easier to write your own custom instances.
@@ -40,6 +49,9 @@
   )
   where
 
+import Data.Int
+import Data.Word
+
 -- | Custom handling of debug terms (e.g. in the variables pane, or when
 -- inspecting a lazy variable)
 class DebugView a where
@@ -60,17 +72,52 @@
   --
   -- This method should only be called to get the fields if the corresponding
   -- @'VarValue'@ has @'varExpandable' = True@.
-  debugFields :: a -> VarFields
+  debugFields :: a -> Program VarFields
 
+-- | The 'Program' abstraction allows more complicated 'DebugView' instances
+-- to be constructed. The debugger will interpreter a 'Program' lazily when
+-- determining how to display a variable.
+--
+-- At the moment the only interesting query when constructing a program is determining
+-- if a value is already evaluated or not. This can be used to only display the evaluated
+-- prefix of a list for example.
+data Program a where
+    -- | Lift a value to a program
+    PureProgram :: a -> Program a
+    -- | Program application
+    ProgramAp :: Program (a -> b) -> Program a -> Program b
+    -- | Evaluate the conditional, and branch on the result
+    ProgramBranch :: Program Bool -> Program a -> Program a -> Program a
+    -- | Is the value a thunk or evaluated?
+    ProgramAskThunk :: a -> Program Bool
+
+instance Functor Program where
+   fmap f x = ProgramAp (PureProgram f) x
+
+instance Applicative Program where
+   pure = PureProgram
+   fx <*> fy = ProgramAp fx fy
+
+-- | Construct a 'VarValue' which doesn't require a 'Program'.
+simpleValue :: String -> Bool -> VarValue
+simpleValue s b = VarValue (pure s) b
+
+-- | Construct a 'Program' which determines if 'a' is a thunk or not.
+isThunk :: a -> Program Bool
+isThunk = ProgramAskThunk
+
+-- | Construct a program which branches
+ifP :: Program Bool -> Program a -> Program a -> Program a
+ifP = ProgramBranch
+
 -- | The representation of the value for some variable on the debugger
 data VarValue = VarValue
   { -- | The value to display inline for this variable
-    varValue      :: String
+    varValue      :: Program String
 
     -- | Can this variable further be expanded (s.t. @'debugFields'@ is not null?)
   , varExpandable :: Bool
   }
-  deriving (Show, Read)
 
 -- | The representation for fields of a value which is expandable in the debugger
 newtype VarFields = VarFields
@@ -108,11 +155,19 @@
 newtype BoringTy a = BoringTy a
 
 instance Show a => DebugView (BoringTy a) where
-  debugValue (BoringTy x) = VarValue (show x) False
-  debugFields _           = VarFields []
+  debugValue (BoringTy x) = simpleValue (show x) False
+  debugFields _           = pure $ VarFields []
 
 deriving via BoringTy Int     instance DebugView Int
+deriving via BoringTy Int8    instance DebugView Int8
+deriving via BoringTy Int16   instance DebugView Int16
+deriving via BoringTy Int32   instance DebugView Int32
+deriving via BoringTy Int64   instance DebugView Int64
 deriving via BoringTy Word    instance DebugView Word
+deriving via BoringTy Word8   instance DebugView Word8
+deriving via BoringTy Word16  instance DebugView Word16
+deriving via BoringTy Word32  instance DebugView Word32
+deriving via BoringTy Word64  instance DebugView Word64
 deriving via BoringTy Double  instance DebugView Double
 deriving via BoringTy Float   instance DebugView Float
 deriving via BoringTy Integer instance DebugView Integer
@@ -120,31 +175,48 @@
 deriving via BoringTy String  instance DebugView String
 
 instance DebugView (a, b) where
-  debugValue _ = VarValue "( , )" True
-  debugFields (x, y) = VarFields
+  debugValue _ = simpleValue "( , )" True
+  debugFields (x, y) = pure $ VarFields
     [ ("fst", VarFieldValue x)
     , ("snd", VarFieldValue y) ]
 
+-- | This instance will display up to the first 50 forced elements of a list.
+instance {-# OVERLAPPABLE #-} DebugView [a] where
+  debugValue [] = simpleValue "[]" False
+  debugValue (_:_) = simpleValue "[...]" True
+  debugFields v = VarFields <$> go 0 v
+    where
+      go :: Int -> [a] -> Program [(String, VarFieldValue)]
+      go 50 xs = pure [("tail", VarFieldValue xs)]
+      go _ [] = pure []
+      go n (x:xs) = ((show n, VarFieldValue x) :) <$>
+                      (ifP (isThunk xs) (pure $ [("tail", VarFieldValue xs)])
+                                        (go (n + 1) xs))
+
 --------------------------------------------------------------------------------
 -- * (Internal) Wrappers required to call `evalStmt` on methods more easily
 --------------------------------------------------------------------------------
 
 -- | Wrapper to make evaluating from debugger easier
 data VarValueIO = VarValueIO
-  { varValueIO :: IO String
+  { varValueIO :: Program (IO String)
   , varExpandableIO :: Bool
   }
 
 debugValueIOWrapper :: DebugView a => a -> IO [VarValueIO]
 debugValueIOWrapper x = case debugValue x of
   VarValue str b ->
-    pure [VarValueIO (pure str) b]
+    pure [VarValueIO (pure <$> str) b]
 
 newtype VarFieldsIO = VarFieldsIO
-  { varFieldsIO :: [(IO String, VarFieldValue)]
+  { varFieldsIO :: Program [(IO String, VarFieldValue)]
   }
 
 debugFieldsIOWrapper :: DebugView a => a -> IO [VarFieldsIO]
-debugFieldsIOWrapper x = case debugFields x of
-  VarFields fls ->
-    pure [VarFieldsIO [ (pure fl_s, b) | (fl_s, b) <- fls]]
+debugFieldsIOWrapper x = pure [VarFieldsIO (toVarFieldsIO <$> (debugFields x))]
+
+toVarFieldsIO :: VarFields -> [(IO String, VarFieldValue)]
+toVarFieldsIO x =
+  case x of
+    VarFields fls -> [ (pure fl_s, b) | (fl_s, b) <- fls]
+
diff --git a/src/GHC/Debugger/View/Containers.hs b/src/GHC/Debugger/View/Containers.hs
--- a/src/GHC/Debugger/View/Containers.hs
+++ b/src/GHC/Debugger/View/Containers.hs
@@ -7,15 +7,15 @@
 import qualified Data.Map           as M
 
 instance DebugView (IM.IntMap a) where
-  debugValue _ = VarValue "IntMap" True
-  debugFields im = VarFields
+  debugValue _ = simpleValue "IntMap" True
+  debugFields im = pure $ VarFields
     [ (show k, VarFieldValue v)
     | (k, v) <- IM.toList im
     ]
 
 instance Show k => DebugView (M.Map k a) where
-  debugValue _ = VarValue "Map" True
-  debugFields m = VarFields
+  debugValue _ = simpleValue "Map" True
+  debugFields m = pure $ VarFields
     [ (show k, VarFieldValue v)
     | (k, v) <- M.toList m
     ]
diff --git a/src/GHC/Debugger/View/Text.hs b/src/GHC/Debugger/View/Text.hs
--- a/src/GHC/Debugger/View/Text.hs
+++ b/src/GHC/Debugger/View/Text.hs
@@ -6,6 +6,6 @@
 import qualified Data.Text          as T
 
 instance DebugView T.Text where
-  debugValue  t = VarValue (show (T.unpack t)) False
-  debugFields _ = VarFields []
+  debugValue  t = simpleValue (show (T.unpack t)) False
+  debugFields _ = pure $ VarFields []
 
