// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function2.java
// public interface Function2<T1, T2, R> {
//     R invoke(T1 arg1, T2 arg2);
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/Parser.java
// public interface Parser<T> {
// 	ParseResult<T> invoke(String input);
// 	default Parser<T> or(Parser<T> rhs) {
// 		return new Or<>(this, rhs);
// 	}
// 	default <U> Parser<Tuple2<T, U>> cat(Parser<U> rhs) {
// 		return new Cat<>(this, rhs);
// 	}
// 	default <U> Parser<U> map(Function1<T, U> fn) {
// 	    return new MapParser<>(this, fn);
// 	}
// 	default <U> Parser<U> flatMap(Function1<T, Parser<U>> fn) {
// 		return new FlatMapParser<>(this, fn);
// 	}
// 	default Parser<Optional<T>> option() { return new OptionParser<T>(this); }
// 	default Parser<List<T>> many() {
// 		return new ManyParser<T>(this);
// 	}
// 	default Parser<List<T>> many1() {
// 		return new Many1Parser<T>(this);
// 	}
// 	default Parser<T> chain(Parser<Function2<T, T, T>> q) {
// 		return this.cat(q.cat(this).many()).map(t -> t.extract((init, list) -> {
// 			return foldLeft(list, init, ts -> {
// 				T a = ts.item1();
// 				return let(ts.item2().item1(), f -> {
// 					return let(ts.item2().item2(), b -> {
// 						return f.invoke(a, b);
// 					});
// 				});
// 			});
// 		}));
// 	}
// 	default Parser<T> not() { return new Not<>(this); }
// 	default Parser<T> and() { return new And<>(this); }
// 	static Parser<String> any() { return new AnyParser(); }
// 	static Parser<String> string(String literal) {
// 	    return new StringParser(literal);
// 	}
// 	static <T> Rule<T> rule(Function0<Parser<T>> body) {
// 		return new Rule<>(body);
// 	}
// 	static Parser<String> eof() {
// 		return new EOFParser();
// 	}
// 	static RangeParser range(char from, char to) {
// 		return new RangeParser(from, to);
// 	}
// 	static SetParser set(char... characters) {
// 		java.util.Set<Character> set = new java.util.HashSet<>();
// 		for(char ch:characters) {
// 		    set.add(ch);
// 		}
// 		return new SetParser(set);
// 	}
// 	static Parser<String> alphabet() {
// 		return range('a', 'z').or(range('A', 'Z'));
// 	}
// 	static Parser<String> digit() {
// 		return range('0', '9');
// 	}
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/Functions.java
// public class Functions {
// 
//     public static <T, U> U let(T value, Function1<T, U> fn) {
//         return fn.invoke(value);
//     }
// 
//     public static <T> void let(T value, Procedure1<T> pr) {
//         pr.invoke(value);
//     }
//     
//     public static <T, U> U foldLeft(List<T> list, U init, Function1<Tuple2<U, T>, U> f) {
//     	U result = init;
//     	for(T t:list) {
//     		result = f.invoke(new Tuple2<>(result, t));
//     	}
//     	return result;
//     }
//     
//     public static <T> String join(List<T> list, String separator) {
//     	if(list.size() == 0) {
//     		return "";
//     	} else {
//     		return let(new StringBuilder(), builder -> {
//     		    T t = list.get(0);
//     		    List<T> es = list.subList(1, list.size());
//     			builder.append(t.toString());
//     			for(T e:es) {
//     				builder.append(separator);
//     				builder.append(e.toString());
//     			}
//     			return new String(builder);
//     		});
//     	}
//     }
// }


import com.github.kmizu.jcombinator.datatype.Function2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.junit.Assert.*;
import static com.github.kmizu.jcombinator.Parser.*;
import static com.github.kmizu.jcombinator.Functions.*;
package com.github.kmizu.jcombinator;




@RunWith(JUnit4.class)
public class ChainlTest {
	private Rule<Integer> expression() {
	    return rule(() ->
			additive().cat(eof()).map(t -> t.extract((result, __) -> result))
		);
	}
	private Rule<Integer> additive() {
		return rule(() -> {
			final Parser<Function2<Integer, Integer, Integer>> Q = string("+").map(op -> (Integer lhs, Integer rhs) -> lhs + rhs);
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function2.java
// public interface Function2<T1, T2, R> {
//     R invoke(T1 arg1, T2 arg2);
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/Parser.java
// public interface Parser<T> {
// 	ParseResult<T> invoke(String input);
// 	default Parser<T> or(Parser<T> rhs) {
// 		return new Or<>(this, rhs);
// 	}
// 	default <U> Parser<Tuple2<T, U>> cat(Parser<U> rhs) {
// 		return new Cat<>(this, rhs);
// 	}
// 	default <U> Parser<U> map(Function1<T, U> fn) {
// 	    return new MapParser<>(this, fn);
// 	}
// 	default <U> Parser<U> flatMap(Function1<T, Parser<U>> fn) {
// 		return new FlatMapParser<>(this, fn);
// 	}
// 	default Parser<Optional<T>> option() { return new OptionParser<T>(this); }
// 	default Parser<List<T>> many() {
// 		return new ManyParser<T>(this);
// 	}
// 	default Parser<List<T>> many1() {
// 		return new Many1Parser<T>(this);
// 	}
// 	default Parser<T> chain(Parser<Function2<T, T, T>> q) {
// 		return this.cat(q.cat(this).many()).map(t -> t.extract((init, list) -> {
// 			return foldLeft(list, init, ts -> {
// 				T a = ts.item1();
// 				return let(ts.item2().item1(), f -> {
// 					return let(ts.item2().item2(), b -> {
// 						return f.invoke(a, b);
// 					});
// 				});
// 			});
// 		}));
// 	}
// 	default Parser<T> not() { return new Not<>(this); }
// 	default Parser<T> and() { return new And<>(this); }
// 	static Parser<String> any() { return new AnyParser(); }
// 	static Parser<String> string(String literal) {
// 	    return new StringParser(literal);
// 	}
// 	static <T> Rule<T> rule(Function0<Parser<T>> body) {
// 		return new Rule<>(body);
// 	}
// 	static Parser<String> eof() {
// 		return new EOFParser();
// 	}
// 	static RangeParser range(char from, char to) {
// 		return new RangeParser(from, to);
// 	}
// 	static SetParser set(char... characters) {
// 		java.util.Set<Character> set = new java.util.HashSet<>();
// 		for(char ch:characters) {
// 		    set.add(ch);
// 		}
// 		return new SetParser(set);
// 	}
// 	static Parser<String> alphabet() {
// 		return range('a', 'z').or(range('A', 'Z'));
// 	}
// 	static Parser<String> digit() {
// 		return range('0', '9');
// 	}
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/Functions.java
// public class Functions {
// 
//     public static <T, U> U let(T value, Function1<T, U> fn) {
//         return fn.invoke(value);
//     }
// 
//     public static <T> void let(T value, Procedure1<T> pr) {
//         pr.invoke(value);
//     }
//     
//     public static <T, U> U foldLeft(List<T> list, U init, Function1<Tuple2<U, T>, U> f) {
//     	U result = init;
//     	for(T t:list) {
//     		result = f.invoke(new Tuple2<>(result, t));
//     	}
//     	return result;
//     }
//     
//     public static <T> String join(List<T> list, String separator) {
//     	if(list.size() == 0) {
//     		return "";
//     	} else {
//     		return let(new StringBuilder(), builder -> {
//     		    T t = list.get(0);
//     		    List<T> es = list.subList(1, list.size());
//     			builder.append(t.toString());
//     			for(T e:es) {
//     				builder.append(separator);
//     				builder.append(e.toString());
//     			}
//     			return new String(builder);
//     		});
//     	}
//     }
// }


// Path: src/test/java/com/github/kmizu/jcombinator/ChainlTest.java
import com.github.kmizu.jcombinator.datatype.Function2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.junit.Assert.*;
import static com.github.kmizu.jcombinator.Parser.*;
import static com.github.kmizu.jcombinator.Functions.*;

package com.github.kmizu.jcombinator;




@RunWith(JUnit4.class)
public class ChainlTest {
	private Rule<Integer> expression() {
	    return rule(() ->
			additive().cat(eof()).map(t -> t.extract((result, __) -> result))
		);
	}
	private Rule<Integer> additive() {
		return rule(() -> {
			final Parser<Function2<Integer, Integer, Integer>> Q = string("+").map(op -> (Integer lhs, Integer rhs) -> lhs + rhs);
			final Parser<Function2<Integer, Integer, Integer>> R = string("-").map(op -> (Integer lhs, Integer rhs) -> lhs - rhs);