Function to convert List to Array or to sort Array by key?
Boscop opened this issue · comments
I found the function to convert a List to an Array (of
), but it seems there is no function to do the reverse?
It would be useful to have it in the std library, e.g.:
let list_to_arr l =
match l with
| Nil -> []
| Cons head tail -> append [head] (list_to_arr tail)
Or (with tail call & accumulator):
let list_to_array l =
let to_array acc l =
match l with
| Nil -> acc
| Cons head tail -> to_array (append acc [head]) tail
to_array [] l
Btw, does gluon do any tail call optimization? :)
I'm asking because I'm working with a lot of long arrays and I need to often sort them.
The only sort function I found in std is for lists, but I need sort_by_key
for arrays.
I tried doing
fn sort_by_key<T, K: std::cmp::Ord>(mut arr: Vec<T>, f: &dyn Fn(&T) -> K) -> Vec<T> {
arr.sort_by_key(f);
arr
}
// ...
ExternModule::new(vm, record! {
sort_by_key => primitive!(2, sort_by_key),
// ...
})
but I got all kinds of errors because of the generics and because the Fn can't cross the FFI boundary. Is there any way to make it work? :)
Then I tried to write sort_by_key
for arrays in the repl, like this (based on sort
for List
):
let { append, Array } = import! std.array
let { List, of, ? } = import! std.list
let list_to_array l =
let to_array acc l =
match l with
| Nil -> acc
| Cons head tail -> to_array (append acc [head]) tail
to_array [] l
let sort_by_key arr key : forall a k. [Ord k] -> Array a -> (a -> k) -> Array a =
let prelude @ { Ordering, ? } = import! std.prelude
let { Semigroup, Monoid, Eq, Show } = prelude
let { Functor, Applicative, Alternative, Monad } = prelude
let { Foldable } = import! std.foldable
let { Traversable } = import! std.traversable
let { Bool } = import! std.bool
let array @ { ? } = import! std.array
let { (<>) } = import! std.semigroup
let { compare } = import! std.cmp
let { map } = import! std.functor
let { (<*>), wrap } = import! std.applicative
let { (<|>) } = import! std.alternative
let { List, of, ? } = import! std.list
rec let scan compare xs less equal greater : (a -> Ordering)
-> List a
-> List a
-> List a
-> List a
-> (List a, List a, List a)
=
match xs with
| Nil -> (less, equal, greater)
| Cons y ys ->
match compare y with
| LT -> scan compare ys (Cons y less) equal greater
| EQ -> scan compare ys less (Cons y equal) greater
| GT -> scan compare ys less equal (Cons y greater)
in
rec
let sort xs : /*[Ord a] ->*/ List a -> List a =
match xs with
| Nil -> Nil
| Cons pivot ys ->
let (less, equal, greater) = scan (\a -> compare (key a) (key pivot)) ys Nil (Cons pivot Nil) Nil
sort less <> equal <> sort greater
list_to_array (sort (of arr))
sort_by_key [{ t = 1., k = "a" }, {t = 0., k = "b" }] (\e -> e.t)
It works but it's quite slow.
Ideally I'd want to use the FFI because I'm working with large arrays of thousands of items and the sorting should be fast if possible :)