set mylist {this is a test for the lsplit Tcl command}
lsplit $mylist x {[string length $x] < 4} left right
puts $left
puts $rightMore information inside the comments.
# Split a list in two sub-lists of elements passing, or not passing
# a given test.
#
# The signature is the following:
#
# lsplit listValue variable expression ?firstListVar secondListVar?
#
# We call the sublist of elements passing the test left-list,
# and the sublist of elements not passing the test right-list.
#
# If lsplit is called with three arguments,
# it returns [list $left-list $right-list]
#
# If lsplit is called with additional two arguments (five in total),
# the last two arguments are used as variable names where
# to store the left-list, and the right-list, and the command
# returns [list [llength $left-list] [llength $right-list]].
#
# This function was inspired by the Joy programming language
# 'split' primitive.
#
# Copyright (C) 2004 Salvatore Sanfilippo
# All the Rights reserved.
#
################################################################################
#
# This software is copyrighted by Salvatore Sanfilippo.
# The following terms apply to all files associated with the software
# unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
#
# GOVERNMENT USE: If you are acquiring this software on behalf of the
# U.S. government, the Government shall have only "Restricted Rights"
# in the software and related documentation as defined in the Federal
# Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
# are acquiring the software on behalf of the Department of Defense, the
# software shall be classified as "Commercial Computer Software" and the
# Government shall have only "Restricted Rights" as defined in Clause
# 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
# authors grant the U.S. Government and others acting in its behalf
# permission to use and distribute the software in accordance with the
# terms specified in this license.
proc lsplit {list var expression args} {
switch -- [llength $args] {
2 {upvar [lindex $args 0] left [lindex $args 1] right}
0 {}
default {
error [format %s%s "Wrong number of arguments. Try lsplit " \
"var expr ?leftListVar rightListVar?"]
}
}
upvar $var x
set left {}
set right {}
foreach e $list {
# We take a copy of the element in 'e',
# because 'expresion' is evaluated in a context
# that may change the value of $x
set x $e
if {[uplevel expr [list $expression]]} {
lappend left $e
} else {
lappend right $e
}
}
if {![llength $args]} {
list $left $right
} else {
list [llength $left] [llength $right]
}
}RS has this version:
proc lsplit {list cond} {
set yes {}; set no {}
foreach el $list {if [$cond $el] {lappend yes $el} {lappend no $el}}
list $yes $no
}
proc even x {expr {$x%2 ==0}}
% lsplit {1 2 3 4} even
{2 4} {1 3}SS the RS's version is more functional, but the rationale for my lsplit semantic is that when there is already a defined tester function, like "even", you can still write:
% lsplit {1 2 3 4} x {[even $x]}That's a bit more complex, but still acceptable. On the other hand, often the test condition is simple, and the programmer don't want to define a procedure just for this. In such a case she can write:
% lsplit {1 2 3 4} x {$x&1}Without to have to deal with anonymous functions and lambda implementations.RS has, over a long time, come to think that anonymous functions (lambdas) are the real functions, and names are just an added sugar to that...

