Package net.fortytwo.ripple.libs.control

Source Code of net.fortytwo.ripple.libs.control.Map$InnerMapping

package net.fortytwo.ripple.libs.control;

import net.fortytwo.flow.Collector;
import net.fortytwo.flow.Sink;
import net.fortytwo.ripple.RippleException;
import net.fortytwo.ripple.libs.stack.StackLibrary;
import net.fortytwo.ripple.model.ModelConnection;
import net.fortytwo.ripple.model.NullStackMapping;
import net.fortytwo.ripple.model.Operator;
import net.fortytwo.ripple.model.PrimitiveStackMapping;
import net.fortytwo.ripple.model.RippleList;
import net.fortytwo.ripple.model.RippleValue;
import net.fortytwo.ripple.model.StackMapping;

/**
* A primitive which consumes a list and a mapping, then applies the mapping to
* each element in the list (as if it were on top of the remainder of the stack)
* in turn, yielding another list.
* For instance, <code>(1 2 3) (10 add.) map.</code> yields <code>(11 12 13)</code>
*
* @author Joshua Shinavier (http://fortytwo.net)
*/
public class Map extends PrimitiveStackMapping {
    public String[] getIdentifiers() {
        return new String[]{
                ControlLibrary.NS_2013_03 + "map",
                StackLibrary.NS_2008_08 + "map"};
    }

    public Map() throws RippleException {
        super();
    }

    public Parameter[] getParameters() {
        return new Parameter[]{
                new Parameter("l", "a List to map through m", true),
                new Parameter("m", "a mapping which produces and consumes one argument", true)};
    }

    public String getComment() {
        return "l m  =>  l mapped through m";
    }

    public void apply(final RippleList arg,
                      final Sink<RippleList> solutions,
                      final ModelConnection mc) throws RippleException {
        RippleList stack = arg;

        final RippleValue mappingVal = stack.getFirst();
        stack = stack.getRest();
        RippleValue listVal = stack.getFirst();
        final RippleList rest = stack.getRest();

        // Note: it is simply assumed that these mappings have a production of
        // exactly one item.
        final Collector<Operator> operators = new Collector<Operator>();
        Operator.createOperator(mappingVal, operators, mc);

        Sink<RippleList> listSink = new Sink<RippleList>() {
            public void put(final RippleList list) throws RippleException {
                if (list.isNil()) {
                    solutions.put(rest.push(list));
                }

                // TODO: this is probably a little more complicated than it needs to be
                else {
                    RippleList inverted = list.invert();
                    RippleValue f = inverted.getFirst();

                    for (Operator operator : operators) {
                        StackMapping inner = new InnerMapping(mc.list(), inverted.getRest(), operator);
                        solutions.put(rest.push(f).push(mappingVal).push(Operator.OP).push(new Operator(inner)));
                    }
                }
            }
        };

        mc.toList(listVal, listSink);
    }

    private class InnerMapping implements StackMapping {
        private RippleList invertedListHead;
        private RippleList constructedList;
        private Operator operator;

        public InnerMapping(final RippleList constructedList,
                            final RippleList invertedListHead,
                            final Operator operator) {
            this.constructedList = constructedList;
            this.invertedListHead = invertedListHead;
            this.operator = operator;
        }

        public int arity() {
            return 1;
        }

        public StackMapping getInverse() throws RippleException {
            return new NullStackMapping();
        }

        public boolean isTransparent() {
            return true;
        }

        public void apply(final RippleList arg,
                          final Sink<RippleList> solutions,
                          final ModelConnection mc) throws RippleException {

            RippleList stack = arg;
            RippleValue first = stack.getFirst();
            stack = stack.getRest();

            RippleList newListRest = constructedList.push(first);

            if (invertedListHead.isNil()) {
                solutions.put(stack.push(newListRest));
            } else {
                // The stack to operate on
                RippleList restStack = stack.push(invertedListHead.getFirst()).push(operator);

                StackMapping restMapping = new InnerMapping(newListRest, invertedListHead.getRest(), operator);
                solutions.put(restStack.push(new Operator(restMapping)));
            }
        }
    }
}
TOP

Related Classes of net.fortytwo.ripple.libs.control.Map$InnerMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.