diff --git a/app/Repl/Shared.hs b/app/Repl/Shared.hs
--- a/app/Repl/Shared.hs
+++ b/app/Repl/Shared.hs
@@ -1,25 +1,22 @@
 module Repl.Shared where
 
-import CliOptions (Language(..))
 import Paths_lambda_calculator (version)
-import Language.Lambda.Shared.Errors (LambdaException())
-import Language.Lambda.Shared.UniqueSupply (defaultUniques)
-import Language.Lambda.SystemF
 
-import Data.Text (singleton)
 import Data.Text.IO (putStrLn)
 import Data.Version (showVersion)
 import RIO
-import RIO.State
-import RIO.Text (pack, unpack)
 import System.Console.Repline
-import Control.Monad.Except
-import qualified Data.Map as M
 
-mkReplOpts banner command = ReplOpts
+mkReplOpts
+  :: (MonadIO m, MonadThrow m)
+  => (MultiLine -> HaskelineT m String)
+  -> Command (HaskelineT m)
+  -> Text
+  -> ReplOpts m
+mkReplOpts banner command helpMsg = ReplOpts
   { banner = banner,
     command = command,
-    options = commands,
+    options = commands helpMsg,
     prefix = Just ':',
     multilineCommand = Nothing,
     tabComplete = Custom completer,
@@ -30,14 +27,14 @@
 prompt :: Applicative ap => Text -> HaskelineT ap Text
 prompt prefix = pure $ prefix <> " > "
 
-commands :: (MonadIO m, MonadThrow m) => [(String, String -> HaskelineT m ())]
-commands
+commands :: (MonadIO m, MonadThrow m) => Text -> [(String, String -> HaskelineT m ())]
+commands helpMsg
   = [ ("h", help'),
       ("help", help'),
       ("q", quit'),
       ("quit", quit')
     ]
-  where help' = const helpCommand
+  where help' = const (helpCommand helpMsg)
         quit' = const abort
 
 completer :: Monad m => CompletionFunc m
@@ -49,11 +46,8 @@
           <> version'
           <> ")\nType :h for help\n"
 
-helpCommand :: MonadIO io => HaskelineT io ()
-helpCommand = liftIO $ putStrLn banner
-  where banner = " Commands available: \n\n"
-          <> "    :help, :h\tShow this help\n"
-          <> "    :quit, :q\tQuit\n"
+helpCommand :: MonadIO io => Text -> HaskelineT io ()
+helpCommand message = liftIO $ putStrLn message
 
 version' :: Text
 version' = fromString $ showVersion version
diff --git a/app/Repl/SystemF.hs b/app/Repl/SystemF.hs
--- a/app/Repl/SystemF.hs
+++ b/app/Repl/SystemF.hs
@@ -22,7 +22,7 @@
 runSystemFRepl :: IO ()
 runSystemFRepl
   = void . runExceptT . evalStateT (evalReplOpts replOpts) $ initialState
-  where replOpts = mkReplOpts banner' $ evalSystemF . pack
+  where replOpts = mkReplOpts banner' (evalSystemF . pack) helpMsg
         initialState = mkTypecheckState defaultUniques defaultTyUniques
 
 banner' :: MultiLine -> Repl String
@@ -38,3 +38,31 @@
     Right (res', newState) -> do
       put newState
       liftIO . putStrLn . prettyPrint $ res'
+
+helpMsg :: Text
+helpMsg = " Commands available: \n"
+  <> "    <expression> Evaluate <expression>\n"
+  <> "    :help, :h    Show this help\n"
+  <> "    :quit, :q    Quit\n\n"
+  
+  <> " Expressions can take the form:\n"
+  <> "    x          variable\n"
+  <> "    x:T        type annotated variable\n"
+  <> "    \\x:T. t    abstraction\n"
+  <> "    f x        function application\n"
+  <> "    \\X. t      type abstraction\n"
+  <> "    x [T]      type application\n"
+  <> "    let x = t  global binding\n\n"
+
+  <> " Types can take the form:\n"
+  <> "    T            type variable\n"
+  <> "    T -> T       type of functions\n"
+  <> "    forall X. T  universal type\n\n"
+
+  <> " Examples of valid expressions:\n"
+  <> "    x\n"
+  <> "    \\x:T. x\n"
+  <> "    (\\x:T. x) y:T\n"
+  <> "    \\X. \\x:X. x\n"
+  <> "    \\x:(forall T. T). x\n"
+  <> "    (\\n:((T->T)->T->T) f:(T->T) x:T. f (n f x)) (\\f:(T->T) x:T. x)\n"
diff --git a/app/Repl/Untyped.hs b/app/Repl/Untyped.hs
--- a/app/Repl/Untyped.hs
+++ b/app/Repl/Untyped.hs
@@ -22,21 +22,11 @@
 runUntypedRepl :: IO ()
 runUntypedRepl
   = void . runExceptT . evalStateT (evalReplOpts replOpts) $ initialState
-  where replOpts = ReplOpts
-          { banner = const $ unpack <$> prompt',
-            command = evalLambda . pack,
-            options = commands,
-            prefix = Just ':',
-            multilineCommand = Nothing,
-            tabComplete = Custom completer,
-            initialiser = initializer,
-            finaliser = return Exit
-          }
-
+  where replOpts = mkReplOpts banner' (evalLambda . pack) helpMsg
         initialState = mkEvalState defaultUniques
 
-prompt' :: Repl Text
-prompt' = prompt $ singleton lambda
+banner' :: MultiLine -> Repl String
+banner' _ = unpack <$> prompt (singleton lambda)
 
 evalLambda :: Text -> Repl ()
 evalLambda input = do
@@ -48,3 +38,21 @@
     Right (res', newState) -> do
       put newState
       liftIO . putStrLn . prettyPrint $ res'
+
+helpMsg :: Text
+helpMsg = " Commands available: \n"
+  <> "    <expression> Evaluate <expression>\n"
+  <> "    :help, :h    Show this help\n"
+  <> "    :quit, :q    Quit\n\n"
+  
+  <> " Expressions can take the form:\n"
+  <> "    x          variable\n"
+  <> "    \\x. t      abstraction\n"
+  <> "    f x        function application\n"
+  <> "    let x = t  global binding\n\n"
+
+  <> " Examples of valid expressions:\n"
+  <> "    x\n"
+  <> "    \\x. x\n"
+  <> "    (\\x. x) n\n"
+  <> "    (\\n f x. f (n f x)) (\\f x. f (f x))\n"
diff --git a/lambda-calculator.cabal b/lambda-calculator.cabal
--- a/lambda-calculator.cabal
+++ b/lambda-calculator.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 3256f86f253ee771f5e7374ff11bcb34286722368054e4e233095c13c9abe64b
+-- hash: b69ff1a0ee1fecfd1fc079571eba787eee329de70ac3e79d30bdd4c768a28ec9
 
 name:           lambda-calculator
-version:        3.1.0.0
+version:        3.1.1.0
 synopsis:       A lambda calculus interpreter
 description:    A simple implementation of the Untyped Lambda Calculus
 category:       LambdaCalculus,Language,Teaching
