简体   繁体   中英

Which is a more efficient version of "takeEnd" function

I am new to PureScript so I am re-creating some basic functions, and I wanted to recreate "takeEnd" function which takes specified number of elements from the end of the list.

Here is solution I wrote:

takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n l = go n Nil $ reverse l where
    go _ new Nil = new
    go 0 new _ = new
    go n new  (x : xs) = go (n - 1) (x : new) xs

And here is a solution I found in a book:

takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n  = go >>> snd where
    go Nil = Tuple 0 Nil
    go (x : xs) = go xs
        # \(Tuple c nl) -> Tuple (c + 1) $ if c < n then x : nl else nl

I am interested in which version is more efficient? If I am not mistaken I believe also that second version is not tail optimized

The second solution does a single traversal of the list but is not tail recursive, so creates stack frames.

The first solution looks incorrect and gives the elements backwards. So it should do one traversal of the whole list and then a traversal of n, then possibly another reverse - so it is less efficient in terms of time.

PureScript often makes you decide between these efficiencies, due to strict evaluation. Could you blow the stack with the size of your list? If so, you have to stick with the theoretically slower, first solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM