diff options
| -rwxr-xr-x | tcl.html.markdown | 159 | 
1 files changed, 100 insertions, 59 deletions
| diff --git a/tcl.html.markdown b/tcl.html.markdown index ddf53fe9..5402ce04 100755 --- a/tcl.html.markdown +++ b/tcl.html.markdown @@ -49,8 +49,10 @@ programming in the best way.  Even Lisp is more syntactically heavy than Tcl.  # Every line is a command.  The first word is the name of the command, and
  # subsequent words are arguments to the command. Words are delimited by
 -# whitespace.  Since every word is a string, no escaping is necessary in the
 -# simple case.
 +# whitespace.  Since every word is a string, in the simple case no special
 +# markup such as quotes, braces, or backslash, is necessary.  Even when quotes
 +# are used, they are not a string constructor, but just another escaping
 +# character.
  set greeting1 Sal 
  set greeting2 ut
 @@ -58,27 +60,34 @@ set greeting3 ations  #semicolon also delimits commands
 -
  set greeting1 Sal; set greeting2 ut; set greeting3 ations 
  # Dollar sign introduces variable substitution
 +set greeting $greeting1$greeting2$greeting3
 -set greeting $greeting1$greeting2
 +# Bracket introduces command substitution.  The result of the command is
 +# substituted in place of the bracketed script.  When the "set" command is
 +# given only the name of a variable, it returns the value of that variable.
 +set greeting $greeting1$greeting2[set greeting3]
 -# Bracket introduces command substitution
 -set greeting $greeting[set greeting3]
 +# Command substitution should really be called script substitution, because an
 +# entire script, not just a command, can be placed between the brackets. The
 +# "incr" command increments the value of a variable and returns its value.
 +set greeting $greeting[
 +	incr i
 +	incr i
 +	incr i
 +]
  # backslash suppresses the special meaning of characters
 -
  set amount \$16.42
  # backslash adds special meaning to certain characters
 -
  puts lots\nof\n\n\n\n\n\nnewlines
 @@ -89,55 +98,48 @@ set somevar {      brace remains uninterpreted
  } 
 +
  # In a word enclosed in double quotes, whitespace characters lose their special
  # meaning 
 -
  set name Neo
  set greeting "Hello, $name"
  #variable names can be any string
 -
  set {first name} New
  # The brace form of variable substitution handles more complex variable names
 -
  set greeting "Hello, ${first name}"
  # The "set" command can always be used instead of variable substitution
 -
  set greeting "Hello, [set {first name}]"
  # To promote the words within a word to individual words of the current
  # command, use the expansion operator, "{*}".
 -
  set {*}{name Neo}
  # is equivalent to
 -
  set name Neo
  # An array is a special variable that is a container for other variables.
 -
  set person(name) Neo
  set person(gender) male
 -
  set greeting "Hello, $person(name)"
 -# A namespace holds commands and variables
 +# A namespace holds commands and variables
  namespace eval people {
      namespace eval person1 {
          set name Neo
      }
  }
 -#The full name of a variable includes its enclosing namespace(s), delimited by two colons:
 +#The full name of a variable includes its enclosing namespace(s), delimited by two colons:
  set greeting "Hello $people::person::name"
 @@ -146,20 +148,19 @@ set greeting "Hello $people::person::name"  ## 3. A Few Notes 
  ################################################################################
 -# From this point on, there is no new syntax.  Everything else there is to
 -# learn about Tcl is about the behaviour of individual commands, and what
 -# meaning they assign to their arguments.
 +# All other functionality is implemented via commands.  From this point on,
 +# there is no new syntax.  Everything else there is to learn about Tcl is about
 +# the behaviour of individual commands, and what meaning they assign to their
 +# arguments.
 -# All other functionality is implemented via commands.  To end up with an
 -# interpreter that can do nothing, delete the global namespace.  It's not very
 -# useful to do such a thing, but it illustrates the nature of Tcl.
 -
 +# To end up with an interpreter that can do nothing, delete the global
 +# namespace.  It's not very useful to do such a thing, but it illustrates the
 +# nature of Tcl.
  namespace delete ::
  # Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace.
 -
  namespace eval people {
      namespace eval person1 {
          variable name Neo
 @@ -168,7 +169,6 @@ namespace eval people {  # The full name of a variable can always be used, if desired.
 -
  set people::person1::name Neo
 @@ -178,7 +178,6 @@ set people::person1::name Neo  ################################################################################
  # Math can be done with the "expr" command.
 -
  set a 3
  set b 4
  set c [expr {$a + $b}]
 @@ -189,56 +188,52 @@ set c [expr {$a + $b}]  # The "expr" command understands variable and command substitution
 -
  set c [expr {$a + [set b]}]
  # The "expr" command provides a set of mathematical functions
 -
  set c [expr {pow($a,$b)}]
  # Mathematical operators are available as commands in the ::tcl::mathop
  # namespace
 -
  ::tcl::mathop::+ 5 3
  # Commands can be imported from other namespaces
 -
  namespace import ::tcl::mathop::+
  set result [+ 5 3]
  # New commands can be created via the "proc" command.
 -
  proc greet name {
      return "Hello, $name!"
  }
 +#multiple parameters can be specified
 +proc greet {greeting name} {
 +    return "$greeting, $name!"
 +}
 +
  # As noted earlier, braces do not construct a code block.  Every value, even
  # the third argument of the "proc" command, is a string.  The previous command
 -# could be defined without using braces at all:
 +# rewritten to not use braces at all:
 +proc greet greeting\ name return\ \"Hello,\ \$name!
 -proc greet name return\ \"Hello,\ \$name!
  # When the last parameter is the literal value, "args", it collects all extra
  # arguments when the command is invoked
 -
  proc fold {cmd args} {
      set res 0
      foreach arg $args {
          set res [cmd $res $arg]
      }
  }
 -
  fold ::tcl::mathop::* 5 3 3 ;# ->  45
 -
  # Conditional execution is implemented as a command
 -
  if {3 > 4} {
      puts {This will never happen}
  } elseif {4 > 4} {
 @@ -250,7 +245,6 @@ if {3 > 4} {  # Loops are implemented as commands.  The first, second, and third
  # arguments of the "for" command are treated as mathematical expressions
 -
  for {set i 0} {$i < 10} {incr i} {
      set res [expr {$res + $i}]
  }
 @@ -258,7 +252,6 @@ for {set i 0} {$i < 10} {incr i} {  # The first argument of the "while" command is also treated as a mathematical
  # expression
 -
  set i 0
  while {$i < 10} {
      incr i 2
 @@ -266,14 +259,14 @@ while {$i < 10} {  # A list is a specially-formatted string.  In the simple case, whitespace is sufficient to delimit values
 -
  set amounts 10\ 33\ 18 
  set amount [lindex $amounts 1]
 -# Braces and backslash can be used to format more complex values in a list.
 -# There are three items in the following 
 -
 +# Braces and backslash can be used to format more complex values in a list.  A
 +# list looks exactly like a script, except that the newline character and the
 +# semicolon character lose their special meanings.  This feature makes Tcl
 +# homoiconic.  There are three items in the following list.
  set values {
      one\ two
 @@ -286,8 +279,7 @@ set values {  # Since a list is a string, string operations could be performed on it, at the
 -# risk of corrupting the list.
 -
 +# risk of corrupting the formatting of the list.
  set values {one two three four}
  set values [string map {two \{} $values] ;# $values is no-longer a \
      properly-formatted listwell-formed list
 @@ -295,12 +287,10 @@ set values [string map {two \{} $values] ;# $values is no-longer a \  # The sure-fire way to get a properly-formmated list is to use "list" commands
  set values [list one \{ three four]
 -
  lappend values { } ;# add a single space as an item in the list
  # Use "eval" to evaluate a value as a script
 -
  eval {
      set name Neo
      set greeting "Hello, $name"
 @@ -309,20 +299,17 @@ eval {  # A list can always be passed to "eval" as a script composed of a single
  # command.
 -
  eval {set name Neo}
  eval [list set greeting "Hello, $name"]
  # Therefore, when using "eval", use [list] to build up a desired command 
 -
  set command {set name}
  lappend command {Archibald Sorbisol}
  eval $command
 -# A common mistake is not to use list functions
 -
 +# A common mistake is not to use list functions when building up a command
  set command {set name}
  append command { Archibald Sorbisol}
  eval $command ;# There is an error here, because there are too many arguments \
 @@ -330,7 +317,6 @@ eval $command ;# There is an error here, because there are too many arguments \  # This mistake can easily occur with the "subst" command.
 -
  set replacement {Archibald Sorbisol}
  set command {set name $replacement}
  set command [subst $command] 
 @@ -340,7 +326,6 @@ eval $command ;# The same error as before:  to many arguments to "set" in \  # The proper way is to format the substituted value using use the "list"
  # command.
 -
  set replacement [list {Archibald Sorbisol}]
  set command {set name $replacement}
  set command [subst $command] 
 @@ -348,24 +333,80 @@ eval $command  # It is extremely common to see the "list" command being used to properly
 -# format values that are substituted into Tcl script templates.  There is an
 -# example of this in the following replacement "while" implementation.
 +# format values that are substituted into Tcl script templates.  There are 
 +# several examples of this, below.
 -#get rid of the built-in "while" command.
 +# The "apply" command evaluates a string as a command.
 +set cmd {{greeting name} {
 +    return "$greeting, $name!"
 +}}
 +apply $cmd Whaddup Neo
 +
 +
 +# The "uplevel" command evaluates a script in some enclosing scope.
 +proc greet {} {
 +	uplevel {puts "$greeting, $name"}
 +}
 +
 +proc set_double {varname value} {
 +	if {[string is double $value]} {
 +		uplevel [list variable $varname $value]
 +	} else {
 +		error [list {not a double} $value]
 +	}
 +}
 +
 +# The "upvar" command links a variable in the current scope to a variable in
 +# some enclosing scope
 +proc set_double {varname value} {
 +	if {[string is double $value]} {
 +		upvar 1 $varname var
 +		set var $value
 +	} else {
 +		error [list {not a double} $value]
 +	}
 +}
 +
 +
 +#get rid of the built-in "while" command.
  rename ::while {}
  # Define a new while command with the "proc" command.  More sophisticated error
  # handling is left as an exercise.
 -
  proc while {condition script} {
      if {[uplevel 1 [list expr $condition]]} {
          uplevel 1 $script
          tailcall [namespace which while] $condition $script
      }
  }
 +
 +
 +# The "coroutine" command creates a separate call stack, along with a command
 +# to enter that call stack. The "yield" command suspends execution in that
 +# stack. 
 +proc countdown {} {
 +	#send something back to the initial "coroutine" command
 +	yield
 +
 +	set count 3 
 +	while {$count > 1} {
 +		yield [incr count -1]
 +	}
 +	return 0
 +}
 +coroutine countdown1 countdown
 +coroutine countdown2 countdown
 +puts [countdown 1] ;# -> 2 
 +puts [countdown 2] ;# -> 2 
 +puts [countdown 1] ;# -> 1 
 +puts [countdown 1] ;# -> 0 
 +puts [coundown 1] ;# -> invalid command name "countdown1"
 +puts [countdown 2] ;# -> 1 
 +
 +
  ```
  ## Reference
 | 
