Presenters

Visual Prolog can write any value, but often the printed version of a value is not very useful. An object is for example written as the address of the object. A presenter is a predicate that is attached to a domain and can be used to write (i.e. "present") the values of that domain in a more meaningful way.

Presenters are however also used in the debugging process to provide more expressive/simpler presentations in the Variables Window (and in similar contexts).

As you can see in the example above the presenter not only affect the writing of the map object it also alters the way it is expanded in the window. The map above is actually an object that contains a fact with a red-black-tree which contains the actual mapping of 1 to "a", but all these details are hidden in favor of a much more semantically meaningful presentation.

If you need access to the low-level expansion of something in the debugger you can right click the value and switch on "Native View". This will affect all values of that type; which will get an extra child node which contains the "native" (i.e. unpresented) view of the value.

The notion of presenters is relatively complex due to the double role it serves both as plain text presentation and as recipe for expansion in the debugger. Subsequently, it can be difficult to write a good presenter for a complex domain.

Presenting
Any text-mode outputStream can present a value of a domains that has presenters attached. This can be done either by calling the predicate present or by using "%p" in a format string. The present predicate works like the write predicate except that all values are written using the attached presenters rather than in the default/built-in way. Likewise, a value corresponding to "%p" in a format string will be written using the attached presenters.

string::present(V)</vp> will return a string with the presentation of V</vp>, and string::format</vp> will (and any other predicate that uses format strings) can also use "%p"</vp> for presentation.

As mentioned below presenters works on (deeply) nested terms regardless of whether the surrounding term has attached presenters or not.

Attaching presenters
If a presenter predicate has not been attached to a domain, then the domain will use a default presenter predicate instead. The default presenter predicate will present the value in the standard way (i.e. like write</vp>) however subterms will be presented using their presenter. So presenters works on deeply nested in values (regardless of whether the outer terms have presenters or not).

The presenter for a domain is a predicate which is attached to the domain using a presenter/1</vp> attribute in the domain definition:

The presenter predicate is (i.e. must be) a function from a Value</vp> in the domain (i.e. Type</vp>) to a Presentation</vp>, as specified by the PFC domain presenter::presenter</vp>:

domains presenter{Type} = (Type Value) -> presentation Presentation.

Objects can also be presented. A presenter is attached by using the presenter/0</vp> attribute in the domain definition:

For objects the presenter predicate is always named presenter</vp> corresponding to this declaration (in the interface):

predicates presenter : -> presenter::presentation Presentation.

Notice however that the predicate should not be declared; stating the attribute implicitly implies the predicate declaration.

Cautions
Since presenters are used in the debugging process it is very important that they are kept simple, stateless and efficient. Especially:


 * They should be efficient; long running calculations will affect debug performance.
 * They shoud not have or depend on side-effects; during debugging the presenters may be calculated any number of times in any order.
 * They may not acquire exclusive access to resources (critical sections, mutexes, etc): that may end up blocking the entrire debugging process.
 * They should not start or depend on other threads

Presenter Domain
The presentation</vp> domain (also defined in the presenter</vp> class) looks like this:

domains presentation = noExpand(string Presentation, any Term); expand(string Presentation, any Term); structured(string Delimiter, subPresenter SubPresenter); enclose(string Opening, string Closing, presentation Presentation); functor(functorDescr FunctorDescr, any* SubTerms).

noExpand
domains presentation = noExpand(string Presentation, any Term); ...

The noExpand</vp> alternative is used to provide a string Presentation</vp> for an "atomic" value. The value will be presented as <vp>Presentation</vp> and the debugger will not show any children of the value. The <vp>Term</vp> is used by the debugger to obtain a type of the term. The <vp>noExpand</vp> alternative could for example be used for a number that represent a time; the <vp>Presentation</vp> would be a readable format of the time and the <vp>Term</vp> would be the "raw" time value. The presentation will be the readable format, and the debugger will not provide any expansion of the term (but Native View can be used to see the actual value).

expand
domains presentation = expand(string Presentation, any Term); ...

The <vp>expand</vp> alternative it used to provide a string <vp>Presentation</vp> for an "non-atomic" value. The value will be presented as <vp>Presentation</vp> and will expand it as it would natively expand the <vp>Term</vp>. The debugger also in some cases obtain the type from <vp>Term</vp>. The <vp>expand</vp> alternative could for example be used for a functor term containing date and time fields like year, month, date, hour and minute; the <vp>Presentation</vp> would be a readable format of the date/time and the <vp>Term</vp> would be the functor term. The presentation will be the readable format, and the debugger will provide an expansion that contains the individual fields (year, etc).

enclose
domains presentation = ...       enclose(string Opening, string Closing, presentation Presentation); ...

The <vp>enclose</vp> is used to surround a presentation by <vp>Opening</vp> and <vp>Closing</vp> strings. This is for example used to surround the presentation of a set with "[" and "]" to result in a list-like presentation. The debugger simply consider the nested <vp>Presentation</vp>.

functor
domains presentation = ...       functor(functorDescr FunctorDescr, any* SubTerms). The <vp>functor</vp> alternative is specially designed to be used internally by the compiler runtime system, because the <vp>FunctorDescr</vp>'s are terms that are layed-out as contants by the compiler. The <vp>functor</vp> alternative will create a presentation that corresponds to a functor term which has <vp>SubTerms</vp> as sub-terms. The alternative is partly redundant, because the same thing could have been expressed using <vp>structured</vp> and <vp>enclose</vp> alternatives.

structured
domains presentation = ...       structured(string Delimiter, subPresenter SubPresenter); ...

The <vp>structured</vp> alternative is used for structured terms. The <vp>SubPresenter</vp> will produce a number of sub-presentations. When writing the presentation each of the sub-presentations will be written delimited by <vp>Delimiter</vp>. Typically the delimiter is ", " so that the resulting presentations are written comma separated. This is for example used when presenting sets.

To avoid calculating very large/deep presentations during debugging, the structured presenters uses lazy evaluation of the sub-presenters. This is achieved by letting the presentation contain functions that can calculate the presentation rarther than the presentation itself. So during debugging the presentation of a term will only expand to a certain level. Inside that level there will be functions the debugger can choose to call if further expansion is required. But if further expansion is not required the calculation will be skipped. For this reason the debugger can deal efficiently with very large terms. On the downside this complicates the coding of presenters somewhat.

There are two kinds of <vp>subPresenter</vp>'s:

domains subPresenter = fixed(fieldPresentation* FieldPresentations); sequence(sequencePresenter Sequence).

fixed (structured)
domains subPresenter = fixed(fieldPresentation* FieldPresentations); ...

used for presenting values that have a fixed number of "Field" sub-presentations. This could for example be the presentation of a certain functor alternative, since such a functor term has a certain (fixed) number of sub-terms. Which result in a fixed number of sub-presentations.

When the debugger expands a <vp>fixed</vp> presentation all the sub-presentations will be shown, because they are considered all part of the expanded term.

A <vp>fixed</vp> sub-presenter consist of a list of <vp>fieldPresentation</vp>'s each describing one of the fields.

There are three kinds of <vp>fieldPresentation</vp>'s:

domains fieldPresentation = fp(string Name, subLazy Sub); fp_string(string Presentation); fp_childOnly(string Name, subLazy Sub).

The <vp>fp</vp> alternative has a field <vp>Name</vp> and a lazy sub-presentation <vp>Sub</vp> of the field itself. The field <vp>Name</vp> is used by the debugger for labeling the presentation, but it is not used when writing the presentation. <vp>Sub</vp> will be used by the debugger for the corresponding value and it will also be used in when writing the presentation.

The <vp>fp_string</vp> will only appear in the writing of the presentation, the debugger will not include an <vp>fp_string</vp> when expanding the presentation.

The <vp>fp_childOnly</vp> does not take part in the writing of the presentation, it will only be used as a child by the debugger.

So to summarize, the <vp>fp_string</vp> alternative only show-up in the writing, the <vp>fp_childOnly</vp> only show-up as a child when the debugger expands the presentation and finally the <vp>fp</vp> will both show up in the writing and as a child.

The <vp>subLazy</vp> domain is a little complex:

domains subLazy = subPresentation{fieldPresenter}.

domains fieldPresenter = function{presentation}.

domains subPresentation{Presentation} = pres(Presentation Presentation); term(any Term).

To simplify the explanation it is worth expanding the <vp>fieldPresenter</vp> and <vp>subPresentation</vp> definitions into the <vp>subLazy</vp> domain:

domains subLazy = pres(function{presentation} Presentation); term(any Term).

So effectively a <vp>subLazy</vp> term is either (<vp>pres</vp>) a function returning a presentation or a (<vp>term</vp>) term. The function need only be called if the presentation is required and likewise the term need only be presented if its presentation is required.

sequence (structured)
domains subPresenter = ...;       sequence(sequencePresenter Sequence).

A <vp>sequence</vp> sub-presenter is used for presenting values have a varying number of sub-presentations, for example a set can have from any number of sub-presentations (including none at all). When the debugger expands a <vp>sequence</vp> presentation it will at first only show a limited number of the sub-presentations. That way the debugger will not suddenly be expanding a set that contains millions of elements. Expanding such a large set is rarely interesting, since it will both take a very long time to do and since it will also give result that is too large to comprehend anyway.

The <vp>sequencePresenter</vp> is defined like this:

domains sequencePresenter = function_nd{sub Presentation}.

domains sub = subPresentation{presentation}.

domains subPresentation{Presentation} = pres(Presentation Presentation); term(any Term).

Here it is worth expanding <vp>subPresentation</vp> into the <vp>sub</vp> domain:

domains sequencePresenter = function_nd{sub Presentation}.

domains sub = pres(presentation Presentation); term(any Term).

So a <vp>sequencePresenter</vp> is a nondeterministic predicate that returns presentations (<vp>pres</vp>) or terms (<vp>term</vp>). The nondeterministic predicate can be used to achieve the step-wise expansion of the children (though it is necessary to start from scratch to obtain more children).

Support predicates
The predicate <vp>outputStreamSupport::writePresentation</vp> can be used to test (or use) presenters which are not attached to a domain.

These predicates (in the <vp>presenter</vp> class): predicates present : presenter{any Any}. present_native : presenter{any Any}.

predicates present_term : presenter{Type}. present_term_native : presenter{Type}. Will return the presentation of terms.

The <vp>presenter</vp> class contains a number of support predicates that can be used to make presenters.

The predicate <vp>presenter::mkPresenter_set</vp> will create a "set" presentation (i.e. comma separated and enclosed in "[" and "]") of the elements returned by a nondeterministic predicate.

Should you need/want to enclose a comma separated sequence in something else than "[" and "]", then you can use the predicate <vp>presenter::mkPresenter_setElements</vp> instead.

Similar predicates exist for map-like constructions:

predicates mkPresenter_map : (function_nd{tuple{Key, Value}} GetAll_nd) -> presentation Map. mkPresenter_mapElements : (string MapSymbol, function_nd{tuple{Key, Value}} GetAll_nd) -> presentation Map.

The <vp>MapSymbol</vp> is inserted between the key and value; in <vp>mkPresenter_map</vp> it is <vp>" -> "</vp>.