Модуль functional с функциональными операторами для данных

This commit is contained in:
Victor 2016-01-09 21:21:17 +02:00
parent 1fd2dd8e87
commit 89d48f7737
9 changed files with 213 additions and 1 deletions

View File

@ -1,5 +1,7 @@
use "math" use "math"
use "std" use "std"
use "functional"
word = 2 + 2 word = 2 + 2
word2 = PI + word word2 = PI + word
str = "a" * 5 + "ba" * 7 + "\n" str = "a" * 5 + "ba" * 7 + "\n"
@ -117,3 +119,9 @@ thread(::inthread)
def inthread() = echo("this is a thread") def inthread() = echo("this is a thread")
thread(def (str) { println str }, "this is a thread with arguments") thread(def (str) { println str }, "this is a thread with arguments")
println "functional"
nums = [1,2,3,4,5,6,7,8,9,10]
nums = filter(nums, def(x) = x % 2 == 0)
squares = map(nums, def(x) = x * x)
foreach(squares, ::echo)
println "Sum: " + reduce(squares, 0, def(x, y) = x + y)

View File

@ -47,6 +47,10 @@ public final class ArrayValue implements Value, Iterable<Value> {
return Types.ARRAY; return Types.ARRAY;
} }
public int size() {
return elements.length;
}
public Value get(int index) { public Value get(int index) {
return elements[index]; return elements[index];
} }

View File

@ -26,6 +26,10 @@ public class MapValue implements Value, Iterable<Map.Entry<Value, Value>> {
return Types.MAP; return Types.MAP;
} }
public int size() {
return map.size();
}
public Value get(Value key) { public Value get(Value key) {
return map.get(key); return map.get(key);
} }

View File

@ -0,0 +1,19 @@
package com.annimon.ownlang.lib.modules;
import com.annimon.ownlang.lib.*;
import com.annimon.ownlang.lib.modules.functions.*;
/**
*
* @author aNNiMON
*/
public final class functional implements Module {
@Override
public void init() {
Functions.set("foreach", new functional_foreach());
Functions.set("map", new functional_map());
Functions.set("reduce", new functional_reduce());
Functions.set("filter", new functional_filter());
}
}

View File

@ -0,0 +1,52 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public final class functional_filter implements Function {
@Override
public Value execute(Value... args) {
if (args.length < 2) throw new RuntimeException("At least two args expected");
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
final Value container = args[0];
final Function consumer = ((FunctionValue) args[1]).getValue();
if (container.type() == Types.ARRAY) {
return filterArray((ArrayValue) container, consumer);
}
if (container.type() == Types.MAP) {
return filterMap((MapValue) container, consumer);
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
}
private Value filterArray(ArrayValue array, Function predicate) {
final int size = array.size();
final List<Value> values = new ArrayList<Value>(size);
for (Value value : array) {
if (predicate.execute(value) != NumberValue.ZERO) {
values.add(value);
}
}
final int newSize = values.size();
return new ArrayValue(values.toArray(new Value[newSize]));
}
private Value filterMap(MapValue map, Function predicate) {
final MapValue result = new MapValue(map.size());
for (Map.Entry<Value, Value> element : map) {
if (predicate.execute(element.getKey(), element.getValue()) != NumberValue.ZERO) {
result.set(element.getKey(), element.getValue());
}
}
return result;
}
}

View File

@ -0,0 +1,34 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Map;
public final class functional_foreach implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 2) throw new RuntimeException("Two args expected");
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
final Value container = args[0];
final Function consumer = ((FunctionValue) args[1]).getValue();
if (container.type() == Types.ARRAY) {
final ArrayValue array = (ArrayValue) container;
for (Value element : array) {
consumer.execute(element);
}
return NumberValue.ZERO;
}
if (container.type() == Types.MAP) {
final MapValue map = (MapValue) container;
for (Map.Entry<Value, Value> element : map) {
consumer.execute(element.getKey(), element.getValue());
}
return NumberValue.ZERO;
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
}
}

View File

@ -0,0 +1,55 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Map;
public final class functional_map implements Function {
@Override
public Value execute(Value... args) {
if (args.length < 2) throw new RuntimeException("At least two args expected");
final Value container = args[0];
if (container.type() == Types.ARRAY) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
final Function mapper = ((FunctionValue) args[1]).getValue();
return mapArray((ArrayValue) container, mapper);
}
if (container.type() == Types.MAP) {
if (args[1].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in second arg");
}
if (args[2].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in third arg");
}
final Function keyMapper = ((FunctionValue) args[1]).getValue();
final Function valueMapper = ((FunctionValue) args[2]).getValue();
return mapMap((MapValue) container, keyMapper, valueMapper);
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
}
private Value mapArray(ArrayValue array, Function mapper) {
final int size = array.size();
final ArrayValue result = new ArrayValue(size);
for (int i = 0; i < size; i++) {
result.set(i, mapper.execute(array.get(i)));
}
return result;
}
private Value mapMap(MapValue map, Function keyMapper, Function valueMapper) {
final MapValue result = new MapValue(map.size());
for (Map.Entry<Value, Value> element : map) {
final Value newKey = keyMapper.execute(element.getKey());
final Value newValue = valueMapper.execute(element.getValue());
result.set(newKey, newValue);
}
return result;
}
}

View File

@ -0,0 +1,37 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Map;
public final class functional_reduce implements Function {
@Override
public Value execute(Value... args) {
if (args.length != 3) throw new RuntimeException("Three args expected");
if (args[2].type() != Types.FUNCTION) {
throw new RuntimeException("Function expected in third arg");
}
final Value container = args[0];
final Value identity = args[1];
final Function accumulator = ((FunctionValue) args[2]).getValue();
if (container.type() == Types.ARRAY) {
Value result = identity;
final ArrayValue array = (ArrayValue) container;
for (Value element : array) {
result = accumulator.execute(result, element);
}
return result;
}
if (container.type() == Types.MAP) {
Value result = identity;
final MapValue map = (MapValue) container;
for (Map.Entry<Value, Value> element : map) {
result = accumulator.execute(result, element.getKey(), element.getValue());
}
return result;
}
throw new RuntimeException("Invalid first argument. Array or map exprected");
}
}

View File

@ -12,7 +12,6 @@ public final class std implements Module {
@Override @Override
public void init() { public void init() {
Functions.set("echo", new std_echo()); Functions.set("echo", new std_echo());
Functions.set("foreach", new std_foreach());
Functions.set("newarray", new std_newarray()); Functions.set("newarray", new std_newarray());
Functions.set("rand", new std_rand()); Functions.set("rand", new std_rand());
Functions.set("sleep", new std_sleep()); Functions.set("sleep", new std_sleep());