Zarutian tormented kbk the other day (late Desember 2007 or early January 2008) with this:
package Tcl 8.5
variable storage {}
proc restore {caller vars} {
if {![dict exists $::storage $caller]} { return }
foreach var $vars {
uplevel 1 [list set $var [dict get $::storage $caller $var]]
}
}
proc save {caller vars} {
foreach var $vars {
dict set ::storage $caller $var [uplevel 1 [list set $var]]
}
}
proc persist {args} {
set vars $args; unset args
if {[uplevel 1 [list info exists __[info level 0]]]} { return }
uplevel 1 [list set __[info level 0] exists]
set caller [lindex [info level 1] 0]
uplevel 1 [list restore $caller $vars]
catch [list uplevel 1 [info body $caller]] result options
uplevel 1 [list save $caller $vars]
dict incr options -level +2
return -options $options $result
}
proc prufa {args} {
persist si
incr si 42
puts "si = $si"
}another well known procedure decorator is memoize, but that only works for referentially transparent functions (i.e. side-effect free procedures).
DKF: So what does this code do? It's not at all clear from just reading the code...
RS: Could it have to do with static variables? But I don't understand the code either...
Zarutian: indeed the above example of an decorator is for persisting static variables.
Zarutian adds an memoize decorator:
# not tested yet
package require Tcl 8.5
variable memoize_storage {}
proc memoize {} {
if {[uplevel 1 [liss info exists __[info level 0]]} { return }
uplevel 1 [list set __[info level 0] exists]
variable memoize_storage
set invocation [info level 1]
if {[dict exists $memoize_storage $invocation]]} {
set result [dict get $memoize_storage $invocation result]
set options [dict get $memoize_storage $invocation return_options]
} else {
set caller [lindex $invocation 0]
catch [list uplevel 1 [info body $caller]] result options
dict set memoize_storage $invocation result $result
dict set memoize_storage $invocation return_options $options
}
dict incr options -level +2
return -options $options $result
}kruzalex Example above adapted on Tcl 8.4 with some modifications:
#tested
package require dict
variable memoize_storage {}
proc memoize {args} {
set vars $args; unset args
foreach var $vars break
if {[uplevel 1 [list info exists __[info level 0]]]} {return }
uplevel 1 [list set __[info level 0] exists]
variable memoize_storage
set invocation [info level 1]
set caller [lindex $invocation 0]
set procname [lindex [info level -1] 0]
if {[dict exists $memoize_storage $caller]} {
set result [uplevel 1 [list set $var [dict get $memoize_storage $caller $var]]]
catch [list uplevel 1 [info body $caller]] result
dict set memoize_storage $caller $var [uplevel 1 [list set $var]]
} else {
catch [list uplevel 1 [info body $caller]] result
dict set memoize_storage $caller $var [uplevel 1 [list set $var]]
}
return -code return $result
}
proc prufa {{si 0}} {
memoize si
incr si 42
puts "si = $si"
}prufa prufa prufa
kruzalex For Tcl 8.4 lovers example mentioned on the top should work in this way
package require dict
variable storage {}
proc restore {caller vars} {
if {![dict exists $::storage $caller]} { return }
foreach var $vars {
uplevel 1 [list set $var [dict get $::storage $caller $var]]
}
}
proc save {caller vars} {
foreach var $vars {
dict set ::storage $caller $var [uplevel 1 [list set $var]]
}
}
proc persist {args} {
set vars $args; unset args
if {[uplevel 1 [list info exists __[info level 0]]]} { return }
uplevel 1 [list set __[info level 0] exists]
set caller [lindex [info level 1] 0]
uplevel 1 [list restore $caller $vars]
catch [list uplevel 1 [info body $caller]] result
uplevel 1 [list save $caller $vars]
dict incr -level +2
return -code return $result
}
proc prufa {{si 0}} {
persist si
incr si 42
puts "si = $si"
}
prufa
prufa
prufa| enter categories here |
|---|