From 21e36e8132472f2dd950ac83c6290db701bdc6d4 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 19 Sep 2024 09:24:47 -0700 Subject: [PATCH 1/6] stdlib: Add list functions --- share/wake/lib/core/list.wake | 59 +++++++++++++++++++++++++++ tests/standard-library/list/pass.sh | 16 +++++++- tests/standard-library/list/stdout | 13 ++++++ tests/standard-library/list/test.wake | 20 ++++++++- 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/share/wake/lib/core/list.wake b/share/wake/lib/core/list.wake index 238f81467..5c2ccf92c 100644 --- a/share/wake/lib/core/list.wake +++ b/share/wake/lib/core/list.wake @@ -889,3 +889,62 @@ export def groupBy (cmpFn: a => a => Order) (list: List a): List (List a) = _ -> (elem, Nil), acc foldr combo Nil sorted + +# Returns a list of items where each item was a memeber of the two parameter lists. +# The returned list will not be the same order as the parameters. +# +# Guarantees: +# - Output list length will be <= the length of the smaller input list +# - All items in output list will be present in both input lists +# - Performance is considered and exceeds the naive N^2 algorithm +# +# Examples: +# ``` +# intersect icmp (seq 3) (seq 4) = (0, 1, 2, Nil) +# intersect icmp (seq 3) (seq 3) = (0, 1, 2, Nil) +# intersect icmp (seq 3) (4, 2, 0, Nil) = (0, 2, Nil) +# intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = ("", "bat", Nil) +# ``` +export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = + def lhsSort = sortBy cmpFn lhs + def rhsSort = sortBy cmpFn rhs + + match lhsSort rhsSort + # If either list is exhuasted then no more matches are possible + Nil _ -> Nil + _ Nil -> Nil + (lh, lt) (rh, rt) -> match (cmpFn lh rh) + # lh is smaller so drop it + LT -> intersect cmpFn lt (rh, rt) + # rh is smaller so drop it + GT -> intersect cmpFn (lh, lt) rt + # equal, grab and continue + EQ -> lh, (intersect cmpFn lt rt) + +# Returns a Boolean determining if all items in lhs are also item in rhs. +# +# Guarantees: +# - True is returned only when all items of lhs are present in rhs +# - Performance is considered and exceeds the naive N^2 algorithm +# +# Examples: +# subset icmp (seq 3) (seq 4) = True +# subset icmp (seq 3) (seq 3) = True +# subset icmp (seq 3) (seq 2) = False +# subset icmp (seq 3) (4, 2, 0, Nil) = False +# subset icmp Nil Nil = True +# subset icmp Nil (seq 1) = True +# subset icmp (seq 1) Nil = False +# subset scmp ("", Nil) ("", "foo", "bar", Nil) = True +# subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) = False +export def subset (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): Boolean = + def lhsSort = sortBy cmpFn lhs + def rhsSort = sortBy cmpFn rhs + + match lhsSort rhsSort + Nil _ -> True + _ Nil -> False + (lh, lt) (rh, rt) -> match (cmpFn lh rh) + LT -> False + GT -> subset cmpFn (lh, lt) rt + EQ -> subset cmpFn lt rt diff --git a/tests/standard-library/list/pass.sh b/tests/standard-library/list/pass.sh index 94c64b882..c243b3ada 100755 --- a/tests/standard-library/list/pass.sh +++ b/tests/standard-library/list/pass.sh @@ -1,4 +1,18 @@ #! /bin/sh WAKE="${1:+$1/wake}" -"${WAKE:-wake}" --stdout=warning,report test + +"${WAKE:-wake}" --stdout=warning,report test1 +"${WAKE:-wake}" --stdout=warning,report test2 +"${WAKE:-wake}" --stdout=warning,report test3 +"${WAKE:-wake}" --stdout=warning,report test4 +"${WAKE:-wake}" --stdout=warning,report test5 +"${WAKE:-wake}" --stdout=warning,report test6 +"${WAKE:-wake}" --stdout=warning,report test7 +"${WAKE:-wake}" --stdout=warning,report test8 +"${WAKE:-wake}" --stdout=warning,report test9 +"${WAKE:-wake}" --stdout=warning,report test10 +"${WAKE:-wake}" --stdout=warning,report test11 +"${WAKE:-wake}" --stdout=warning,report test12 +"${WAKE:-wake}" --stdout=warning,report test13 +"${WAKE:-wake}" --stdout=warning,report test14 diff --git a/tests/standard-library/list/stdout b/tests/standard-library/list/stdout index 9f7ca79cf..9e373d01c 100644 --- a/tests/standard-library/list/stdout +++ b/tests/standard-library/list/stdout @@ -1 +1,14 @@ (0, 1, 2, Nil), (3, 4, 5, Nil), (6, 7, 8, Nil), (9, 10, Nil), Nil +0, 1, 2, Nil +0, 1, 2, Nil +0, 2, Nil +"", "bat", Nil +True +True +False +False +True +True +False +True +False diff --git a/tests/standard-library/list/test.wake b/tests/standard-library/list/test.wake index 74ba05b90..103813019 100644 --- a/tests/standard-library/list/test.wake +++ b/tests/standard-library/list/test.wake @@ -1 +1,19 @@ -export def test _ = seq 11 | groupBy (\l\r icmp (l/3) (r/3)) +# groupBy tests +export def test1 _ = seq 11 | groupBy (\l\r icmp (l/3) (r/3)) + +# intersect tests +export def test2 _ = intersect icmp (seq 3) (seq 4) +export def test3 _ = intersect icmp (seq 3) (seq 3) +export def test4 _ = intersect icmp (seq 3) (4, 2, 0, Nil) +export def test5 _ = intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) + +# subset tests +export def test6 _ = subset icmp (seq 3) (seq 4) +export def test7 _ = subset icmp (seq 3) (seq 3) +export def test8 _ = subset icmp (seq 3) (seq 2) +export def test9 _ = subset icmp (seq 3) (4, 2, 0, Nil) +export def test10 _ = subset icmp Nil Nil +export def test11 _ = subset icmp Nil (seq 1) +export def test12 _ = subset icmp (seq 1) Nil +export def test13 _ = subset scmp ("", Nil) ("", "foo", "bar", Nil) +export def test14 _ = subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) From e2e9e6e5401749751db885077366009a326c4fc5 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Fri, 20 Sep 2024 15:57:25 -0700 Subject: [PATCH 2/6] fix performance --- share/wake/lib/core/list.wake | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/share/wake/lib/core/list.wake b/share/wake/lib/core/list.wake index 5c2ccf92c..ddb1c024b 100644 --- a/share/wake/lib/core/list.wake +++ b/share/wake/lib/core/list.wake @@ -906,20 +906,19 @@ export def groupBy (cmpFn: a => a => Order) (list: List a): List (List a) = # intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = ("", "bat", Nil) # ``` export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = - def lhsSort = sortBy cmpFn lhs - def rhsSort = sortBy cmpFn rhs - - match lhsSort rhsSort + def intersectImp cmpFn lhsSort rhsSort = match lhsSort rhsSort # If either list is exhuasted then no more matches are possible Nil _ -> Nil _ Nil -> Nil (lh, lt) (rh, rt) -> match (cmpFn lh rh) # lh is smaller so drop it - LT -> intersect cmpFn lt (rh, rt) + LT -> intersectImp cmpFn lt (rh, rt) # rh is smaller so drop it - GT -> intersect cmpFn (lh, lt) rt + GT -> intersectImp cmpFn (lh, lt) rt # equal, grab and continue - EQ -> lh, (intersect cmpFn lt rt) + EQ -> lh, (intersectImp cmpFn lt rt) + + intersectImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) # Returns a Boolean determining if all items in lhs are also item in rhs. # @@ -938,13 +937,12 @@ export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List # subset scmp ("", Nil) ("", "foo", "bar", Nil) = True # subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) = False export def subset (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): Boolean = - def lhsSort = sortBy cmpFn lhs - def rhsSort = sortBy cmpFn rhs - - match lhsSort rhsSort + def subsetImp cmpFn lhsSort rhsSort = match lhsSort rhsSort Nil _ -> True _ Nil -> False (lh, lt) (rh, rt) -> match (cmpFn lh rh) LT -> False - GT -> subset cmpFn (lh, lt) rt - EQ -> subset cmpFn lt rt + GT -> subsetImp cmpFn (lh, lt) rt + EQ -> subsetImp cmpFn lt rt + + subsetImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) From 9eb9b794309b75c4156c139c34615a302501cc8a Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Fri, 20 Sep 2024 16:19:07 -0700 Subject: [PATCH 3/6] Add difference function --- share/wake/lib/core/list.wake | 40 ++++++++++++++++++++++++--- tests/standard-library/list/pass.sh | 4 +++ tests/standard-library/list/stdout | 4 +++ tests/standard-library/list/test.wake | 6 ++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/share/wake/lib/core/list.wake b/share/wake/lib/core/list.wake index ddb1c024b..74685c5b8 100644 --- a/share/wake/lib/core/list.wake +++ b/share/wake/lib/core/list.wake @@ -900,10 +900,10 @@ export def groupBy (cmpFn: a => a => Order) (list: List a): List (List a) = # # Examples: # ``` -# intersect icmp (seq 3) (seq 4) = (0, 1, 2, Nil) -# intersect icmp (seq 3) (seq 3) = (0, 1, 2, Nil) -# intersect icmp (seq 3) (4, 2, 0, Nil) = (0, 2, Nil) -# intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = ("", "bat", Nil) +# intersect icmp (seq 3) (seq 4) = 0, 1, 2, Nil +# intersect icmp (seq 3) (seq 3) = 0, 1, 2, Nil +# intersect icmp (seq 3) (4, 2, 0, Nil) = 0, 2, Nil +# intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = "", "bat", Nil # ``` export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = def intersectImp cmpFn lhsSort rhsSort = match lhsSort rhsSort @@ -946,3 +946,35 @@ export def subset (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): Boolean EQ -> subsetImp cmpFn lt rt subsetImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) + +# Returns a list of items where each item was a memeber of lhs but not rhs +# The returned list will not be the same order as the parameters. +# +# Guarantees: +# - Output list length will be <= the length of lhs +# - All items in output list will be present in lhs +# - No items in output list will be present in rhs +# - Performance is considered and exceeds the naive N^2 algorithm +# +# Examples: +# ``` +# difference icmp (seq 4) (seq 3) = 3, Nil +# difference icmp (seq 3) (seq 3) = Nil +# difference icmp (seq 3) (2, Nil) = 0, 1, Nil +# difference scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = "bar", Nil +# ``` +export def difference (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = + def differenceImp cmpFn lhsSort rhsSort = match lhsSort rhsSort + # lhs is empty so the result will always be empty + Nil _ -> Nil + # rhs is empty nothing else to subtract so result will always be lhs + l Nil -> l + (lh, lt) (rh, rt) -> match (cmpFn lh rh) + # lh is smaller, add it to the output set then continue looking in lt + LT -> lh, (differenceImp cmpFn lt (rh, rt)) + # rh is smaller so drop it, then continue looking in (lh, lt) + GT -> differenceImp cmpFn (lh, lt) rt + # item is in both sets. Remove it then continue looking + EQ -> differenceImp cmpFn lt rt + + differenceImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) diff --git a/tests/standard-library/list/pass.sh b/tests/standard-library/list/pass.sh index c243b3ada..5d894cfe3 100755 --- a/tests/standard-library/list/pass.sh +++ b/tests/standard-library/list/pass.sh @@ -16,3 +16,7 @@ WAKE="${1:+$1/wake}" "${WAKE:-wake}" --stdout=warning,report test12 "${WAKE:-wake}" --stdout=warning,report test13 "${WAKE:-wake}" --stdout=warning,report test14 +"${WAKE:-wake}" --stdout=warning,report test15 +"${WAKE:-wake}" --stdout=warning,report test16 +"${WAKE:-wake}" --stdout=warning,report test17 +"${WAKE:-wake}" --stdout=warning,report test18 diff --git a/tests/standard-library/list/stdout b/tests/standard-library/list/stdout index 9e373d01c..a32891a2d 100644 --- a/tests/standard-library/list/stdout +++ b/tests/standard-library/list/stdout @@ -12,3 +12,7 @@ True False True False +3, Nil +Nil +0, 1, Nil +"bar", Nil diff --git a/tests/standard-library/list/test.wake b/tests/standard-library/list/test.wake index 103813019..38399f977 100644 --- a/tests/standard-library/list/test.wake +++ b/tests/standard-library/list/test.wake @@ -17,3 +17,9 @@ export def test11 _ = subset icmp Nil (seq 1) export def test12 _ = subset icmp (seq 1) Nil export def test13 _ = subset scmp ("", Nil) ("", "foo", "bar", Nil) export def test14 _ = subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) + +# difference tests +export def test15 _ = difference icmp (seq 4) (seq 3) +export def test16 _ = difference icmp (seq 3) (seq 3) +export def test17 _ = difference icmp (seq 3) (2, Nil) +export def test18 _ = difference scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) From 0e74c7a54097ded38d1c7f9d23ec5a9397e4b624 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 23 Sep 2024 10:29:46 -0700 Subject: [PATCH 4/6] address comments --- share/wake/lib/core/list.wake | 50 +++++++++++++-------------- tests/standard-library/list/test.wake | 10 +++--- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/share/wake/lib/core/list.wake b/share/wake/lib/core/list.wake index 74685c5b8..e549a28b4 100644 --- a/share/wake/lib/core/list.wake +++ b/share/wake/lib/core/list.wake @@ -890,7 +890,7 @@ export def groupBy (cmpFn: a => a => Order) (list: List a): List (List a) = foldr combo Nil sorted -# Returns a list of items where each item was a memeber of the two parameter lists. +# Returns a list of items where each item was a member of the two parameter lists. # The returned list will not be the same order as the parameters. # # Guarantees: @@ -905,8 +905,8 @@ export def groupBy (cmpFn: a => a => Order) (list: List a): List (List a) = # intersect icmp (seq 3) (4, 2, 0, Nil) = 0, 2, Nil # intersect scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = "", "bat", Nil # ``` -export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = - def intersectImp cmpFn lhsSort rhsSort = match lhsSort rhsSort +export def intersect (cmpFn: a => a => Order) (left: List a) (right: List a): List a = + def intersectImp cmpFn leftSort rightSort = match leftSort rightSort # If either list is exhuasted then no more matches are possible Nil _ -> Nil _ Nil -> Nil @@ -918,12 +918,12 @@ export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List # equal, grab and continue EQ -> lh, (intersectImp cmpFn lt rt) - intersectImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) + intersectImp cmpFn (sortBy cmpFn left) (sortBy cmpFn right) -# Returns a Boolean determining if all items in lhs are also item in rhs. +# Returns a Boolean determining if all items in left are also item in right. # # Guarantees: -# - True is returned only when all items of lhs are present in rhs +# - True is returned only when all items of left are present in right # - Performance is considered and exceeds the naive N^2 algorithm # # Examples: @@ -936,8 +936,8 @@ export def intersect (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List # subset icmp (seq 1) Nil = False # subset scmp ("", Nil) ("", "foo", "bar", Nil) = True # subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) = False -export def subset (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): Boolean = - def subsetImp cmpFn lhsSort rhsSort = match lhsSort rhsSort +export def subset (cmpFn: a => a => Order) (left: List a) (right: List a): Boolean = + def subsetImp cmpFn leftSort rightSort = match leftSort rightSort Nil _ -> True _ Nil -> False (lh, lt) (rh, rt) -> match (cmpFn lh rh) @@ -945,36 +945,36 @@ export def subset (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): Boolean GT -> subsetImp cmpFn (lh, lt) rt EQ -> subsetImp cmpFn lt rt - subsetImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) + subsetImp cmpFn (sortBy cmpFn left) (sortBy cmpFn right) -# Returns a list of items where each item was a memeber of lhs but not rhs +# Remove all items from the left list which occur in the right. # The returned list will not be the same order as the parameters. # # Guarantees: -# - Output list length will be <= the length of lhs -# - All items in output list will be present in lhs -# - No items in output list will be present in rhs +# - Output list length will be <= the length of left +# - All items in output list will be present in left +# - No items in output list will be present in right # - Performance is considered and exceeds the naive N^2 algorithm # # Examples: # ``` -# difference icmp (seq 4) (seq 3) = 3, Nil -# difference icmp (seq 3) (seq 3) = Nil -# difference icmp (seq 3) (2, Nil) = 0, 1, Nil -# difference scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = "bar", Nil +# subtract icmp (seq 4) (seq 3) = 3, Nil +# subtract icmp (seq 3) (seq 3) = Nil +# subtract icmp (seq 3) (2, Nil) = 0, 1, Nil +# subtract scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) = "bar", Nil # ``` -export def difference (cmpFn: a => a => Order) (lhs: List a) (rhs: List a): List a = - def differenceImp cmpFn lhsSort rhsSort = match lhsSort rhsSort - # lhs is empty so the result will always be empty +export def subtract (cmpFn: a => a => Order) (left: List a) (right: List a): List a = + def subtractImp cmpFn leftSort rightSort = match leftSort rightSort + # left is empty so the result will always be empty Nil _ -> Nil - # rhs is empty nothing else to subtract so result will always be lhs + # right is empty nothing else to subtract so result will always be left l Nil -> l (lh, lt) (rh, rt) -> match (cmpFn lh rh) # lh is smaller, add it to the output set then continue looking in lt - LT -> lh, (differenceImp cmpFn lt (rh, rt)) + LT -> lh, (subtractImp cmpFn lt (rh, rt)) # rh is smaller so drop it, then continue looking in (lh, lt) - GT -> differenceImp cmpFn (lh, lt) rt + GT -> subtractImp cmpFn (lh, lt) rt # item is in both sets. Remove it then continue looking - EQ -> differenceImp cmpFn lt rt + EQ -> subtractImp cmpFn lt rt - differenceImp cmpFn (sortBy cmpFn lhs) (sortBy cmpFn rhs) + subtractImp cmpFn (sortBy cmpFn left) (sortBy cmpFn right) diff --git a/tests/standard-library/list/test.wake b/tests/standard-library/list/test.wake index 38399f977..af7401191 100644 --- a/tests/standard-library/list/test.wake +++ b/tests/standard-library/list/test.wake @@ -18,8 +18,8 @@ export def test12 _ = subset icmp (seq 1) Nil export def test13 _ = subset scmp ("", Nil) ("", "foo", "bar", Nil) export def test14 _ = subset scmp ("", "bat", Nil) ("", "foo", "bar", Nil) -# difference tests -export def test15 _ = difference icmp (seq 4) (seq 3) -export def test16 _ = difference icmp (seq 3) (seq 3) -export def test17 _ = difference icmp (seq 3) (2, Nil) -export def test18 _ = difference scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) +# subtract tests +export def test15 _ = subtract icmp (seq 4) (seq 3) +export def test16 _ = subtract icmp (seq 3) (seq 3) +export def test17 _ = subtract icmp (seq 3) (2, Nil) +export def test18 _ = subtract scmp ("", "bar", "bat", Nil) ("", "foo", "bat", Nil) From 84020de05df287184602f5bb7b62177cdec127ac Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 23 Sep 2024 13:12:34 -0700 Subject: [PATCH 5/6] timing --- tests/inspection/canceled/test.wake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/inspection/canceled/test.wake b/tests/inspection/canceled/test.wake index b68148708..d53bcaa14 100644 --- a/tests/inspection/canceled/test.wake +++ b/tests/inspection/canceled/test.wake @@ -2,7 +2,7 @@ from wake import _ export def test _: Result Unit Error = def _ = - makeExecPlan ("sleep", "10",) Nil + makeExecPlan ("sleep", "1000",) Nil | runJobWith defaultRunner Pass Unit From 93a3845622e08a6be0855de8882ee02c2916eb87 Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Mon, 23 Sep 2024 13:39:37 -0700 Subject: [PATCH 6/6] bonk --- tests/inspection/canceled/stdout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/inspection/canceled/stdout b/tests/inspection/canceled/stdout index 61adfa2f4..e1befc066 100644 --- a/tests/inspection/canceled/stdout +++ b/tests/inspection/canceled/stdout @@ -1,2 +1,2 @@ # (1) -$ sleep 10 +$ sleep 1000