Make zip functions (and joinPath, concat) compatible with apply. Close #19

This commit is contained in:
2021-07-24 12:03:37 -06:00
parent 3652d8e107
commit 611c3ade0f
5 changed files with 60 additions and 55 deletions

View File

@@ -56,11 +56,9 @@ class Kiss {
"print" => Symbol("Prelude.print"), "print" => Symbol("Prelude.print"),
"sort" => Symbol("Prelude.sort"), "sort" => Symbol("Prelude.sort"),
"groups" => Symbol("Prelude.groups"), "groups" => Symbol("Prelude.groups"),
"concat" => Symbol("Prelude.concat"),
"pairs" => Symbol("Prelude.pairs"), // TODO test pairs "pairs" => Symbol("Prelude.pairs"), // TODO test pairs
"reversed" => Symbol("Prelude.reversed"), // TODO test reversed "reversed" => Symbol("Prelude.reversed"), // TODO test reversed
"memoize" => Symbol("Prelude.memoize"), // TODO test memoize "memoize" => Symbol("Prelude.memoize"), // TODO test memoize
"joinPath" => Symbol("Prelude.joinPath"),
"symbolName" => Symbol("Prelude.symbolName"), "symbolName" => Symbol("Prelude.symbolName"),
"symbolNameValue" => Symbol("Prelude.symbolNameValue"), "symbolNameValue" => Symbol("Prelude.symbolNameValue"),
"symbol" => Symbol("Prelude.symbol"), "symbol" => Symbol("Prelude.symbol"),
@@ -70,11 +68,12 @@ class Kiss {
"flatten" => Symbol("Lambda.flatten"), "flatten" => Symbol("Lambda.flatten"),
"has" => Symbol("Lambda.has"), "has" => Symbol("Lambda.has"),
"count" => Symbol("Lambda.count"), "count" => Symbol("Lambda.count"),
// These work with (apply) because they are added as "opAliases" in Macros.kiss:
"min" => Symbol("Prelude.min"), "min" => Symbol("Prelude.min"),
"max" => Symbol("Prelude.max") "max" => Symbol("Prelude.max"),
], ],
// These ones won't conflict with variables and might commonly be used with (apply)
identAliases: [ identAliases: [
// These ones won't conflict with variables and might commonly be used with (apply)
"+" => Symbol("Prelude.add"), "+" => Symbol("Prelude.add"),
"-" => Symbol("Prelude.subtract"), "-" => Symbol("Prelude.subtract"),
"*" => Symbol("Prelude.multiply"), "*" => Symbol("Prelude.multiply"),
@@ -85,7 +84,13 @@ class Kiss {
">=" => Symbol("Prelude.greaterEqual"), ">=" => Symbol("Prelude.greaterEqual"),
"<" => Symbol("Prelude.lessThan"), "<" => Symbol("Prelude.lessThan"),
"<=" => Symbol("Prelude.lesserEqual"), "<=" => Symbol("Prelude.lesserEqual"),
"=" => Symbol("Prelude.areEqual") "=" => Symbol("Prelude.areEqual"),
// These ones *probably* won't conflict with variables and might commonly be used with (apply) because they are variadic
"concat" => Symbol("Prelude.concat"),
"zipKeep" => Symbol("Prelude.zipKeep"),
"zipDrop" => Symbol("Prelude.zipDrop"),
"zipThrow" => Symbol("Prelude.zipThrow"),
"joinPath" => Symbol("Prelude.joinPath"),
], ],
fields: [], fields: [],
loadingDirectory: "", loadingDirectory: "",

View File

@@ -110,12 +110,6 @@ class Macros {
b.callSymbol("Prelude.range", [min, max, step]); b.callSymbol("Prelude.range", [min, max, step]);
}; };
macros["zip"] = (wholeExp:ReaderExp, exps:kiss.List<ReaderExp>, k) -> {
wholeExp.checkNumArgs(3, null, '(zip [listA] [listB] [moreLists...] [extraHandling])');
var b = wholeExp.expBuilder();
return b.callSymbol("Prelude.zip", [b.list(exps.slice(0, -1)), exps[-1]]);
};
// Most conditional compilation macros are based on this macro: // Most conditional compilation macros are based on this macro:
macros["#if"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { macros["#if"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, 3, '(#if [cond] [then] [?else])'); wholeExp.checkNumArgs(2, 3, '(#if [cond] [then] [?else])');

View File

@@ -181,47 +181,51 @@ class Prelude {
public static var concat:Function = Reflect.makeVarArgs(_concat); public static var concat:Function = Reflect.makeVarArgs(_concat);
public static function zip(arrays:Array<Array<Dynamic>>, extraHandling = Drop):kiss.List<kiss.List<Dynamic>> { static function _zip(iterables:Array<Dynamic>, extraHandling:ExtraElementHandling):Array<Array<Dynamic>> {
var lengthsAreEqual = true; var lists = [];
var lengths = [for (arr in arrays) arr.length]; var iterators = [for (iterable in iterables) iterable.iterator()];
for (idx in 1...lengths.length) {
if (lengths[idx] != lengths[idx - 1]) {
lengthsAreEqual = false;
break;
}
}
var max = Math.floor(if (!lengthsAreEqual) {
switch (extraHandling) {
case Throw:
throw 'zip was given lists of mis-matched size: $arrays';
case Keep:
Prelude._max(lengths);
case Drop:
Prelude._min(lengths);
}
} else {
lengths[0];
});
return [ while (true) {
for (idx in 0...max) { var zipped:Array<Dynamic> = [];
var zipped:Array<Dynamic> = [];
for (arr in arrays) { var someNonNull = false;
zipped.push( for (it in iterators) {
if (idx < arr.length) { switch (extraHandling) {
arr[idx]; case Keep:
} else { zipped.push(
null; if (it.hasNext()) {
} someNonNull = true;
); it.next();
} else {
null;
});
default:
if (it.hasNext())
zipped.push(it.next());
} }
zipped;
} }
];
switch (extraHandling) {
case _ if (zipped.length == 0):
break;
case Keep if (!someNonNull):
break;
case Drop if (zipped.length != iterators.length):
break;
case Throw if (zipped.length != iterators.length):
throw 'zip${extraHandling} was given iterables of mis-matched size: $iterables';
default:
}
lists.push(zipped);
}
return lists;
} }
public static var zipKeep:Function = Reflect.makeVarArgs(_zip.bind(_, Keep));
public static var zipDrop:Function = Reflect.makeVarArgs(_zip.bind(_, Drop));
public static var zipThrow:Function = Reflect.makeVarArgs(_zip.bind(_, Throw));
public static function pairs(l:kiss.List<Dynamic>, loopAround = false):kiss.List<kiss.List<Dynamic>> { public static function pairs(l:kiss.List<Dynamic>, loopAround = false):kiss.List<kiss.List<Dynamic>> {
var l1 = l.slice(0, l.length - 1); var l1 = l.slice(0, l.length - 1);
var l2 = l.slice(1, l.length); var l2 = l.slice(1, l.length);
@@ -229,7 +233,7 @@ class Prelude {
l1.push(l[-1]); l1.push(l[-1]);
l2.unshift(l[0]); l2.unshift(l[0]);
} }
return zip([l1, l2]); return zipThrow(l1, l2);
} }
public static function reversed<T>(l:kiss.List<T>):kiss.List<T> { public static function reversed<T>(l:kiss.List<T>):kiss.List<T> {

View File

@@ -119,14 +119,16 @@
(catch [error] (Assert.pass)))) (catch [error] (Assert.pass))))
(defun _testZip [] (defun _testZip []
(Assert.equals (.toString [[1 2] [3 4]]) (.toString (zip [1 3] [2 4] Throw))) (Assert.equals (.toString [[1 2] [3 4]]) (.toString (zipThrow [1 3] [2 4])))
(Assert.equals (.toString [[1 2] [3 null]]) (.toString (zip [1 3] [2] Keep))) (Assert.equals (.toString [[1 2] [3 null]]) (.toString (zipKeep [1 3] [2])))
(Assert.equals (.toString [[1 2] [null 4]]) (.toString (zip [1 null] [2 4] Keep))) (Assert.equals (.toString [[1 2] [null 4]]) (.toString (zipKeep [1 null] [2 4])))
(try (begin (zip [1 3] [2] Throw) (Assert.fail)) (try (begin (zipThrow [1 3] [2]) (Assert.fail))
(catch [error] (Assert.pass))) (catch [error] (Assert.pass)))
(try (begin (zip [1] [2 4] Throw) (Assert.fail)) (try (begin (zipThrow [1] [2 4]) (Assert.fail))
(catch [error] (Assert.pass))) (catch [error] (Assert.pass)))
(Assert.equals (.toString [[1 2 3] [2 null 3]]) (.toString (zip [1 2] [2] [3 3] Keep)))) (Assert.equals (.toString [[1 2 3] [2 null 3]]) (.toString (zipKeep [1 2] [2] [3 3])))
(Assert.equals (.toString [[1 2]]) (.toString (zipDrop [1 2 3 4] [2])))
(Assert.equals (.toString [[1 2] [3 4]]) (.toString (apply zipThrow [[1 3] [2 4]]))))
(defun _testLet [] (defun _testLet []
(let [a 5 (let [a 5

View File

@@ -35,9 +35,9 @@
// TODO rectangle type // TODO rectangle type
// TODO optional source rectangle argument // TODO optional source rectangle argument
(defmethod blitSurface [:Surface surface x y] (defmethod blitSurface [:Surface surface x y]
(doFor [srcX destX] (zip (collect (range 0 surface.width)) (collect (range x (+ x surface.width))) Drop) (doFor [srcX destX] (zipDrop (range surface.width) (range x (+ x surface.width)))
(when (< -1 destX width) (when (< -1 destX width)
(doFor [srcY destY] (zip (collect (range 0 surface.height)) (collect (range y (+ y surface.height))) Drop) (doFor [srcY destY] (zipDrop (range 0 surface.height) (range y (+ y surface.height)))
(when (< -1 destY height) (when (< -1 destY height)
(when (surface.isCellOpaque srcX srcY) (when (surface.isCellOpaque srcX srcY)
(setBackgroundColor destX destY (surface.getBackgroundColor srcX srcY)) (setBackgroundColor destX destY (surface.getBackgroundColor srcX srcY))