Language features

Prosper offers language features similar to other server-side technologies as PHP or JSP.

Terminology

In the sections below, we assume that the reader is familiar with the standard Prolog terminology. However, we will additionally use the term function to denote a Prolog predicate whose last argument is constrained to be outward bound. (This corresponds to the Mercury definition of function.) This implicit last argument is never written out but an uninstantiated variable is appended internally when calling the predicate in question. Usually, the outward bound return value is exposed through a local variable for use in the server page.

When defining the syntax of a language construct, we use the following wide-spread conventions:

courier

represents text to be used as-is.

italics

denotes elements to be replaced according to context.

[brackets]

denote optional elements.

[alt1|alt2|alt3]

denote exclusive alternatives.

Variable assignment

Similarly to Prolog, variables in Prosper are single-assigned, i.e. they are immutable once instantiated. On the contrary, the only way to instantiate a variable is within the assignment where it is introduced, there are no means to delay the instantiation of a variable as in Prolog. The examples below illustrate the use of variables, variable assignment and variable contexts via the element psp:assign.

psp:assign with expr attribute

Syntax


<psp:assign var="variable" expr="expression">
  xml-content
</psp:assign>

Example


<psp:assign var="A" expr="{atom_prefix('ok', 'okay')}">
  ok
</psp:assign>

Sample output

ok

psp:assign with function attribute

Syntax

<psp:assign var="variable" function="function">
  xml-content
</psp:assign>

Example

<psp:assign var="A" function="length([1,2,3])">
  ok, value = <psp:insert var="A" />
</psp:assign>

Sample output

ok, value = 3

psp:assign with variable redefinition

Example

<psp:assign var="A" expr="fail">
  <psp:assign var="A" expr="ok">
    <psp:insert var="A" />
  </psp:assign>
</psp:assign>

Sample output

ok

Variable insertion

The value of single-assigned variables or potions of complex data structures are inserted directly into the output via the psp:insert element.

psp:assign with var attribute

Syntax

<psp:insert var="variable" />

Example

<psp:assign var="A" expr="Hello">
  <psp:insert var="A" /> world!
</psp:assign>

Sample output

Hello world!

Simple conditionals

Conditionals allow page sections to be displayed or hidden based on values or expressions or the satisfiability of a goal. The examples below illustrate the use of simple conditionals, represented by the element psp:if.

psp:if with goal attribute

Syntax

<psp:if goal="goal">
  xml-content
</psp:if>

Semantics

Attempts to run the specified Prolog goal and embeds the content defined by the enclosing tags into the output upon success, or is replaced by empty content otherwise. The element performs an implicit cut on the specified goal and does not backtrack.

Example

<psp:if goal="length([1,2,3], 3)">
  ok
</psp:if>

Sample output

ok

psp:if with function attribute

Syntax

<psp:if function="function" [binding="variable"]>
  xml-content
</psp:if>

Semantics

Calls the given Prolog function (i.e. appends an uninstantiated argument to the specified term and calls the resulting predicate) and embeds the enclosed content in the output if the function succeeds. The difference between the psp:if element used in conjunction with the goal and function attribute is that in the latter case, the return value (i.e. the last outward bound argument of the augmented predicate) is available through the local variable Binding. In order to avoid name clashes in nested constructs, the attribute binding can be used to rename this local variable.

Example

<psp:if function="length([1,2,3])">
  ok, value = <psp:insert var="Binding" />
</psp:if>

Sample output

ok, value = 3

psp:if with expr attribute

Syntax

<psp:if expr="boolean-expression">
  xml-content
</psp:if>

Semantics

Evaluates the given expression and embeds the content enclosed by the start and end tags in the output if the expression is true. The expression must evaluate to the Prolog atom true or fail, or an error is generated. Typically, the condition expression uses the functional-flavor expression language (enclosed in {braces}).

Example

<psp:if expr="{1 + 2 + 3 > 5}">
  ok
</psp:if>

Sample output

ok

psp:if with defined attribute

Syntax

<psp:if defined="variable">
  xml-content
</psp:if>

Example

<psp:assign var="Var" expr="{1}">
  <psp:if defined="Var">
    ok
  </psp:if>
</psp:assign>

Sample output

ok

psp:if-else

Syntax

<psp:if-else>
  <psp:if attributes>
    xml-content
  </psp:if>
  <psp:else>
    xml-content
  </psp:else>
</psp:if-else>

Example


<psp:if-else>
  <psp:if expr="{random(100) >= 50}">
    heads
  </psp:if>
  <psp:else>
    tails
  </psp:else>
</psp:if-else>

Sample output

tails

Compound conditional

psp:choose

Syntax

<psp:choose>
  <psp:when [goal="goal"|function="function"|expr="boolean"|defined="variable"]>
    xml-content
  </psp:when>
  <psp:when [goal="goal"|function="function"|expr="boolean"|defined="variable"]>
    xml-content
  </psp:when>
  <psp:otherwise>
    xml-content
  <psp:otherwise>
</psp:choose>

Semantics

psp:choose is provided as an alternative to nested psp:if constructs to improve readability. Upon evaluation, the condition of the first psp:when child node of a psp:choose element is tested, if it fails, evaluation proceeds to the next condition. A psp:otherwise (or psp:else) node allows an alternative in case all others fail. Syntactically equivalent to the Prolog construct:

( predicate_1(A, B, C) -> action_1
; predicate_2(D, E) -> action_2
; action_otherwise
).

psp:when accepts exactly the same attributes as psp:if and the outcome is identical in all aspects. psp:when constructs can always be – and internally are – rewritten as nested psp:if-else constructs.

Example

 <psp:assign var="Number" expr="{random(100)}">
  <psp:choose>
    <psp:when goal="between(50, 100, Number)">
      <psp:insert var="Number" /> is greater than or equal to 50.
    </psp:when>
    <psp:when expr="{Number mod 2 =:= 0}">
      <psp:insert var="Number" /> is even.
    </psp:when>
    <psp:otherwise>
      <psp:insert var="Number" /> is odd and less than 50.  
    <psp:otherwise>
  </psp:choose>
</psp:assign>

Sample output

78 is greater than or equal to 50.

Iteration and backtracking

Displaying a slightly modified version of a page section for each member of a list that contains solutions is a task that arises frequently. The examples below show how to iterate over the members of a list and display all solutions of a problem using for-each and psp:for-all.

psp:for-each with function attribute

This construct evaluates a page section for each element of the list returned by function. The returned value is stored in a variable whose name is defined by iterator.

Syntax

<psp:for-each iterator="iterator" function="function">
  xml-content
</psp:for-each>

Example

This snippet displays the ASCII character codes that comprise the string Prosper.

<ol>
<psp:for-each iterator="I" function="atom_codes('Prosper')">
  <li><psp:insert var="I" /></li>
</psp:for-each>
</ol>

Sample output

  1. 80
  2. 114
  3. 111
  4. 115
  5. 112
  6. 101
  7. 114

psp:for-each-else

This construct evaluates a page section for each element of a list returned by some function. The returned value is stored in a variable whose name is defined by iterator. The construct also defines an alternative page section to be displayed when function fails.

Syntax

<psp:for-each-else>
  <psp:for-each iterator="iterator" function="function">
    xml-content
  </psp:for-each>
  <psp:else>
    xml-content
  </psp:else>
</psp:for-each-else>

psp:for-all with function attribute

This construct calls the Prolog predicate corresponding to function, and displays the encapsulated page section using its returned value, which is accessed through the variable iterator. If the predicate has more solutions, these are discovered by backtracking, and the page section is displayed for each solution.

Syntax

<psp:for-all iterator="iterator" function="function">
  xml-content
</psp:for-each>

Example

This snippet displays integers between 1 and 11.

<ol>
<psp:for-all iterator="I" function="between(1,11)">
  <li><psp:insert var="I" /></li>
</psp:for-each>
</ol>

Sample output

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11