diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,13 @@
+# 0.4.0
+
+## Breaking changes
+
+- Change in behavior when the same option is specified multiple times [#8](https://github.com/tanakh/optparse-declarative/pull/8)
+
+## Other changes
+
+- Support for list types [#8](https://github.com/tanakh/optparse-declarative/pull/8)
+
 # 0.3.1
 
 - Allow False as a default value for Bool arguments [#2](https://github.com/tanakh/optparse-declarative/pull/2)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![Hackage](https://matrix.hackage.haskell.org/api/v2/packages/optparse-declarative/badge)](http://hackage.haskell.org/package/optparse-declarative) [![GitHub Actions: test](https://github.com/tanakh/optparse-declarative/workflows/test/badge.svg)](https://github.com/tanakh/optparse-declarative/actions?query=workflow%3Atest) [![Join the chat at https://gitter.im/optparse-declarative/community](https://badges.gitter.im/optparse-declarative/community.svg)](https://gitter.im/optparse-declarative/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
-`optparse-declarative` is a declarative and easy to use command-line option parser.
+`optparse-declarative` is a declarative and easy-to-use command-line option parser.
 
 # Install
 
@@ -14,15 +14,17 @@
 
 ## Writing a simple command
 
-First, you need to enable `DataKinds` extension and import `Options.Declarative` module.
+First, you need to enable `DataKinds` extension. Then import `Options.Declarative` module.
 
 ```hs
 {-# LANGUAGE DataKinds #-}
 import           Options.Declarative
 ```
 
-Then, define the command line option as a **type of the function**.
-For example, this is a simple greeting program:
+Next, define command line options as a **type of the function**.
+For example, this is a simple greeting program with `-g` option that
+takes a message of type `String` and an unnamed command-line argument
+that specifies a name:
 
 ```hs
 greet :: Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)
@@ -32,26 +34,47 @@
     liftIO $ putStrLn $ get msg ++ ", " ++ get name ++ "!"
 ```
 
-There are two type of options, `Flag` and `Arg`.
-`Flag` is named argument and `Arg` is unnamed argument.
-Last argument of both options is value type.
-If you need to specify default value, use the modifiers such as `Def`.
+There are two types of options, `Flag` and `Arg`.
+`Flag` represents a named argument (e.g., `--greet "Hola"`), and `Arg` an unnamed argument (e.g., `John` of `greet --greet Hola John`).
+The last argument of `Flag` and `Arg` is the type of the value of the
+argument; in this example, they are both `String`.
+You can specify any type for the value as long as the type is an
+instance of `ArgRead` typeclass, in which the conversion function
+from `String` to the specified type is defined.
+`Options.Declarative` provides following instances of `ArgRead`
+typeclass.
 
-In above, variable `msg` has a very complex type (`Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)`).
-In order to get the value of usual type (in this case, that is `String`),
+- Int
+- Integer
+- Bool
+- Double
+- String
+- (ArgRead a) => Maybe a
+
+Users can add a new instance of `ArgRead` to support any user-defined type.
+Please see Section "How to add a new instance of `ArgRead`" for details.
+
+If you wish to specify a default value for allowing users to omit a
+value, use the modifier `Def` with the default value as the second type argument (and the third type argument is the type of the value).
+You need to specify the default value in `String` instead of the final
+value of the target type; the string will be converted to the final
+value via `ArgRead` typeclass.
+
+In the example above, the variable `msg` has a very complex type (`Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)`).
+In order to get the value of the target type (in this case, that is `String`),
 you can use `get` function.
 
 The whole type of command is `Cmd`.
 `Cmd` is an instance of `MonadIO` and it has some extra information.
 
-After defining a command, you just invoke it by `run_`.
+Finally, you can run the whole program by `run_`.
 
 ```hs
 main :: IO ()
 main = run_ greet
 ```
 
-You can execute this program like this:
+Here is an example session with the program shown above.
 
 ```bash
 $ ghc simple.hs
@@ -73,14 +96,44 @@
 Goodbye, World!
 ```
 
-## Writing multiple sub-commands
+Note that only the final option is used when multiple options of the
+same name are given. This behavior emulates the behavior of a naive
+program that uses GNU Getopt.
 
-You can write (nested) sub-commands.
+```bash
+$ ./simple --greet=Hello --greet=Goodbye World
+Goodbye, World!
+```
 
-Just groupe subcommands by `Group`, you got sub-command parser.
+There is another way of interpreting multiple options of the same name.
+Suppose if you need to get multiple values from the same option.
+Say, you wish to get `["Hello", "Goodbye"]` from the command-line
+option `--greet=Hello --greeet=Goodbye`. Then, you can use
+the type `[]` to indicate that it accepts multiple values.
+The first line of the function `greet` in the example above
+would be changed as this:
 
-This is the example:
+```hs
+greet :: Flag "g" '["greet"] "STRING" "greeting message" [String]
+```
 
+The value returned by `get` will be a value of type `[String]`.
+See the complete working example at `example/list.hs` for details.
+
+
+## Writing multiple subcommands
+
+You can write (nested) subcommands.
+You don't know what subcommands are? Imagine `git` command.
+`git` has subcommands such as `git add`, `git commit`, `git log`, etc.
+`git` has nested subcommands such as `git remote add`, `git remote rm`,
+etc.
+`optparse-declarative` provides an easy way to provide such possibly
+nested subcommands.
+
+Just group subcommands by `Group`, then you get a subcommand parser.
+Here is an example with two subcommands `greet` and `connect`:
+
 ```hs
 {-# LANGUAGE DataKinds #-}
 
@@ -110,7 +163,7 @@
     liftIO $ putStrLn $ "connect to " ++ addr
 ```
 
-And this is the output:
+This is a sample session for the program above:
 
 ```bash
 $ ./subcmd --help
@@ -126,4 +179,78 @@
 connect to localhost:1234
 ```
 
+If you wish to specify the program name or the version number,
+use `run` instead of `run_`. The first argument of `run` is
+a program name (of type `String`). The second argument is
+a version number (of type `Maybe String`).
+
+```hs
+main :: IO ()
+main = run "program_name" (Just "1.3.2") $
+    Group "Test program for library"
+    [ subCmd "greet"   greet
+    , subCmd "connect" connect
+    ]
+```
+
 For more examples, please see `example` directory.
+
+
+## Default options
+`optparse-declarative` provides a few default options.
+For example, `--help` is defined automatically so users do not have to
+write it by their own. If run with `run` and the version number,
+`--version` is defined automatically. Also, `--verbosity` option (`-v`
+for short) is defined by default.
+`getVerbosity` returns the verbosity level in `Int`.
+`-v` gives 1, `-vv` gives 2, `-vvv` gives 3.
+Alternatively, `--verbose=3` would yield 3.
+
+
+## How to add a new instance of `ArgRead`
+Users need to create an instance of `ArgRead` for supporting a new type
+for the command line argument. Here is the definition of class
+`ArgRead`.
+
+```hs
+class ArgRead a where
+    -- | Type of the argument
+    type Unwrap a :: *
+    type Unwrap a = a
+
+    -- | Get the argument's value
+    unwrap :: a -> Unwrap a
+    default unwrap :: a ~ Unwrap a => a -> Unwrap a
+    unwrap = id
+
+    -- | Argument parser
+    argRead :: [String] -> Maybe a
+    default argRead :: Read a => [String] -> Maybe a
+    argRead ss = getLast $ mconcat $ Last . readMaybe <$> ss
+
+    -- | Indicate this argument is mandatory
+    needArg :: Proxy a -> Bool
+    needArg _ = True
+```
+
+Suppose you are adding a support for your type `T`.
+We explain which function to define explicitly, depending on the
+property of `T`.
+
+If `T` is the type of the final value you take out of a command line,
+you do not have to define `Unwrap`. If `T` is a wrapper like `Def`,
+define `type Unwrap T = <unwrapped type>`. For `Def x y`,
+`type Unwrap (Def x y) = y`. If you defined `Unwrap`, define `unwrap`
+that takes an actual value out of the wrapped value.
+
+`argRead` is the main function that converts String into a value.
+If the type is an instance of `Read` and you are satisfied with
+how `read` converts a `String` into value, there is no need to
+define your own `argRead`. Otherwise, you define a function that
+converts a `String` into a value of the target type. When parsing
+is successful, return `Just`. When it fails, return `Nothing`.
+If the input is `[]`, it indicates the option does not have an
+argument; otherwise the input is a list of a single `String`.
+Last but not least, define `needArg _ = False` when the option
+allows us to omit the associated value; consider a boolean
+option like `--help`.
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/example/bool.hs b/example/bool.hs
new file mode 100644
--- /dev/null
+++ b/example/bool.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE DataKinds #-}
+
+import           Control.Monad.Trans
+import           Options.Declarative
+
+main' :: Flag "b" '["bool"] "STRING" "boolean flag" Bool
+      -> Cmd "Simple greeting example" ()
+main' b =
+    liftIO $ putStrLn $ if get b then "Flag is True" else "Flag is False"
+
+main :: IO ()
+main = run_ main'
diff --git a/example/list.hs b/example/list.hs
new file mode 100644
--- /dev/null
+++ b/example/list.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE DataKinds #-}
+
+import           Control.Monad
+import           Control.Monad.Trans
+import           Options.Declarative
+
+greet :: Flag "n" '["name"] "STRING" "name" [String]
+      -> Cmd "Count the number of people" ()
+greet name =
+    let people_name_list = get name
+        num_people = length people_name_list
+    in liftIO $ do
+        putStrLn $ "There are " ++ show num_people ++ " people on the list."
+        putStrLn " -- "
+        forM_ people_name_list putStrLn
+
+main :: IO ()
+main = run_ greet
diff --git a/optparse-declarative.cabal b/optparse-declarative.cabal
--- a/optparse-declarative.cabal
+++ b/optparse-declarative.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                optparse-declarative
-version:             0.3.1
+version:             0.4.0
 synopsis:            Declarative command line option parser
 description:         Declarative and easy to use command line option parser
 homepage:            https://github.com/tanakh/optparse-declarative
diff --git a/src/Options/Declarative.hs b/src/Options/Declarative.hs
--- a/src/Options/Declarative.hs
+++ b/src/Options/Declarative.hs
@@ -29,7 +29,7 @@
     Flag,
     Arg,
 
-    -- * Defining argment types
+    -- * Defining argument types
     ArgRead(..),
     Def,
 
@@ -41,12 +41,11 @@
     run, run_,
     ) where
 
-import           Control.Applicative
 import           Control.Monad
 import           Control.Monad.Reader
-import           Control.Monad.Trans
 import           Data.List
 import           Data.Maybe
+import           Data.Monoid
 import           Data.Proxy
 import           GHC.TypeLits
 import           System.Console.GetOpt
@@ -93,9 +92,9 @@
     unwrap = id
 
     -- | Argument parser
-    argRead :: Maybe String -> Maybe a
-    default argRead :: Read a => Maybe String -> Maybe a
-    argRead s = readMaybe =<< s
+    argRead :: [String] -> Maybe a
+    default argRead :: Read a => [String] -> Maybe a
+    argRead ss = getLast $ mconcat $ Last . readMaybe <$> ss
 
     -- | Indicate this argument is mandatory
     needArg :: Proxy a -> Bool
@@ -107,22 +106,28 @@
 
 instance ArgRead Double
 
-instance ArgRead String where
-    argRead = id
+instance {-# OVERLAPPING #-} ArgRead String where
+    argRead [] = Nothing
+    argRead xs = Just $ last xs
 
 instance ArgRead Bool where
-    argRead Nothing = Just False
-    argRead (Just "f") = Just False
-    argRead (Just "t") = Just True
-    argRead _ = Nothing
+    argRead []    = Just False
+    argRead ["f"] = Just False
+    argRead ["t"] = Just True
+    argRead _     = Nothing
 
     needArg _ = False
 
 instance ArgRead a => ArgRead (Maybe a) where
-    argRead Nothing = Just Nothing
-    argRead (Just a) = Just <$> argRead (Just a)
+    argRead [] = Just Nothing
+    argRead xs = Just <$> argRead xs
 
--- | The argument which has defalut value
+instance {-# OVERLAPPABLE #-} ArgRead a => ArgRead [a] where
+    argRead xs = case mapMaybe (argRead . (:[])) xs of
+                 [] -> Nothing
+                 xs -> Just xs
+
+-- | The argument which has default value
 newtype Def (defaultValue :: Symbol) a =
     Def { getDef :: a }
 
@@ -131,12 +136,14 @@
     unwrap = unwrap . getDef
 
     argRead s =
-        let s' = fromMaybe (symbolVal (Proxy :: Proxy defaultValue)) s
-        in Def <$> argRead (Just s')
+        let s' = case s of
+                 [] -> [symbolVal (Proxy :: Proxy defaultValue)]
+                 v  -> v
+        in Def <$> argRead s'
 
 -- | Command
 newtype Cmd (help :: Symbol) a =
-    Cmd { unCmd :: ReaderT Int IO a }
+    Cmd (ReaderT Int IO a)
     deriving (Functor, Applicative, Monad, MonadIO)
 
 -- | Output string when the verbosity level is greater than or equal to `logLevel`
@@ -210,7 +217,7 @@
          , IsCmd c )
          => IsCmd (Flag shortNames longNames placeholder help a -> c) where
     getOptDescr f =
-        let flagname = head $
+        let flagName = head $
                        symbolVals (Proxy :: Proxy longNames) ++
                        [ [c] | c <- symbolVal (Proxy :: Proxy shortNames) ]
         in Option
@@ -218,23 +225,23 @@
             (symbolVals (Proxy :: Proxy longNames))
             (if needArg (Proxy :: Proxy a)
              then ReqArg
-                  (flagname, )
+                  (flagName, )
                   (symbolVal (Proxy :: Proxy placeholder))
              else NoArg
-                  (flagname, "t"))
+                  (flagName, "t"))
             (symbolVal (Proxy :: Proxy help))
         : getOptDescr (f undefined)
 
     runCmd f name mbver options nonOptions unrecognized =
-        let flagname = head $
+        let flagName = head $
                        symbolVals (Proxy :: Proxy longNames) ++
                        [ [c] | c <- symbolVal (Proxy :: Proxy shortNames) ]
-            mbs = lookup flagname options
+            mbs = map snd $ filter ((== flagName) . fst) options
         in case (argRead mbs, mbs) of
-            (Nothing, Nothing) ->
-                errorExit name $ "flag must be specified: --" ++ flagname
-            (Nothing, Just s) ->
-                errorExit name $ "bad argument: --" ++ flagname ++ "=" ++ s
+            (Nothing, []) ->
+                errorExit name $ "flag must be specified: --" ++ flagName
+            (Nothing, s:_) ->
+                errorExit name $ "bad argument: --" ++ flagName ++ "=" ++ s
             (Just arg, _) ->
                 runCmd (f $ Flag arg) name mbver options nonOptions unrecognized
 
@@ -261,7 +268,7 @@
     case nonOptions of
         [] -> errorExit name "not enough arguments"
         (opt: rest) ->
-            case argRead (Just opt) of
+            case argRead [opt] of
                 Nothing ->
                     errorExit name $ "bad argument: " ++ opt
                 Just arg ->
@@ -274,7 +281,7 @@
         " " ++ symbolVal (Proxy :: Proxy placeholder) ++ getUsageHeader (f undefined) prog
 
     runCmd f name mbver options nonOptions unrecognized =
-        case traverse argRead $ Just <$> nonOptions of
+        case traverse argRead $ (:[]) <$> nonOptions of
             Nothing ->
                 errorExit name $ "bad arguments: " ++ unwords nonOptions
             Just opts ->
@@ -342,7 +349,7 @@
             ++ [ Option "v" ["verbose"] (OptArg (\arg -> ("verbose", fromMaybe "" arg)) "n") "set verbosity level" ]
 
         prog     = unwords name
-        vermsg   = prog ++ maybe "" (" version " ++) mbver
+        verMsg   = prog ++ maybe "" (" version " ++) mbver
         header = "Usage: " ++ prog ++ " [OPTION...]" ++ getUsageHeader cmd prog ++ "\n" ++
                  "  " ++ getCmdHelp cmd ++ "\n\n" ++
                  "Options:"
@@ -359,7 +366,7 @@
                   putStr usage
                   exitSuccess
             | isJust (lookup "version" options) -> do
-                  putStrLn vermsg
+                  putStrLn verMsg
                   exitSuccess
             | otherwise ->
                   runCmd cmd name mbver options nonOptions unrecognized
