annotate src/main/java/fj/data/IOFunctions.java @ 0:fe80c1edf1be

add getLoop
author tatsuki
date Fri, 20 Mar 2015 21:04:03 +0900
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
1 package fj.data;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
2
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
3 import static fj.Bottom.errorF;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
4 import static fj.Function.constant;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
5 import static fj.Function.partialApply2;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
6
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
7 import java.io.BufferedReader;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
8 import java.io.File;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
9 import java.io.FileInputStream;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
10 import java.io.IOException;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
11 import java.io.InputStreamReader;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
12 import java.io.Reader;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
13 import java.nio.charset.Charset;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
14 import java.util.Arrays;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
15
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
16 import fj.*;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
17 import fj.data.Iteratee.Input;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
18 import fj.data.Iteratee.IterV;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
19 import fj.function.Try0;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
20
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
21 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
22 * IO monad for processing files, with main methods {@link #enumFileLines },
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
23 * {@link #enumFileChars} and {@link #enumFileCharChunks}
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
24 * (the latter one is the fastest as char chunks read from the file are directly passed to the iteratee
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
25 * without indirection in between).
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
26 *
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
27 * @author Martin Grotzke
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
28 *
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
29 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
30 public class IOFunctions {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
31
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
32 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
33
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
34 public static <A> Try0<A, IOException> toTry(IO<A> io) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
35 return () -> io.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
36 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
37
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
38 public static <A> P1<Validation<IOException, A>> p(IO<A> io) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
39 return Try.f(toTry(io));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
40 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
41
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
42 public static <A> IO<A> io(P1<A> p) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
43 return () -> p._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
44 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
45
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
46 public static <A> IO<A> io(Try0<A, ? extends IOException> t) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
47 return () -> t.f();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
48 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
49
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
50 public static final F<Reader, IO<Unit>> closeReader =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
51 new F<Reader, IO<Unit>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
52 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
53 public IO<Unit> f(final Reader r) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
54 return closeReader(r);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
55 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
56 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
57
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
58 public static IO<Unit> closeReader(final Reader r) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
59 return new IO<Unit>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
60 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
61 public Unit run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
62 r.close();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
63 return Unit.unit();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
64 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
65 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
66 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
67
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
68 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
69 * An IO monad that reads lines from the given file (using a {@link BufferedReader}) and passes
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
70 * lines to the provided iteratee. May not be suitable for files with very long
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
71 * lines, consider to use {@link #enumFileCharChunks} or {@link #enumFileChars}
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
72 * as an alternative.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
73 *
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
74 * @param f the file to read, must not be <code>null</code>
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
75 * @param encoding the encoding to use, {@link Option#none()} means platform default
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
76 * @param i the iteratee that is fed with lines read from the file
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
77 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
78 public static <A> IO<IterV<String, A>> enumFileLines(final File f, final Option<Charset> encoding, final IterV<String, A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
79 return bracket(bufferedReader(f, encoding)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
80 , Function.<BufferedReader, IO<Unit>>vary(closeReader)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
81 , partialApply2(IOFunctions.<A>lineReader(), i));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
82 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
83
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
84 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
85 * An IO monad that reads char chunks from the given file and passes them to the given iteratee.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
86 *
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
87 * @param f the file to read, must not be <code>null</code>
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
88 * @param encoding the encoding to use, {@link Option#none()} means platform default
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
89 * @param i the iteratee that is fed with char chunks read from the file
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
90 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
91 public static <A> IO<IterV<char[], A>> enumFileCharChunks(final File f, final Option<Charset> encoding, final IterV<char[], A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
92 return bracket(fileReader(f, encoding)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
93 , Function.<Reader, IO<Unit>>vary(closeReader)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
94 , partialApply2(IOFunctions.<A>charChunkReader(), i));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
95 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
96
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
97 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
98 * An IO monad that reads char chunks from the given file and passes single chars to the given iteratee.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
99 *
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
100 * @param f the file to read, must not be <code>null</code>
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
101 * @param encoding the encoding to use, {@link Option#none()} means platform default
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
102 * @param i the iteratee that is fed with chars read from the file
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
103 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
104 public static <A> IO<IterV<Character, A>> enumFileChars(final File f, final Option<Charset> encoding, final IterV<Character, A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
105 return bracket(fileReader(f, encoding)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
106 , Function.<Reader, IO<Unit>>vary(closeReader)
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
107 , partialApply2(IOFunctions.<A>charChunkReader2(), i));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
108 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
109
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
110 public static IO<BufferedReader> bufferedReader(final File f, final Option<Charset> encoding) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
111 return IOFunctions.map(fileReader(f, encoding), new F<Reader, BufferedReader>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
112 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
113 public BufferedReader f(final Reader a) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
114 return new BufferedReader(a);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
115 }});
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
116 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
117
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
118 public static IO<Reader> fileReader(final File f, final Option<Charset> encoding) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
119 return new IO<Reader>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
120 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
121 public Reader run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
122 final FileInputStream fis = new FileInputStream(f);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
123 return encoding.isNone() ? new InputStreamReader(fis) : new InputStreamReader(fis, encoding.some());
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
124 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
125 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
126 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
127
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
128 public static final <A, B, C> IO<C> bracket(final IO<A> init, final F<A, IO<B>> fin, final F<A, IO<C>> body) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
129 return new IO<C>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
130 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
131 public C run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
132 final A a = init.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
133 try {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
134 return body.f(a).run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
135 } catch (final IOException e) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
136 throw e;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
137 } finally {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
138 fin.f(a);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
139 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
140 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
141 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
142 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
143
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
144 public static final <A> IO<A> unit(final A a) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
145 return new IO<A>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
146 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
147 public A run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
148 return a;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
149 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
150 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
151 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
152
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
153 public static final <A> IO<A> lazy(final P1<A> p) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
154 return () -> p._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
155 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
156
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
157 public static final <A> IO<A> lazy(final F<Unit, A> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
158 return () -> f.f(Unit.unit());
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
159 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
160
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
161 public static final <A> SafeIO<A> lazySafe(final F<Unit, A> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
162 return () -> f.f(Unit.unit());
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
163 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
164
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
165 public static final <A> SafeIO<A> lazySafe(final P1<A> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
166 return () -> f._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
167 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
168
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
169 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
170 * A function that feeds an iteratee with lines read from a {@link BufferedReader}.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
171 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
172 public static <A> F<BufferedReader, F<IterV<String, A>, IO<IterV<String, A>>>> lineReader() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
173 final F<IterV<String, A>, Boolean> isDone =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
174 new F<Iteratee.IterV<String, A>, Boolean>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
175 final F<P2<A, Input<String>>, P1<Boolean>> done = constant(P.p(true));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
176 final F<F<Input<String>, IterV<String, A>>, P1<Boolean>> cont = constant(P.p(false));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
177
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
178 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
179 public Boolean f(final IterV<String, A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
180 return i.fold(done, cont)._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
181 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
182 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
183
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
184 return new F<BufferedReader, F<IterV<String, A>, IO<IterV<String, A>>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
185 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
186 public F<IterV<String, A>, IO<IterV<String, A>>> f(final BufferedReader r) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
187 return new F<IterV<String, A>, IO<IterV<String, A>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
188 final F<P2<A, Input<String>>, P1<IterV<String, A>>> done = errorF("iteratee is done"); //$NON-NLS-1$
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
189
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
190 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
191 public IO<IterV<String, A>> f(final IterV<String, A> it) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
192 // use loop instead of recursion because of missing TCO
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
193 return new IO<Iteratee.IterV<String, A>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
194 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
195 public IterV<String, A> run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
196 IterV<String, A> i = it;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
197 while (!isDone.f(i)) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
198 final String s = r.readLine();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
199 if (s == null) { return i; }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
200 final Input<String> input = Input.<String>el(s);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
201 final F<F<Input<String>, IterV<String, A>>, P1<IterV<String, A>>> cont = F1Functions.lazy(Function.<Input<String>, IterV<String, A>>apply(input));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
202 i = i.fold(done, cont)._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
203 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
204 return i;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
205 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
206 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
207 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
208 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
209 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
210 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
211 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
212
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
213 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
214 * A function that feeds an iteratee with character chunks read from a {@link Reader}
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
215 * (char[] of size {@link #DEFAULT_BUFFER_SIZE}).
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
216 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
217 public static <A> F<Reader, F<IterV<char[], A>, IO<IterV<char[], A>>>> charChunkReader() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
218 final F<IterV<char[], A>, Boolean> isDone =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
219 new F<Iteratee.IterV<char[], A>, Boolean>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
220 final F<P2<A, Input<char[]>>, P1<Boolean>> done = constant(P.p(true));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
221 final F<F<Input<char[]>, IterV<char[], A>>, P1<Boolean>> cont = constant(P.p(false));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
222
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
223 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
224 public Boolean f(final IterV<char[], A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
225 return i.fold(done, cont)._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
226 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
227 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
228
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
229 return new F<Reader, F<IterV<char[], A>, IO<IterV<char[], A>>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
230 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
231 public F<IterV<char[], A>, IO<IterV<char[], A>>> f(final Reader r) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
232 return new F<IterV<char[], A>, IO<IterV<char[], A>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
233 final F<P2<A, Input<char[]>>, P1<IterV<char[], A>>> done = errorF("iteratee is done"); //$NON-NLS-1$
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
234
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
235 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
236 public IO<IterV<char[], A>> f(final IterV<char[], A> it) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
237 // use loop instead of recursion because of missing TCO
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
238 return new IO<Iteratee.IterV<char[], A>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
239 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
240 public IterV<char[], A> run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
241
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
242 IterV<char[], A> i = it;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
243 while (!isDone.f(i)) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
244 char[] buffer = new char[DEFAULT_BUFFER_SIZE];
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
245 final int numRead = r.read(buffer);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
246 if (numRead == -1) { return i; }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
247 if(numRead < buffer.length) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
248 buffer = Arrays.copyOfRange(buffer, 0, numRead);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
249 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
250 final Input<char[]> input = Input.<char[]>el(buffer);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
251 final F<F<Input<char[]>, IterV<char[], A>>, P1<IterV<char[], A>>> cont =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
252 F1Functions.lazy(Function.<Input<char[]>, IterV<char[], A>>apply(input));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
253 i = i.fold(done, cont)._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
254 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
255 return i;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
256 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
257 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
258 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
259 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
260 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
261 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
262 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
263
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
264 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
265 * A function that feeds an iteratee with characters read from a {@link Reader}
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
266 * (chars are read in chunks of size {@link #DEFAULT_BUFFER_SIZE}).
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
267 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
268 public static <A> F<Reader, F<IterV<Character, A>, IO<IterV<Character, A>>>> charChunkReader2() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
269 final F<IterV<Character, A>, Boolean> isDone =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
270 new F<Iteratee.IterV<Character, A>, Boolean>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
271 final F<P2<A, Input<Character>>, P1<Boolean>> done = constant(P.p(true));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
272 final F<F<Input<Character>, IterV<Character, A>>, P1<Boolean>> cont = constant(P.p(false));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
273
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
274 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
275 public Boolean f(final IterV<Character, A> i) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
276 return i.fold(done, cont)._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
277 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
278 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
279
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
280 return new F<Reader, F<IterV<Character, A>, IO<IterV<Character, A>>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
281 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
282 public F<IterV<Character, A>, IO<IterV<Character, A>>> f(final Reader r) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
283 return new F<IterV<Character, A>, IO<IterV<Character, A>>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
284 final F<P2<A, Input<Character>>, IterV<Character, A>> done = errorF("iteratee is done"); //$NON-NLS-1$
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
285
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
286 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
287 public IO<IterV<Character, A>> f(final IterV<Character, A> it) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
288 // use loop instead of recursion because of missing TCO
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
289 return new IO<Iteratee.IterV<Character, A>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
290 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
291 public IterV<Character, A> run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
292
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
293 IterV<Character, A> i = it;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
294 while (!isDone.f(i)) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
295 char[] buffer = new char[DEFAULT_BUFFER_SIZE];
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
296 final int numRead = r.read(buffer);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
297 if (numRead == -1) { return i; }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
298 if(numRead < buffer.length) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
299 buffer = Arrays.copyOfRange(buffer, 0, numRead);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
300 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
301 for(int c = 0; c < buffer.length; c++) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
302 final Input<Character> input = Input.el(buffer[c]);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
303 final F<F<Input<Character>, IterV<Character, A>>, IterV<Character, A>> cont =
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
304 Function.<Input<Character>, IterV<Character, A>>apply(input);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
305 i = i.fold(done, cont);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
306 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
307 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
308 return i;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
309 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
310 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
311 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
312 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
313 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
314 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
315 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
316
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
317 public static final <A, B> IO<B> map(final IO<A> io, final F<A, B> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
318 return new IO<B>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
319 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
320 public B run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
321 return f.f(io.run());
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
322 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
323 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
324 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
325
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
326 public static final <A, B> IO<B> bind(final IO<A> io, final F<A, IO<B>> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
327 return new IO<B>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
328 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
329 public B run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
330 return f.f(io.run()).run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
331 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
332 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
333 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
334
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
335 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
336 * Evaluate each action in the sequence from left to right, and collect the results.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
337 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
338 public static <A> IO<List<A>> sequence(List<IO<A>> list) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
339 F2<IO<A>, IO<List<A>>, IO<List<A>>> f2 = (io, ioList) ->
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
340 IOFunctions.bind(ioList, (xs) -> map(io, x -> List.cons(x, xs)));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
341 return list.foldRight(f2, IOFunctions.unit(List.<A>nil()));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
342 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
343
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
344
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
345 public static <A> IO<Stream<A>> sequence(Stream<IO<A>> stream) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
346 F2<IO<Stream<A>>, IO<A>, IO<Stream<A>>> f2 = (ioList, io) ->
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
347 IOFunctions.bind(ioList, (xs) -> map(io, x -> Stream.cons(x, P.lazy(u -> xs))));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
348 return stream.foldLeft(f2, IOFunctions.unit(Stream.<A>nil()));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
349 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
350
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
351
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
352 /**
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
353 * Map each element of a structure to an action, evaluate these actions from left to right
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
354 * and collect the results.
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
355 */
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
356 public static <A, B> IO<List<B>> traverse(List<A> list, F<A, IO<B>> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
357 F2<A, IO<List<B>>, IO<List<B>>> f2 = (a, acc) ->
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
358 bind(acc, (bs) -> map(f.f(a), b -> bs.append(List.list(b))));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
359 return list.foldRight(f2, IOFunctions.unit(List.<B>nil()));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
360 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
361
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
362 public static <A> IO<A> join(IO<IO<A>> io1) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
363 return bind(io1, io2 -> io2);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
364 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
365
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
366 public static <A> SafeIO<Validation<IOException, A>> toSafeIO(IO<A> io) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
367 return () -> Try.f(() -> io.run())._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
368 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
369
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
370 public static <A, B> IO<B> append(final IO<A> io1, final IO<B> io2) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
371 return () -> {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
372 io1.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
373 return io2.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
374 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
375 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
376
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
377 public static <A, B> IO<A> left(final IO<A> io1, final IO<B> io2) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
378 return () -> {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
379 A a = io1.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
380 io2.run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
381 return a;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
382 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
383 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
384
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
385 public static <A, B> IO<B> flatMap(final IO<A> io, final F<A, IO<B>> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
386 return bind(io, f);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
387 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
388
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
389 static <A> IO<Stream<A>> sequenceWhile(final Stream<IO<A>> stream, final F<A, Boolean> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
390 return new IO<Stream<A>>() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
391 @Override
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
392 public Stream<A> run() throws IOException {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
393 boolean loop = true;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
394 Stream<IO<A>> input = stream;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
395 Stream<A> result = Stream.<A>nil();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
396 while (loop) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
397 if (input.isEmpty()) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
398 loop = false;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
399 } else {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
400 A a = input.head().run();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
401 if (!f.f(a)) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
402 loop = false;
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
403 } else {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
404 input = input.tail()._1();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
405 result = result.cons(a);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
406 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
407 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
408 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
409 return result.reverse();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
410 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
411 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
412 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
413
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
414 public static <A, B> IO<B> apply(IO<A> io, IO<F<A, B>> iof) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
415 return bind(iof, f -> map(io, a -> f.f(a)));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
416 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
417
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
418 public static <A, B, C> IO<C> liftM2(IO<A> ioa, IO<B> iob, F2<A, B, C> f) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
419 return bind(ioa, a -> map(iob, b -> f.f(a, b)));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
420 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
421
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
422 public static <A> IO<List<A>> replicateM(IO<A> ioa, int n) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
423 return sequence(List.replicate(n, ioa));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
424 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
425
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
426 public static <A> IO<State<BufferedReader, Validation<IOException, String>>> readerState() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
427 return () -> State.unit((BufferedReader r) -> P.p(r, Try.f((BufferedReader r2) -> r2.readLine()).f(r)));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
428 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
429
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
430 public static final BufferedReader stdinBufferedReader = new BufferedReader(new InputStreamReader(System.in));
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
431
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
432 public static IO<String> stdinReadLine() {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
433 return () -> stdinBufferedReader.readLine();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
434 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
435
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
436 public static IO<Unit> stdoutPrintln(final String s) {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
437 return () -> {
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
438 System.out.println(s);
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
439 return Unit.unit();
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
440 };
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
441 }
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
442
fe80c1edf1be add getLoop
tatsuki
parents:
diff changeset
443 }