[p-dev] for review: [docs] Begin documenting loops

Paul Bone paul at plasmalang.org
Tue Aug 23 00:11:09 AEST 2016


From: Paul Bone <paul at bone.id.au>

I've written the initial version of the reference information about loops
and I'm seeking any feedback or discussion about this.  If you'd prefer you
can read it online here:

http://plasmalang.org/docs/plasma_ref.html#_loops

I haven't written a grammar yet or described the interface for the coroutines
and other interfaces.  But they shouldn't be too hard to imagine.

---

[docs] Begin documenting loops

This is an initial idea of how loops might work.  I'm seeking feedback on
this.

docs/plasma_ref.txt:
    As above.
---
 docs/plasma_ref.txt | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/docs/plasma_ref.txt b/docs/plasma_ref.txt
index 5bdcf45..ae0a3fd 100644
--- a/docs/plasma_ref.txt
+++ b/docs/plasma_ref.txt
@@ -621,6 +621,125 @@ that also binds the variable (or does not fall-through).  Else branches
 aren't required if the then branch does not fall-through or does not bind
 anything (it may have an effect).
 
+==== Loops
+
+NOTE: Not implemented yet.
+
+NOTE: I'm seeking feedback on this section in particular.
+
+There are three basic types of loops: map, reduce and map+reduce.
+However they all use the same syntax and general implementation.
+These loop types are useful in introducing them in this manual.  The types
+also refer to possible compiler optimisations.
+
+Map loops are the easiest to understand.
+
+----
+    for x in xs -> y in ys {
+        y = f(x)
+    }
+----
+
+A reduce loop can look like.
+
+----
+    for x in xs accumulate sum from 0 {
+        sum = sum0 + x
+    }
+----
+
+And map+reduce loops look like.
+
+----
+    for x in xs -> y in ys accumulate sum from 0 {
+        y = f(x)
+        sum = sum0 + y
+    }
+----
+
+The variable sum0 is made available automatically.  This may change after
+accumulator syntax (like state variables in Mercury) is introduced.
+
+Of course for these trivial examples using map or foldl directly may make
+code more concise, especially when the body is simply another (curried)
+function.  But for more complex loops, the loop syntax can be very
+expressive.
+
+There may be multiple accumulators, separated by commas.  There may also be
+multiple inputs and outputs, also separated by commas.  Multiple inputs
+work as "dot" products, they must be of equal length.  Cross products are
+also supported with the +cross+ keyword.  Parenthesis may be used resolve
+binding between cross and dot products.
+
+----
+    for x in xs, y in ys -> a in as, b in bs {
+        a = x + y
+        b = x * y
+    }
+----
+
+So far all of the ADTs have been the same (oh, they're not just list,
+they're any ADT supporting the generate and/or build interfaces, for input
+and output respectively).  Let's build an array from a map over a list (or
+other ADT).
+
+----
+    for x in xs {
+        y = f(x)
+    } returning {
+        ys = array of y
+    }
+----
+
+Here we switched to the "full" syntax.  In this case +array+ is the name of
+a builder that builds an array during iteration.  We haven't yet designed
+the interfaces of generators and builders, but they will probably involve
+coroutines and allow for optimisation to other interfaces like +foldable+ or
++functor+ for more efficient execution.
+
+You can preform other reductions using this syntax, oh and drop the body if
+you don't need it to do anything.
+
+----
+    for x in xs returning {
+        m = max of x
+    }
+----
+
++max+ returns the maximum.  The +returning+ clause can contain multiple
+entries.
+
+----
+    for p0 in procs0 -> p in procs {
+        ...
+    } returning {
+        errors = concat_list of errors
+        warnings = concat_list of warnings
+    }
+----
+
+Returning is similar to using an accumulator, except that the calculation
+used in the accumulator is part of the loop body, and therefore its
+intermediate results may be used by other parts of the loop.  For example a
+returning clause entry cannot be used to compute a running total.
+
+In general loops are implemented in terms of coroutines.  A coroutine per
+input, per output / returning.  Accumulators can be handled directly.  I
+have not started the design of the interfaces for the coroutining.  Many
+loops (and parts of loops) can be optimised by using +foldable+ or
++mappable+ interfaces rather than coroutines, and some may optimised
+further.  Avoiding accumulators will allow the compiler to more easily
+optimise loops.  It may be possible to do a better optimisation job by
+performing a dependency analysis on the body and separating out the code for
+each accumulator.
+
+Auto-parallelisation (a future goal) will work better with accumulators or
+reductions that are known to be either:
+
+- Order independent
+- Associative / commutative, but whose input type is the same as the output
+- Mergable, with a known identity value.
+
 === Expressions
 
 Expressions are broken into two parts.  This allows us to parse call
-- 
2.7.4



More information about the dev mailing list