Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorials:advanced:task_trees [2015/06/29 13:30] – Added info on the with-transformative-tryouts macro. mpomarlantutorials:advanced:task_trees [2020/09/17 14:09] (current) – [Plan transformations: task trees, code replacement, and serialization] gkazhoya
Line 1: Line 1:
 ====== Plan transformations: task trees, code replacement, and serialization ====== ====== Plan transformations: task trees, code replacement, and serialization ======
  
-**Description:** this tutorial is aimed at CRAM developers, and its purpose is to present an in-development aspect of CRAM; expect content to change. It contains an intro to task trees, a data structure used by CRAM functions (note: this has existed in CRAM for a while and will not change). It also describes code replacement (also long existing), failure handling through code replacement (new), and serialization of task trees and functions (new).+**Disclaimer:** the most up to date overview of plan transformations you can find in README.md of ''cram_plan_transformation'' package (''CRAM_REPO/cram_3d_world/cram_plan_transformation/README.md''). The tutorial below is out of date and has not be maintained, unfortunately, but you might still find some useful explanations there. Otherwise, stick to the README. 
 + 
 +**Description:** this tutorial is aimed at CRAM developers, and its purpose is to present an in-development aspect of CRAM. It is less a proper tutorial and more documentation for work in progress. Expect content to change. It contains an intro to task trees, a data structure used by CRAM functions (note: this has existed in CRAM for a while and will not change). It also describes code replacement (also long existing), failure handling through code replacement (new), and serialization of task trees and functions (new).
  
 ===== CRAM task trees ===== ===== CRAM task trees =====
Line 284: Line 286:
 <code lisp> <code lisp>
 (swank:operate-on-system-for-emacs "cram-projection" (quote load-op)) (swank:operate-on-system-for-emacs "cram-projection" (quote load-op))
-(cram-projection:define-projection-environment example-env) 
 (in-package :cpl-impl) (in-package :cpl-impl)
 +(cram-projection:define-projection-environment example-env)
  
 (def-top-level-cram-function tryprj ()  (def-top-level-cram-function tryprj () 
Line 330: Line 332:
     * any special variables acting as parameters for BODY can be changed in TRANSFORMATION-CLAUSE. In the example, we use cpl-impl:*in-projection-environment* as such a parameter.     * any special variables acting as parameters for BODY can be changed in TRANSFORMATION-CLAUSE. In the example, we use cpl-impl:*in-projection-environment* as such a parameter.
     * if plan transformations should be enabled for BODY, it must contain at least one CRAM-FUNCTION.     * if plan transformations should be enabled for BODY, it must contain at least one CRAM-FUNCTION.
-  * BODY, a list of S-expressions that should be run.+  * BODY, a list of S-expressions that should be run. The macro return value is the return value of BODY. 
 + 
 +Just like with-transformative-failure-handling, with-transformative-tryouts will store only the latest run of BODY in the task tree. 
 + 
 +===== Changing parameters with plan transformation ===== 
 + 
 +Remember one of the previous laws of the task tree:  
 + 
 +//When a task tree node is run, the value of PARAMETERS in either CODE or (car CODE-REPLACEMENTS) is set to the value of the parameters at the moment of the function call.// 
 + 
 +This means that, typically, you can't change parameters through plan transformation as previously implemented in CRAM. However, it's useful to distinguish two types of parameters for a cram-function: 
 + 
 +  * "run-time" parameters. These take their values from the actual runtime context that a cram-function is called in. This is the only behavior available in the main CRAM code branch. 
 +  * "compile-time" parameters. These are fixed when the code is generated, either at compile time //or after plan transformation//. You can think of them as parameters to tweak how a function runs, but they can also be adjusted to reflect the runtime context. Their main use is to allow plan transformation to affect them. 
 + 
 +To support "compile-time" parameters, a new construct was just added to cpl, def-ptr-cram-function, and its workings are explained below. Let's first load a sample code into a new repl window: 
 + 
 +<code lisp> 
 +(swank:operate-on-system-for-emacs "cram-language" (quote load-op)) 
 + 
 +(defparameter par-1 1) ;; just a couple variables to give some 'runtime' context for our cram functions to work in 
 +(defparameter par-2 1) 
 + 
 +(cpl-impl:def-ptr-cram-function example-ptr (P &rest args) 
 +  (format T "Inside example-ptr.~%"
 +  (format T "Received arguments ~a~%" args) 
 +  (format T "PTR parameter is (~a)~%Will now fail, so as to trigger plan transformation.~%" P) 
 +  (cpl:fail 'cpl-impl:plan-failure)) 
 + 
 +(defun compatible-ptr (P &rest args) 
 +  (format T "Inside compatible-ptr.~%"
 +  (format T "Received arguments ~a~%" args) 
 +  (format T "PTR parameter is (~a)~%Done!~%" P)) 
 +            
 +(cpl-impl:def-top-level-cram-function try-ptr () 
 +  (cpl-impl:with-transformative-failure-handling 
 +    ((cpl-impl:plan-failure (f) 
 +      (let ((code-path (cpl-impl::plan-failure/get-code-path f))) 
 +        (format t "Will replace code now (and switch the ptr-parameter) ...~%"
 +        (cpl-impl:replace-task-code '(compatible-ptr args) #'compatible-ptr code-path :ptr-parameter "Oranges"
 +        (cpl-impl:retry)))) 
 +    (setf par-1 (+ par-1 par-2)) 
 +    (setf par-2 (- par-1 par-2)) 
 +    (example-ptr "Apples" par-1 par-2 0))) 
 +</code> 
 + 
 +Of these, example-ptr is the "star" of the show. Notice that it's been defined with def-ptr-cram-function, and what that tells CRAM is that the first argument in the supplied lambda list (in this case, P) is supposed to be a "compile-time", or plan-transformation accessible, parameter. 
 + 
 +ptr-cram-functions are a bit peculiar. When you call them the first time they behave like regular cram functions, and take their parameters from the ones you supplied. When you call them again (meaning, when there's a node in the task tree corresponding to the plan location you're calling them from), they ignore the first parameter in the lambda list you supply them with and replace it with the ptr-parameter stored in the task tree node. ptr-cram-functions do all this automatically; you don't need to write anything different when using them. In the example above, the ptr-cram-function uses the P parameter as if it were a usual parameter. 
 + 
 +To actually change the compile time parameter in a node, notice the extra &key parameter in replace-task-code: 
 + 
 +<code lisp> 
 +(cpl-impl:replace-task-code '(compatible-ptr args) #'compatible-ptr code-path :ptr-parameter "Oranges"
 +</code> 
 + 
 +By default the :ptr-parameter to cpl-impl:replace-task-code is set to the previously effective value of ptr-parameter that is stored in the task tree node. This either the ptr-parameter in the code slot of the node (if there are no code replacements), or the ptr-parameter in the car object in the code-replacements list of the node. When a task tree node is created and a ptr-parameter is not specified, the default is nil. 
 + 
 +In our example here, the compile-time parameter is a string. It can however be anything, including a struct or a list, for when you need to pass on several objects through plan transformation. 
 + 
 +Let's run the top-level function and see what happens (trace below shows a copy-paste from the repl window) ... 
 + 
 +<code lisp> 
 +CL-USER> (try-ptr) 
 +Inside example-ptr. 
 +Received arguments (2 1 0) 
 +PTR parameter is (Apples) 
 +Will now fail, so as to trigger plan transformation. 
 +Will replace code now (and switch the ptr-parameter) ... 
 +Inside compatible-ptr. 
 +Received arguments (3 2 0) 
 +PTR parameter is (Oranges) 
 +Done! 
 +NIL 
 +CL-USER> (try-ptr) 
 +Inside compatible-ptr. 
 +Received arguments (5 3 0) 
 +PTR parameter is (Oranges) 
 +Done! 
 +NIL 
 +CL-USER> (try-ptr) 
 +Inside compatible-ptr. 
 +Received arguments (8 5 0) 
 +PTR parameter is (Oranges) 
 +Done! 
 +NIL 
 +</code> 
 + 
 +Notice how the transformed plan persists between plan runs, including the compile-time parameter, even though the run-time parameters change as expected.
  
 ===== Task tree serialization ===== ===== Task tree serialization =====