How to use COOSy: ================= COOSy (Curry Object Observation System) is a tool to observe the execution of programs written in the declarative multi-paradigm language Curry. It is based on the idea to observe the evaluation of expressions (including functions and free variables) in a Curry program. Thus, one must annotate the expressions to be observed in a Curry program as explained in the following. The observation of an expression is done by the following steps: 1. Start the COOSy environment by the command `:coosy` in the PAKCS environment. This command also adds to the load path the directory containing the modules to be imported for executing observations (see below). 2. Import the module `Observe` into your program by the import declaration `import Observe`. 3. Annotate the expression to be observed. For instance, if `e` is this expression in your program, replace `e` by (observe e) where is a string to be printed with this observation and is an appropriate observer for the type of `e`. The library `Observe` defines observers for various types, e.g., `oInt`, `oBool`, `oChar`, `oFloat` for the base types, `oLit` for enumeration types consisting only of 0-ary data constructors, `oList`, `oString`, `oPair`, `oTriple`, `oMaybe`, `oEither` for some basic structured types, and combinators `~>`, `~~>`, `~~~>` for functional types. Further observers can be automatically derived (see below). Note that COOSy also show the instantiation of free variables. For this purpose, the expression to be observed must be an instance of class `Data`. If this is not the case (e.g., for functional values), one has to use the observation function `observeG` instead of `observe`. 4. Load and run your program with the PAKCS system. 5. Show the recorded observations with the `Show` button in the COOSy environment. A few examples: =============== - Observe the evaluation of an integer expression (x+y): (observe oInt "Addition" (x+y)) - Observe the evaluation of an infinite list ([1..]): (observe (oList oInt) "enumFrom 1" [1..]) If your program terminates, only the evaluated parts of this list are shown. - Observe the evaluation (i.e., instantiations) of a logical variable x: (observe (oList oInt) "List variable" x) ++ y =:= [1,2] - Observe the evaluation of a function (reverse): (observeG (oList oInt ~> oList oInt) "reverse" reverse) [1,2,3] - Observe all evaluations of a function (reverse): Insert a new function definition with observers orev = observeG (oList oInt ~> oList oInt) "all_reverse" reverse and replace all calls to "reverse" (with integer lists) by "orev", e.g. orev [1,2] ++ orev [3,4] - Observe all evaluations of a higher-order function (`foldr`): (observeG ((oInt ~~> oInt ~~> oInt) ~~~> oInt ~~> oList oInt ~~> oInt) "foldr" foldr) (+) 0 [1..4] Since functional values are not instances of class `Data`, one has to use different observer combinators for functions. The combinator `~>` requires that the argument and result types are instances of `Data`. The combinator `~~>` requires that the argument type is an instance of `Data`. The combinator `~~~>` have no such requirement of the argument and result type. Note that in this example the representation of functions as bags of input/output tuples is relevant to represent the functional argument. Interpretation of the output: ============================= "_": unevaluated argument "!": undefined result "?": logical variable "?/v": logical variable bound to value v "{ ... }": Functional value represented as input/output pairs Automatic generation of observers for user-defined types ======================================================== If you need observer functions for your own datatypes, COOSy can automatically derive them from the datatype definitions in your program. For this purpose, click on the button "Add observers" and select your Curry program. As a result, all necessary definitions of observer functions are added to your source program.