Primes Expressions example

In this version of the Primes example, we use svc_expr to decide whether a number is prime.

Figure: Primes Expressions example - Overview


Tip: Get the code from the SPARKL public repository.
Table 1. Primes Expressions - Markup
Example Description
<folder name="Primes_expr">
  <field name="NO"/>
  <field name="YES"/>
  <field name="MAYBE"/>
  <field name="n" 
    type="integer"/>
  <field name="div" 
    type="integer"/>
  <service name="Sequencer" 
    provision="sequencer"/>
  <service name="Backend" 
    provision="expr">
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
NextDiv = fun
  (2) -> 3;
  (Div) -> Div + 2
end.
    ]]></prop>
  </service>
  <mix name="Mix">
    <folder name="Frontend">
    ...      
    </folder>
    <folder name="Backend">
    ...  
    </folder>
  </mix>
</folder>
In this mix we use:
  • Five fields sent between the operations
  • The Sequencer service that implements the solicit/response operation
  • The Backend service, which implements multiple operations in this mix
  • Two folders containing five operations
The Backend service contains a function, which is bound to the NextDiv variable.

Any operation on the Backend service can reference this function.

The NextDiv function is used to create new divisors.

If the value of the previous divisor is 2, the new divisor is 3.

Otherwise, the value of the new divisor is previous divisor plus two.

<folder name="Frontend">
  <solicit name="CheckPrime" 
    service="Sequencer" 
    fields="n">
    <response name="Yes" 
      fields="YES"/>
    <response name="No" 
      fields="NO"/>
  </solicit>
  <consume name="Log"
     service="Backend"
     fields="n YES"/>
</folder>
The CheckPrime solicit sends the field n, and starts a transaction.

The transaction ends if Sequencer manages to collect either:

  • n and YES - Prime response is sent

  • n and NO - NotPrime response is sent

If a field set contains n and YES, Backend implements the Log operation.

Tip: You can use the Log operation to add records to a database. Expressions services can be used as databases. See Services as Databases usage pattern.
<folder name="Backend">
  <request name="FirstDivisor" 
    service="Backend" 
    fields="n">
    <prop name="expr.bind.out" 
      Div="div"/>
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
Div = 2,
"Ok".
    ]]></prop>
    <reply name="Ok" 
      fields="div"/>
  </request>
  <request name="Test" 
    service="Backend" 
    fields="div n">
    <prop name="expr.bind.in" 
      Div="div" N="n"/>
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
case Div * Div > N of
  true ->
    "Yes";
  false ->
    case N rem Div of
      0 ->
        "No";
      _Otherwise ->
        "Maybe"
    end
 end.
    ]]></prop>
    <reply name="Yes" 
      fields="YES"/>
    <reply name="No" 
      fields="NO"/>
    <reply name="Maybe"
      fields="MAYBE"/>
  </request>
  <consume name="Iterate" 
    service="Backend" 
    fields="MAYBE div n">
    <prop name="expr.bind.in" 
      Div="div" N="n"/>
    <prop name="expr.bind.out" 
      NewDiv="div" N="n"/>
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
NewDiv = NextDiv(Div),
"Ok".
    ]]></prop>
    <reply name="Ok" 
      fields="div n"/>
  </consume>
</folder>
The FirstDivisor operation adds the field div to the field set.

This field is bound to the variable Div. The expressions in FirstDivisor assign the value 2 to the variable and send the Ok reply.

The field set now contains n and div.

The Test operation makes some calculations with n and div, which are bound to the N and Div variables.

Based on the calculations, Test sends either the Yes, No or Maybe reply.

The field set now contains either of the following:

  • n, div and YES - n is prime
  • n, div and NO - n is not prime
  • n, div and MAYBE - at this point it cannot be decided if n is prime

If Test sends the Maybe reply, the Iterate operation is implemented.

Iterate is a consume/reply. The consume forms a goal as reply-less consumes usually do. A reply to a consume creates a new field set, and thus, a parallel thread of execution.

A parallel thread does not count as a new transaction. Only one response will be sent to the CheckPrime solicit. Consumes, however, like Iterate itself, can be satisfied multiple times in the same transaction by parallel threads.

Iterate uses field bindings, and the NextDiv function in the Backend service, to:
  • Retain the value of n
  • Create a new value for div
Iterate sends a new field set comprising n and div to Test.

Test again sends either the Yes, No or Maybe reply.

If the Maybe reply is sent, Iterate creates yet another field set, and so on, until Test sends either Yes or No.

Previous field sets, which contain n, div and MAYBE, are discarded after satisfying the Iterate consume, as they cannot satisfy other goals.