Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stdlib: Add list functions #1648

Merged
merged 6 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 47 additions & 17 deletions share/wake/lib/core/list.wake
Original file line number Diff line number Diff line change
Expand Up @@ -900,26 +900,25 @@ 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 lhsSort = sortBy cmpFn lhs
def rhsSort = sortBy cmpFn rhs

match lhsSort rhsSort
def intersectImp cmpFn lhsSort rhsSort = match lhsSort rhsSort
V-FEXrt marked this conversation as resolved.
Show resolved Hide resolved
# 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.
#
Expand All @@ -938,13 +937,44 @@ 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)

# 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
ag-eitilt marked this conversation as resolved.
Show resolved Hide resolved
# ```
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)
4 changes: 4 additions & 0 deletions tests/standard-library/list/pass.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions tests/standard-library/list/stdout
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ True
False
True
False
3, Nil
Nil
0, 1, Nil
"bar", Nil
6 changes: 6 additions & 0 deletions tests/standard-library/list/test.wake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading