@@ -743,6 +743,150 @@ def generateMainClasses(): Unit = {
743743 """
744744 }
745745
746+ def genLazyFor (im : ImportManager , packageName : String , className : String ): String = {
747+ xs """
748+ ${
749+ monadicTypesFor
750+ .filterNot(_ == " Iterable" )
751+ .gen(mtype => (2 to N ).gen(i => {
752+ val forClassName = s " ForLazy $i$mtype"
753+ val isComplex = monadicTypesThatNeedParameter.contains(mtype)
754+ val parameterInset = if (isComplex) " L, " else " "
755+ val generics = parameterInset + (1 to i).gen(j => s " T $j" )(" , " )
756+
757+ val params = (1 to i).gen { j =>
758+ if (j == 1 )
759+ s " $mtype< ${parameterInset}T1> ts1 "
760+ else {
761+ val inputTypes = (1 until j).gen(k => s " T $k" )(" , " )
762+ s " Function ${j - 1 }< $inputTypes, $mtype< ${parameterInset}T $j>> ts $j"
763+ }
764+ }(" , " )
765+
766+ val ctorArgs = (1 to i).gen(j => s " ts $j" )(" , " )
767+
768+ xs """
769+ / $javadoc
770+ * Creates a lazy {@code For}-comprehension over ${i.numerus(mtype)}.
771+ *
772+ * <p>The first argument ({@code ts1}) is the initial ${mtype}. Each subsequent
773+ * argument ({@code ts2} .. {@code ts $i}) is a function that receives all values
774+ * bound so far and returns the next ${mtype}. This only builds the lazy
775+ * comprehension; effects are evaluated when {@code yield(...)} is called.</p>
776+ *
777+ ${(0 to i).gen(j => if (j == 0 ) " *" else s " * @param ts $j the ${j.ordinal} ${mtype}" )(" \n " )}
778+ ${if (isComplex) s " * @param <L> the common left-hand type of all ${mtype}s \n " else " " }
779+ ${(1 to i).gen(j => s " * @param <T $j> the component type of the ${j.ordinal} ${mtype}" )(" \n " )}
780+ * @return a new {@code $forClassName} builder of arity $i
781+ * @throws NullPointerException if any argument is {@code null}
782+ */
783+ public static < $generics> $forClassName< $generics> For( $params) {
784+ ${(1 to i).gen(j => xs """ $Objects.requireNonNull(ts $j, "ts $j is null"); """ )(" \n " )}
785+ return new $forClassName<>( $ctorArgs);
786+ }
787+ """
788+ })(" \n\n " ))(" \n\n " )
789+ }
790+
791+ ${
792+ monadicTypesFor
793+ .filterNot(_ == " Iterable" )
794+ .gen(mtype => (2 to N ).gen(i => {
795+ val rtype = mtype
796+ val forClassName = s " ForLazy $i$mtype"
797+ val parameterInset = if (monadicTypesThatNeedParameter.contains(mtype)) " L, " else " "
798+ val generics = parameterInset + (1 to i).gen(j => s " T $j" )(" , " )
799+ val functionType = i match {
800+ case 2 => BiFunctionType
801+ case _ => s " Function $i"
802+ }
803+ val args = (1 to i).gen(j => s " ? super T $j" )(" , " )
804+
805+ val fields = (1 to i).gen { j =>
806+ if (j == 1 )
807+ s " private final $mtype< ${parameterInset}T1> ts1; "
808+ else {
809+ val inputTypes = (1 until j).gen(k => s " T $k" )(" , " )
810+ s " private final Function ${j - 1 }< $inputTypes, $mtype< ${parameterInset}T $j>> ts $j; "
811+ }
812+ }(" \n " )
813+
814+ val ctorParams = (1 to i).gen { j =>
815+ if (j == 1 )
816+ s " $mtype< ${parameterInset}T1> ts1 "
817+ else {
818+ val inputTypes = (1 until j).gen(k => s " T $k" )(" , " )
819+ s " Function ${j - 1 }< $inputTypes, $mtype< ${parameterInset}T $j>> ts $j"
820+ }
821+ }(" , " )
822+
823+ val assignments = (1 to i).gen(j => s " this.ts $j = ts $j; " )(" \n " )
824+
825+ val yieldBody = {
826+ def nestedLambda (j : Int ): String = {
827+ val base = " "
828+ val indent = " " * j
829+ if (j == i) {
830+ val argsList = (1 to i).map(k => s " t $k" ).mkString(" , " )
831+ val inputArgs = (1 until i).map(k => s " t $k" ).mkString(" , " )
832+ s " ts $i.apply( $inputArgs).map(t $i -> f.apply( $argsList)) "
833+ } else if (j == 1 ) {
834+ s " ts1.flatMap(t1 -> { \n " +
835+ s " ${base}${indent} return ${nestedLambda(j + 1 )}; \n " +
836+ s " ${base}${indent}}) "
837+ } else {
838+ val inputArgs = (1 until j).map(k => s " t $k" ).mkString(" , " )
839+ s " ts $j.apply( $inputArgs).flatMap(t $j -> { \n " +
840+ s " ${base}${indent} return ${nestedLambda(j + 1 )}; \n " +
841+ s " ${base}${indent}}) "
842+ }
843+ }
844+
845+ nestedLambda(1 )
846+ }
847+
848+ xs """
849+ / $javadoc
850+ * A lazily evaluated {@code For}-comprehension with ${i.numerus(mtype)}.
851+ *
852+ * <p>Constructed via {@code For(...)} and evaluated by calling {@code yield(...)}.
853+ * Construction is side-effect free; underlying ${i.plural(mtype)} are only
854+ * traversed when {@code yield(...)} is invoked.</p>
855+ *
856+ ${if (monadicTypesThatNeedParameter.contains(mtype)) s " * @param <L> the common left-hand type of all ${mtype}s \n " else " " }
857+ ${(1 to i).gen(j => s " * @param <T $j> the component type of the ${j.ordinal} ${mtype}" )(" \n " )}
858+ */
859+ public static class $forClassName< $generics> {
860+
861+ $fields
862+
863+ private $forClassName( $ctorParams) {
864+ $assignments
865+ }
866+
867+ / $javadoc
868+ * Produces results by mapping the Cartesian product of all bound values.
869+ *
870+ * <p>Evaluation is lazy and delegated to the underlying ${i.plural(mtype)} by
871+ * composing flatMap/map chains.</p>
872+ *
873+ * @param f a function that maps a tuple of bound values to a result
874+ * @param <R> the element type of the resulting {@code $rtype}
875+ * @return an {@code $rtype} containing mapped results
876+ * @throws NullPointerException if {@code f} is {@code null}
877+ */
878+ public <R> $rtype< ${parameterInset}R> yield( $functionType< $args, ? extends R> f) {
879+ $Objects.requireNonNull(f, "f is null");
880+ return $yieldBody;
881+ }
882+ }
883+ """
884+ })(" \n\n " ))(" \n\n " )
885+ }
886+ """
887+ }
888+
889+
746890 def genFor (im : ImportManager , packageName : String , className : String ): String = {
747891 xs """
748892 //
@@ -1440,6 +1584,8 @@ def generateMainClasses(): Unit = {
14401584
14411585 ${genFor(im, packageName, className)}
14421586
1587+ ${genLazyFor(im, packageName, className)}
1588+
14431589 ${genMatch(im, packageName, className)}
14441590 }
14451591 """
0 commit comments