[Arjen Markus] Reading the book "Concepts of programming languages" by Robert Sebesta, I stumbled on two special control constructs designed by Edsger Dijkstra, the guarded if-statement and the guarded do-loop. The motivation is simple: provide if-statements and do-loops that can be thoroughly analysed. I lack the time right now to describe their properties in detail, but here is a script that implements them and illustrates their use (up to a point :). Guarded if-statements: * Together the branches must be logically complete, that is, under all circumstances at least one branch condition must hold. * If more than one condition holds, one of these branches is chosen, indeterminately (in the implementation: randomly) Guarded do-loops: * Very s imilar to if-statements, but the loop is repeated until all conditions fail I can recommend the book, but I regret it only mention Tcl in the introduction :( ---- # dijkstra.tcl -- # Experiment with Dijkstra's guarded constructs # (Is it easy t o implement them? Yes, remarkably easy) # # I took the description from R. Sebesta's # Concepts of Programming Languages (fifth edition). # This book showed the syntax of the two constructions as: # # if cond1 --> statement1 # [] c on d2 --> statement2 # ... # fi # # do cond1 --> statement1 # [] cond2 --> statement2 # ... # od # # and I gave this a small Tclish twist # namespace eval ::Guarded { # Simply create the namespace } # d-if -- # G uar ded if-construct # Arguments: # cond_actions List of conditions and actions # Result: # None # Side effects: # Whatever the actions involve or an error if the conditions # turn out to be incomplete # proc ::Guarded::d-if { cond_actions } { # # Create a list of those actions that can trigger # set triggerable_actions {} foreach {cond action} $cond_actions { if { [uplevel expr [list $cond]] } { lappend triggerable_actions $action } } # # Do we have any? Then randomly select one # Otherwise, issue an error! # set number [llength $triggerable_actions] if { $number > 0 } { set selected [expr {int($number*rand())}] uplevel [lindex $triggerable_actio ns $selected] } else { error "Conditions logically incomplete" } } # d-do -- # Guarded do-loop # Arguments: # cond_actions List of conditions and actions # Result: # None # Side effects: # Whatever the actions invol ve (The do-loop stops when # no conditions are true) # proc ::Guarded::d-do { cond_actions } { while { 1 } { # # Create a list of those actions that can trigger # set triggerable_actions {} foreach {cond action} $cond _actions { if { [uplevel expr [list $cond]] } { lappend triggerable_actions $action } } # # Do we have any? Then randomly select one # Otherwise, break out of the while loop # set number [llength $triggerable_actions] if { $number > 0 } { set selected [expr {int($number*rand())}] uplevel [lindex $triggerable_actions $selected] } else { break } } } # main -- # Som e test code and demonstration # # # Maximum of x and y # foreach {x y} {1.0 2.0 3.0 3.0 5.0 4.0 6.0 6.0} { ::Guarded::d-if { {$x <= $y} {puts "y = maximum"; set max $y} {$x >= $y} {puts "x = maximum"; set max $x} } puts "max = $max" } # # Do-loop: two separate ranges with overlap # set x 0 set y 0 ::Guarded::d-do { {$x < 4} {puts "Range X (x,y = $x,$y)"; incr x} {$y < 5} {puts "Range Y (x,y = $x,$y)"; incr y} } # # Overlapping ranges with gap. Note: last illustrates # incompleteness. (This must be last) # foreach {x y} {1.0 2.0 3.0 7.0 5.0 6.0 7.0 8.0} { puts "x, y: $x, $y" ::Guarded::d-if { {$x < 4.0 && $y > 5.0} {puts "Range 1"} {$x > 4.0 && $y < 7.0} {puts "Range 2"} {$y < 4.5} {puts "Range 3"} } } ---- [Lars H]: "Nondeterministic" almost never means "random" in Computer Science (more commonly "I don't want to tell you how/why/what"), but then again, "random" doesn't always mean random either ''(Random Access Memory -- never knowing where the next bit is coming from).'' I couldn't resist making another implementation of the d-if, though. This one is quite non-random: proc ::Guarded::d-if {cond_actions} { set if ::if set call [list] foreach {cond action} $cond_actions { lappend call $if $cond then $action set if elseif } uplevel 1 [lappend call else {error "Conditions logically incomplete"}] } One might also wonder to what extent [switch] already is this d-if... \rant{A preference for numerical conditions in a language is often a way of coping with inferior string handling.} ---- [[ [Category Concept] | [Category Language] ]]�3