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

Function to convert List to Array or to sort Array by key? #942

Open
Boscop opened this issue Oct 30, 2022 · 0 comments
Open

Function to convert List to Array or to sort Array by key? #942

Boscop opened this issue Oct 30, 2022 · 0 comments

Comments

@Boscop
Copy link

Boscop commented Oct 30, 2022

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 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant