From d3bdcbb4fe5b3facbb6ea24a4bb9addf66f16039 Mon Sep 17 00:00:00 2001 From: Julian Hyde Date: Sat, 28 Dec 2024 23:55:55 -0800 Subject: [PATCH] user-defined aggregate function --- .../net/hydromatic/morel/compile/TypeResolver.java | 2 +- src/test/java/net/hydromatic/morel/MainTest.java | 11 ++++++++--- src/test/resources/script/bag.smli | 8 +++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/hydromatic/morel/compile/TypeResolver.java b/src/main/java/net/hydromatic/morel/compile/TypeResolver.java index 67b4db2d..5082cac5 100644 --- a/src/main/java/net/hydromatic/morel/compile/TypeResolver.java +++ b/src/main/java/net/hydromatic/morel/compile/TypeResolver.java @@ -651,7 +651,7 @@ private Triple deduceStepType(TypeEnv env, Ast.FromStep step, Triple triple, reg(aggregate.aggregate, null, v9); equiv( unifier.apply(FN_TY_CON, - unifier.apply(STREAM_TY_CON, unifier.variable(), v10), v8), + unifier.apply(STREAM_TY_CON, unorderedTerm(), v10), v8), v9); env3 = env3.bind(id.name, v8); fieldVars.put(id, v8); diff --git a/src/test/java/net/hydromatic/morel/MainTest.java b/src/test/java/net/hydromatic/morel/MainTest.java index 589d672b..cb8e86ca 100644 --- a/src/test/java/net/hydromatic/morel/MainTest.java +++ b/src/test/java/net/hydromatic/morel/MainTest.java @@ -2479,7 +2479,10 @@ private static List node(Object... args) { + " [{id = 100, name = \"Fred\", deptno = 10},\n" + " {id = 101, name = \"Velma\", deptno = 20},\n" + " {id = 102, name = \"Shaggy\", deptno = 10}]\n" - + " fun sum [] = 0 | sum (h::t) = h + (sum t)\n" + + " fun sum bag =\n" + + " case Bag.getItem bag of\n" + + " NONE => 0\n" + + " | SOME (h, t) => h + (sum t)\n" + "in\n" + " from e in emps\n" + " group #deptno e\n" @@ -2489,7 +2492,9 @@ private static List node(Object... args) { + "[{deptno = 10, id = 100, name = \"Fred\"}," + " {deptno = 20, id = 101, name = \"Velma\"}," + " {deptno = 10, id = 102, name = \"Shaggy\"}]; " - + "fun sum ([]) = 0 | sum (h :: t) = h + sum t " + + "fun sum bag = case #getItem Bag bag of" + + " NONE => 0" + + " | SOME (h, t) => h + sum t " + "in" + " from e in emps" + " group deptno = #deptno e" @@ -2551,7 +2556,7 @@ private static List node(Object... args) { ml("from e in [{a = 1, b = 5}, {a = 0, b = 1}, {a = 1, b = 1}]\n" + " group e.a compute rows = (fn x => x)") - .assertType(hasMoniker("{a:int, rows:{a:int, b:int} list} bag")) + .assertType(hasMoniker("{a:int, rows:{a:int, b:int} bag} bag")) .assertEvalIter( equalsUnordered( list(1, list(list(1, 5), list(1, 1))), diff --git a/src/test/resources/script/bag.smli b/src/test/resources/script/bag.smli index 42330f10..d10d952c 100644 --- a/src/test/resources/script/bag.smli +++ b/src/test/resources/script/bag.smli @@ -102,7 +102,9 @@ from r in recList group r.i; from r in recBag group r.i; > val it = [1,2] : int bag -(*) aggregate functions produce bags +(*) the input to an aggregate functions is a bag, even if the input +(*) stream is a list. (We need to devise syntax for aggregate functions +(*) to sort their input.) from r in recList group r.i compute count; > val it = [{count=2,i=1},{count=1,i=2}] : {count:int, i:int} bag from r in recBag group r.i compute count; @@ -128,9 +130,9 @@ from i in intList order (); from i in intBag order (); > val it = [1,2,3] : int list from r in recList group r.i compute bs = (fn x => x) of r.b order i desc; -> val it = [{bs=[true,false],i=1},{bs=[false],i=2}] : {bs:bool bag, i:int} list +> val it = [{bs=[false],i=2},{bs=[true,false],i=1}] : {bs:bool bag, i:int} list from r in recBag group r.i compute bs = (fn x => x) of r.b order i desc; -> val it = [{bs=[true,false],i=1},{bs=[false],i=2}] : {bs:bool bag, i:int} list +> val it = [{bs=[false],i=2},{bs=[true,false],i=1}] : {bs:bool bag, i:int} list (*) join preserves collection type (should it?)