diff --git a/Data/Loc.hs b/Data/Loc.hs
--- a/Data/Loc.hs
+++ b/Data/Loc.hs
@@ -17,6 +17,8 @@
     startPos,
     linePos,
     advancePos,
+    displayPos,
+    displaySPos,
 
     Loc(..),
     locStart,
@@ -24,6 +26,9 @@
 
     (<-->),
 
+    displayLoc,
+    displaySLoc,
+
     SrcLoc(..),
     srclocOf,
     srcspan,
@@ -47,8 +52,11 @@
 import Data.Monoid (Monoid(..))
 
 -- | Position type.
-data Pos = -- | Source file name, line, column, and character offset
-           Pos !String
+data Pos = -- | Source file name, line, column, and character offset.
+           --
+           -- Line numbering starts at 1, column offset starts at 1, and
+           -- character offset starts at 0.
+           Pos !FilePath
                {-# UNPACK #-} !Int
                {-# UNPACK #-} !Int
                {-# UNPACK #-} !Int
@@ -63,7 +71,7 @@
         compare (f1, l1, c1) (f2, l2, c2)
 
 -- | Position file.
-posFile :: Pos -> String
+posFile :: Pos -> FilePath
 posFile (Pos f _ _ _) = f
 
 -- | Position line.
@@ -78,24 +86,35 @@
 posCoff :: Pos -> Int
 posCoff (Pos _ _ _ coff) = coff
 
+-- | Starting position for given file.
+startPos :: FilePath -> Pos
+startPos f = Pos f startLine startCol startCoff
+
 startLine :: Int
 startLine = 1
 
 startCol :: Int
-startCol = 0
+startCol = 1
 
 startCoff :: Int
 startCoff = 0
 
-startPos :: String -> Pos
-startPos f = Pos f startLine startCol startCoff
-
-linePos :: String -> Int -> Pos
+-- | Position corresponding to given file and line.
+--
+-- Note that the associated character offset is set to 0.
+linePos :: FilePath -> Int -> Pos
 linePos f l = Pos f l startCol startCoff
 
+-- | Advance a position by a single character. Newlines increment the line
+-- number, tabs increase the position column following a tab stop width of 8,
+-- and all other characters increase the position column by one. All characters,
+-- including newlines and tabs, increase the character offset by 1.
+--
+-- Note that 'advancePos' assumes UNIX-style newlines.
 advancePos :: Pos -> Char -> Pos
-advancePos (Pos f l _ coff) '\n' = Pos f (l+1) startCol (coff + 1)
-advancePos (Pos f l c coff) _    = Pos f l     (c + 1)  (coff + 1)
+advancePos (Pos f l _ coff) '\n' = Pos f (l+1) startCol              (coff + 1)
+advancePos (Pos f l c coff) '\t' = Pos f l     (8*((c + 8) `div` 8)) (coff + 1)
+advancePos (Pos f l c coff) _    = Pos f l     (c + 1)               (coff + 1)
 
 -- | Location type, consisting of a beginning position and an end position.
 data Loc =  NoLoc
@@ -213,7 +232,7 @@
 class Relocatable a where
     reloc :: Loc -> a -> a
 
--- | An 'L a' is an 'a' with an associated 'Loc', but this location is ignored
+-- | A value of type @L a@ is a value of type @a@ with an associated 'Loc', but this location is ignored
 -- when performing comparisons.
 data L a = L Loc a
 
@@ -234,3 +253,40 @@
 
 instance Relocatable (L a) where
     reloc loc (L _ x) = L loc x
+
+-- | Format a position in a human-readable way, returning an ordinary
+-- 'String'.
+displayPos :: Pos -> String
+displayPos p = displayLoc (Loc p p)
+
+-- | Format a position in a human-readable way.
+displaySPos :: Pos -> ShowS
+displaySPos p = displaySLoc (Loc p p)
+
+-- | Format a location in a human-readable way, returning an ordinary
+-- 'String'.
+displayLoc :: Loc -> String
+displayLoc loc = displaySLoc loc ""
+
+-- | Format a location in a human-readable way.
+displaySLoc :: Loc -> ShowS
+displaySLoc (Loc p1@(Pos src line1 col1 _) (Pos _ line2 col2 _))
+  | (line1, col1) == (line2, col2) =
+      -- filename.txt:2:3
+      showString src . colon . shows line1 . colon . shows col1
+  | line1 == line2 =
+      -- filename.txt:2:3-5
+      showString src .
+      colon . shows line1 .
+      colon . shows col1 .
+      dash  . shows col2
+  | otherwise =
+      -- filename.txt:2:3-4:5
+      showString src .
+      colon . shows line1 .
+      colon . shows col1 .
+      dash  . shows line2 .
+      colon . shows col2
+  where
+    colon = (':' :)
+    dash  = ('-' :)
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -25,7 +25,7 @@
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 
-Copyright (c) 2011-2014, Geoffrey Mainland
+Copyright (c) 2011-2015, Geoffrey Mainland
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,3 @@
 import Distribution.Simple
+
 main = defaultMain
diff --git a/srcloc.cabal b/srcloc.cabal
--- a/srcloc.cabal
+++ b/srcloc.cabal
@@ -1,10 +1,10 @@
 name:           srcloc
-version:        0.4.1
+version:        0.5.0
 cabal-version:  >= 1.6
 license:        BSD3
 license-file:   LICENSE
 copyright:      (c) 2006-2011 Harvard University
-                (c) 2011-2014 Geoffrey Mainland
+                (c) 2011-2015 Geoffrey Mainland
 author:         Geoffrey Mainland <mainland@cs.drexel.edu>
 maintainer:     Geoffrey Mainland <mainland@cs.drexel.edu>
 stability:      alpha
