diff --git a/Data/Random/Choose/Executable.hs b/Data/Random/Choose/Executable.hs
new file mode 100644
--- /dev/null
+++ b/Data/Random/Choose/Executable.hs
@@ -0,0 +1,46 @@
+{- |
+
+A command-line program that uses "Data.Random.Choose".
+
+Its arguments are specified by "Data.Random.Choose.Executable.Args".
+
+-}
+
+module Data.Random.Choose.Executable ( main ) where
+
+--------------------------------------------------------------------------------
+
+import qualified Data.Random.Choose.Executable.Args as Args
+import           Data.Random.Choose.IO              (getSelectionsIO)
+
+import qualified Data.Text.IO as TextIO
+
+import Control.Exception.Base (try)
+import Control.Monad          (when)
+import Data.Text              (Text)
+import System.IO              (stdin)
+import System.IO.Error        (isEOFError)
+
+--------------------------------------------------------------------------------
+
+main :: IO ()
+-- ^ The entry point for an executable that reads lines from stdin and outputs
+--   some fixed number of them, selected uniformly at random.
+
+readLine :: IO (Maybe Text)
+-- ^ Produces 'Just' a line of text, or 'Nothing' if the stream has ended.
+
+--------------------------------------------------------------------------------
+
+main = do
+    args <- Args.getArgs
+    let n = Args.getN args
+    when (n > 0) $ do
+        selections <- getSelectionsIO readLine n
+        mapM_ TextIO.putStrLn selections
+
+readLine = do
+    lineEither <- try $ TextIO.hGetLine stdin
+    case lineEither of
+        Left e     -> if isEOFError e then return Nothing else ioError e
+        Right line -> return $ Just line
diff --git a/Data/Random/Choose/Executable/Args.hs b/Data/Random/Choose/Executable/Args.hs
new file mode 100644
--- /dev/null
+++ b/Data/Random/Choose/Executable/Args.hs
@@ -0,0 +1,52 @@
+{- |
+
+Defines the command-line arguments for "Data.Random.Choose.Executable".
+
+-}
+
+module Data.Random.Choose.Executable.Args
+    ( Args(..), getArgs
+    -- * /n/
+    , getN, defaultN, parserN
+    ) where
+
+--------------------------------------------------------------------------------
+
+import Control.Applicative (optional)
+
+import Data.Maybe  (fromMaybe)
+import Data.Monoid ((<>))
+
+import qualified Options.Applicative.Builder as Opt
+
+import Options.Applicative.Extra (execParser, helper)
+import Options.Applicative.Types (Parser)
+
+--------------------------------------------------------------------------------
+
+data Args = Args
+    { argN :: Maybe Int -- ^ /n/, the number of items to choose.
+    }
+
+defaultN :: Int
+-- ^ The default value for /n/ if not specified.
+defaultN = 1
+
+readInt :: Opt.ReadM Int
+readInt = Opt.auto
+
+parserN :: Parser (Maybe Int)
+parserN = optional $ Opt.argument readInt $ Opt.metavar "N" <> Opt.help help
+    where help = "Number of items to choose (default: " ++ show defaultN ++ ")"
+
+getN :: Args -> Int
+getN = fromMaybe defaultN . argN
+
+parser :: Parser Args
+parser = Args <$> parserN
+
+parserInfo :: Opt.InfoMod a
+parserInfo = Opt.header "Selects lines from stdin uniformly at random."
+
+getArgs :: IO Args
+getArgs = execParser $ Opt.info (helper <*> parser) parserInfo
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/choose-exe.cabal b/choose-exe.cabal
new file mode 100644
--- /dev/null
+++ b/choose-exe.cabal
@@ -0,0 +1,46 @@
+-- This file has been generated from package.yaml by hpack version 0.14.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           choose-exe
+version:        0.1.0.0
+synopsis:       Command-line program to choose random element from a stream.
+description:    A command-line program that reads lines from stdin and outputs some fixed number of them, selected uniformly at random.
+category:       Application
+author:         Chris Martin <ch.martin@gmail.com>
+maintainer:     Chris Martin <ch.martin@gmail.com>
+license:        Apache-2.0
+license-file:   license.txt
+build-type:     Simple
+cabal-version:  >= 1.10
+
+library
+  hs-source-dirs:
+      .
+  ghc-options: -Wall -fwarn-unused-imports
+  build-depends:
+      base >= 4.7 && < 5
+    , choose
+    , optparse-applicative
+    , text
+  exposed-modules:
+      Data.Random.Choose.Executable
+      Data.Random.Choose.Executable.Args
+  other-modules:
+      Paths_choose_exe
+  default-language: Haskell2010
+
+executable choose
+  main-is: choose.hs
+  hs-source-dirs:
+      .
+  ghc-options: -Wall -fwarn-unused-imports
+  build-depends:
+      base >= 4.7 && < 5
+    , choose
+    , optparse-applicative
+    , text
+  other-modules:
+      Data.Random.Choose.Executable
+      Data.Random.Choose.Executable.Args
+  default-language: Haskell2010
diff --git a/choose.hs b/choose.hs
new file mode 100644
--- /dev/null
+++ b/choose.hs
@@ -0,0 +1,3 @@
+module Main (main) where
+
+import Data.Random.Choose.Executable
diff --git a/license.txt b/license.txt
new file mode 100644
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,13 @@
+Copyright 2016 Chris Martin
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
