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

experiment: use more tail recursion in List.mo #635

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
62 changes: 35 additions & 27 deletions src/List.mo
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,13 @@ module {
/// Space: O(size)
/// *Runtime and space assumes that `f` runs in O(1) time and space.
public func map<T, U>(l : List<T>, f : T -> U) : List<U> {
switch l {
case null { null };
case (?(h, t)) { ?(f(h), map<T, U>(t, f)) }
}
func go(acc : List<U>, l : List<T>) : List<U> {
switch l {
case null { reverse(acc) };
case (?(h, t)) { go(?(f(h), acc), t) }
}
};
go(null, l)
};

/// Create a new list with only those elements of the original list for which
Expand All @@ -211,16 +214,19 @@ module {
///
/// Space: O(size)
public func filter<T>(l : List<T>, f : T -> Bool) : List<T> {
switch l {
case null { null };
case (?(h, t)) {
if (f(h)) {
?(h, filter<T>(t, f))
} else {
filter<T>(t, f)
func go(acc : List<T>, l : List<T>) : List<T> {
switch l {
case null { reverse(acc) };
case (?(h, t)) {
if (f(h)) {
go(?(h, acc), t)
} else {
go(acc, t)
}
}
}
}
};
go(null, l);
};

/// Create two new lists from the results of a given function (`f`).
Expand Down Expand Up @@ -277,15 +283,18 @@ module {
///
/// *Runtime and space assumes that `f` runs in O(1) time and space.
public func mapFilter<T, U>(l : List<T>, f : T -> ?U) : List<U> {
switch l {
case null { null };
case (?(h, t)) {
switch (f(h)) {
case null { mapFilter<T, U>(t, f) };
case (?h_) { ?(h_, mapFilter<T, U>(t, f)) }
func go(acc : List<U>, l : List<T>) : List<U> {
switch l {
case null { reverse(acc) };
case (?(h, t)) {
switch (f(h)) {
case null { go(acc, t) };
case (?h_) { go(?(h_,acc), t) }
}
}
}
}
};
go(null, l);
};

/// Maps a Result-returning function `f` over a List and returns either
Expand Down Expand Up @@ -789,18 +798,17 @@ module {
/// Space: O(n)
public func split<T>(n : Nat, xs : List<T>) : (List<T>, List<T>) {
if (n == 0) { (null, xs) } else {
func rec(n : Nat, xs : List<T>) : (List<T>, List<T>) {
switch (pop<T>(xs)) {
case (null, _) { (null, null) };
case (?h, t) {
if (n == 1) { (make<T>(h), t) } else {
let (l, r) = rec(n - 1, t);
(push<T>(h, l), r)
func rec(n : Nat, acc : List<T>, xs : List<T>) : (List<T>, List<T>) {
switch xs {
case null { (reverse(acc), null) };
case (?(h, t)) {
if (n == 1) { (reverse(?(h, acc)), t) } else {
rec(n - 1, ?(h, acc), t);
}
}
}
};
rec(n, xs)
rec(n, null, xs)
}
};

Expand Down
2 changes: 1 addition & 1 deletion test/Deque.test.mo
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ run(
[
test(
"random insertion and deletion",
isSorted(randomInsertionDeletion(1000)),
isSorted(randomInsertionDeletion(10000)),
M.equals(T.bool(true))
)
]
Expand Down