mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
[functional] Unify functional operators
This commit is contained in:
parent
110aa6264a
commit
2de94d94d5
@ -20,16 +20,16 @@ class StreamValue extends MapValue {
|
|||||||
set("map", wrapIntermediate(new functional_map()));
|
set("map", wrapIntermediate(new functional_map()));
|
||||||
set("flatMap", wrapIntermediate(new functional_flatmap()));
|
set("flatMap", wrapIntermediate(new functional_flatmap()));
|
||||||
set("sorted", this::sorted);
|
set("sorted", this::sorted);
|
||||||
set("sortBy", wrapIntermediate(new functional_sortby()));
|
set("sortBy", wrapIntermediate(new functional_sortBy()));
|
||||||
set("takeWhile", wrapIntermediate(new functional_takeWhile()));
|
set("takeWhile", wrapIntermediate(new functional_takeWhile()));
|
||||||
set("dropWhile", wrapIntermediate(new functional_dropwhile()));
|
set("dropWhile", wrapIntermediate(new functional_dropWhile()));
|
||||||
set("peek", wrapIntermediate(new functional_foreach()));
|
set("peek", wrapIntermediate(new functional_forEach()));
|
||||||
set("skip", this::skip);
|
set("skip", this::skip);
|
||||||
set("limit", this::limit);
|
set("limit", this::limit);
|
||||||
set("custom", this::custom);
|
set("custom", this::custom);
|
||||||
|
|
||||||
set("reduce", wrapTerminal(new functional_reduce()));
|
set("reduce", wrapTerminal(new functional_reduce()));
|
||||||
set("forEach", wrapTerminal(new functional_foreach()));
|
set("forEach", wrapTerminal(new functional_forEach()));
|
||||||
set("toArray", args -> container);
|
set("toArray", args -> container);
|
||||||
set("joining", container::joinToString);
|
set("joining", container::joinToString);
|
||||||
set("count", args -> NumberValue.of(container.size()));
|
set("count", args -> NumberValue.of(container.size()));
|
||||||
|
@ -19,14 +19,14 @@ public final class functional implements Module {
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Function> functions() {
|
public Map<String, Function> functions() {
|
||||||
final var result = new HashMap<String, Function>(15);
|
final var result = new HashMap<String, Function>(15);
|
||||||
result.put("foreach", new functional_foreach());
|
result.put("foreach", new functional_forEach());
|
||||||
result.put("map", new functional_map());
|
result.put("map", new functional_map());
|
||||||
result.put("flatmap", new functional_flatmap());
|
result.put("flatmap", new functional_flatmap());
|
||||||
result.put("reduce", new functional_reduce());
|
result.put("reduce", new functional_reduce());
|
||||||
result.put("filter", new functional_filter());
|
result.put("filter", new functional_filter());
|
||||||
result.put("sortby", new functional_sortby());
|
result.put("sortby", new functional_sortBy());
|
||||||
result.put("takewhile", new functional_takeWhile());
|
result.put("takewhile", new functional_takeWhile());
|
||||||
result.put("dropwhile", new functional_dropwhile());
|
result.put("dropwhile", new functional_dropWhile());
|
||||||
|
|
||||||
result.put("chain", new functional_chain());
|
result.put("chain", new functional_chain());
|
||||||
result.put("stream", new functional_stream());
|
result.put("stream", new functional_stream());
|
||||||
|
@ -9,20 +9,24 @@ import com.annimon.ownlang.lib.Types;
|
|||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.lib.Value;
|
||||||
import com.annimon.ownlang.lib.ValueUtils;
|
import com.annimon.ownlang.lib.ValueUtils;
|
||||||
|
|
||||||
public final class functional_dropwhile implements Function {
|
public final class functional_dropWhile implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value execute(Value[] args) {
|
public Value execute(Value[] args) {
|
||||||
Arguments.check(2, args.length);
|
Arguments.check(2, args.length);
|
||||||
if (args[0].type() != Types.ARRAY) {
|
|
||||||
throw new TypeException("Array expected in first argument");
|
|
||||||
}
|
|
||||||
final Value container = args[0];
|
final Value container = args[0];
|
||||||
final Function predicate = ValueUtils.consumeFunction(args[1], 1);
|
final Function predicate = ValueUtils.consumeFunction(args[1], 1);
|
||||||
|
return dropWhile(container, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ArrayValue dropWhile(Value container, Function predicate) {
|
||||||
|
if (container.type() != Types.ARRAY) {
|
||||||
|
throw new TypeException("Array expected in first argument");
|
||||||
|
}
|
||||||
return dropWhileArray((ArrayValue) container, predicate);
|
return dropWhileArray((ArrayValue) container, predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value dropWhileArray(ArrayValue array, Function predicate) {
|
static ArrayValue dropWhileArray(ArrayValue array, Function predicate) {
|
||||||
int skipCount = 0;
|
int skipCount = 0;
|
||||||
for (Value value : array) {
|
for (Value value : array) {
|
||||||
if (predicate.execute(value) != NumberValue.ZERO)
|
if (predicate.execute(value) != NumberValue.ZERO)
|
@ -15,14 +15,19 @@ public final class functional_flatmap implements Function {
|
|||||||
@Override
|
@Override
|
||||||
public Value execute(Value[] args) {
|
public Value execute(Value[] args) {
|
||||||
Arguments.check(2, args.length);
|
Arguments.check(2, args.length);
|
||||||
if (args[0].type() != Types.ARRAY) {
|
final Value container = args[0];
|
||||||
throw new TypeException("Array expected in first argument");
|
|
||||||
}
|
|
||||||
final Function mapper = ValueUtils.consumeFunction(args[1], 1);
|
final Function mapper = ValueUtils.consumeFunction(args[1], 1);
|
||||||
return flatMapArray((ArrayValue) args[0], mapper);
|
return flatMap(container, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value flatMapArray(ArrayValue array, Function mapper) {
|
static Value flatMap(Value container, Function mapper) {
|
||||||
|
if (container.type() != Types.ARRAY) {
|
||||||
|
throw new TypeException("Array expected in first argument");
|
||||||
|
}
|
||||||
|
return flatMapArray((ArrayValue) container, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value flatMapArray(ArrayValue array, Function mapper) {
|
||||||
final List<Value> values = new ArrayList<>();
|
final List<Value> values = new ArrayList<>();
|
||||||
final int size = array.size();
|
final int size = array.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.annimon.ownlang.modules.functional;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.exceptions.TypeException;
|
||||||
|
import com.annimon.ownlang.lib.*;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class functional_forEach implements Function {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value execute(Value[] args) {
|
||||||
|
Arguments.check(2, args.length);
|
||||||
|
final Value container = args[0];
|
||||||
|
final Function consumer = ValueUtils.consumeFunction(args[1], 1);
|
||||||
|
return forEach(container, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value forEach(Value container, Function consumer) {
|
||||||
|
final int argsCount = consumer.getArgsCount();
|
||||||
|
return switch (container.type()) {
|
||||||
|
case Types.STRING -> forEachString((StringValue) container, argsCount, consumer);
|
||||||
|
case Types.ARRAY -> forEachArray((ArrayValue) container, argsCount, consumer);
|
||||||
|
case Types.MAP -> forEachMap((MapValue) container, consumer);
|
||||||
|
default -> throw new TypeException("Cannot iterate " + Types.typeToString(container.type()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringValue forEachString(StringValue string, int argsCount, Function consumer) {
|
||||||
|
if (argsCount == 2) {
|
||||||
|
for (char ch : string.asString().toCharArray()) {
|
||||||
|
consumer.execute(new StringValue(String.valueOf(ch)), NumberValue.of(ch));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (char ch : string.asString().toCharArray()) {
|
||||||
|
consumer.execute(new StringValue(String.valueOf(ch)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ArrayValue forEachArray(ArrayValue array, int argsCount, Function consumer) {
|
||||||
|
if (argsCount == 2) {
|
||||||
|
int index = 0;
|
||||||
|
for (Value element : array) {
|
||||||
|
consumer.execute(element, NumberValue.of(index++));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Value element : array) {
|
||||||
|
consumer.execute(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MapValue forEachMap(MapValue map, Function consumer) {
|
||||||
|
for (Map.Entry<Value, Value> element : map) {
|
||||||
|
consumer.execute(element.getKey(), element.getValue());
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
package com.annimon.ownlang.modules.functional;
|
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.TypeException;
|
|
||||||
import com.annimon.ownlang.lib.*;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class functional_foreach implements Function {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Value execute(Value[] args) {
|
|
||||||
Arguments.check(2, args.length);
|
|
||||||
final Value container = args[0];
|
|
||||||
final Function consumer = ValueUtils.consumeFunction(args[1], 1);
|
|
||||||
final int argsCount = consumer.getArgsCount();
|
|
||||||
|
|
||||||
switch (container.type()) {
|
|
||||||
case Types.STRING:
|
|
||||||
final StringValue string = (StringValue) container;
|
|
||||||
if (argsCount == 2) {
|
|
||||||
for (char ch : string.asString().toCharArray()) {
|
|
||||||
consumer.execute(new StringValue(String.valueOf(ch)), NumberValue.of(ch));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (char ch : string.asString().toCharArray()) {
|
|
||||||
consumer.execute(new StringValue(String.valueOf(ch)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string;
|
|
||||||
|
|
||||||
case Types.ARRAY:
|
|
||||||
final ArrayValue array = (ArrayValue) container;
|
|
||||||
if (argsCount == 2) {
|
|
||||||
int index = 0;
|
|
||||||
for (Value element : array) {
|
|
||||||
consumer.execute(element, NumberValue.of(index++));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (Value element : array) {
|
|
||||||
consumer.execute(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
|
|
||||||
case Types.MAP:
|
|
||||||
final MapValue map = (MapValue) container;
|
|
||||||
for (Map.Entry<Value, Value> element : map) {
|
|
||||||
consumer.execute(element.getKey(), element.getValue());
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new TypeException("Cannot iterate " + Types.typeToString(container.type()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,7 +31,7 @@ public final class functional_map implements Function {
|
|||||||
throw new TypeException("Invalid first argument. Array or map expected");
|
throw new TypeException("Invalid first argument. Array or map expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value mapArray(ArrayValue array, Function mapper) {
|
static ArrayValue mapArray(ArrayValue array, Function mapper) {
|
||||||
final int size = array.size();
|
final int size = array.size();
|
||||||
final ArrayValue result = new ArrayValue(size);
|
final ArrayValue result = new ArrayValue(size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@ -40,7 +40,7 @@ public final class functional_map implements Function {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value mapMap(MapValue map, Function keyMapper, Function valueMapper) {
|
static MapValue mapMap(MapValue map, Function keyMapper, Function valueMapper) {
|
||||||
final MapValue result = new MapValue(map.size());
|
final MapValue result = new MapValue(map.size());
|
||||||
for (Map.Entry<Value, Value> element : map) {
|
for (Map.Entry<Value, Value> element : map) {
|
||||||
final Value newKey = keyMapper.execute(element.getKey());
|
final Value newKey = keyMapper.execute(element.getKey());
|
||||||
|
@ -19,22 +19,32 @@ public final class functional_reduce implements Function {
|
|||||||
final Value container = args[0];
|
final Value container = args[0];
|
||||||
final Value identity = args[1];
|
final Value identity = args[1];
|
||||||
final Function accumulator = ValueUtils.consumeFunction(args[2], 2);
|
final Function accumulator = ValueUtils.consumeFunction(args[2], 2);
|
||||||
|
return reduce(container, identity, accumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value reduce(Value container, Value identity, Function accumulator) {
|
||||||
if (container.type() == Types.ARRAY) {
|
if (container.type() == Types.ARRAY) {
|
||||||
|
return reduceArray(identity, (ArrayValue) container, accumulator);
|
||||||
|
}
|
||||||
|
if (container.type() == Types.MAP) {
|
||||||
|
return reduceMap(identity, (MapValue) container, accumulator);
|
||||||
|
}
|
||||||
|
throw new TypeException("Invalid first argument. Array or map expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value reduceArray(Value identity, ArrayValue array, Function accumulator) {
|
||||||
Value result = identity;
|
Value result = identity;
|
||||||
final ArrayValue array = (ArrayValue) container;
|
|
||||||
for (Value element : array) {
|
for (Value element : array) {
|
||||||
result = accumulator.execute(result, element);
|
result = accumulator.execute(result, element);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (container.type() == Types.MAP) {
|
|
||||||
|
static Value reduceMap(Value identity, MapValue map, Function accumulator) {
|
||||||
Value result = identity;
|
Value result = identity;
|
||||||
final MapValue map = (MapValue) container;
|
|
||||||
for (Map.Entry<Value, Value> element : map) {
|
for (Map.Entry<Value, Value> element : map) {
|
||||||
result = accumulator.execute(result, element.getKey(), element.getValue());
|
result = accumulator.execute(result, element.getKey(), element.getValue());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw new TypeException("Invalid first argument. Array or map expected");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import com.annimon.ownlang.lib.ValueUtils;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public final class functional_sortby implements Function {
|
public final class functional_sortBy implements Function {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value execute(Value[] args) {
|
public Value execute(Value[] args) {
|
Loading…
Reference in New Issue
Block a user