Tcl has a notion of lists, but as with everything it is implemented through strings. A list is a string that contains words.
A simple list is just a space separated series of strings:
     set a {one two three four five}
     
will set the variable a to the list containing the five
strings shown. The empty list is denoted by an open and close curly bracket
pair with nothing in between: {}.
   
For the Prolog programmer, there is much confusion between a Prolog implementation of lists and the Tcl implementation of lists. In Prolog we have a definite notion of the printed representation of a list: a list is a sequence of terms enclosed in square brackets (we ignore dot notation for now); a nested list is just another term.
In Tcl, however, a list is really just a string that conforms to a certain syntax: a string of space separated words. But in Tcl there is more than one way of generating such a string. For example,
     set fred {a b c d}
     
sets fred to
     "a b c d"
     
as does
     set fred "a b c d"
     
because {a b c d} evaluates to the string a b c d, which
has the correct syntax for a list.  But what about nested lists? 
Those are represented in the final list-string as being contained in
curly brackets.  For example:
     set fred {a b c {1 2 3} e f}
     
results in fred having the value
     "a b c {1 2 3} e f"
     
   The outer curly brackets from the set command have disappeared,
which causes confusion. The curly brackets within a list denote a nested
list, but there are no curly brackets at the top-level of the list.  (We
can't help thinking that life would have been easier if the creators of
Tcl would have chosen a consistent representation for lists, as Prolog
and LISP do.)
   
So remember: a list is really a string with a certain syntax, space separated items or words; a nested list is surrounded by curly brackets.
There are a dozen commands that operate on lists.
     concat ?list list ...?
     
   This makes a list out of a series of lists by concatenating its argument lists together. The return result is the list resulting from the concatenation.
     lindex list index
     
returns the index-th element of the list. The first element of a list has an index of 0.
     linsert list index value ?value ...?
     
returns a new list in which the value arguments have been inserted in turn before the index-th element of list.
     list ?value value ...?
     
returns a list where each element is one of the value arguments.
     llength list
     
returns the number of elements in list list.
     lrange list first last
     
returns a slice of a list consisting of the elements of the list list from index first until index last.
     lreplace list first last ?value ... value?
     
returns a copy of list list but with the elements between indices first and last replaced with a list formed from the value arguments.
     lsearch ?-exact? ?-glob? ?-regexp? list pattern
     
returns the index of the first element in the list that matches the
given pattern. The type of matching done depends on which of the switch
is present -exact, -glob, -regexp, is
present. Default is -glob.
     lsort ?-ascii? ?-integer? ?-real? ?-command command? ?-increasing? ?-decreasing{? list
     
returns a list, which is the original list list sorted by the chosen
technique. If none of the switches supplies the intended sorting technique
then the user can provide one through the -command command switch.
   
There are also two useful commands for converting between lists and strings:
     join list ?joinString?
     
which concatenates the elements of the list together, with the separator joinString between them, and returns the resulting string. This can be used to construct filenames; for example:
     set a {{} usr local bin}
     set filename [join $a /]
     
results in the variable filename having the value /usr/local/bin.
   
The reverse of the join command is the split command:
     split string ?splitChars?
     
which takes the string string and splits it into string on splitChars boundaries and returns a list with the strings as elements. An example is splitting a filename into its constituent parts:
     set a [split /usr/local/src /]
     
gives a the value {{} usr local src}, a list.