Skip to content
Merged
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
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"purescript-lazy": "^3.0.0",
"purescript-nonempty": "^4.0.0",
"purescript-tailrec": "^3.0.0",
"purescript-unfoldable": "^3.0.0"
"purescript-unfoldable": "^3.0.0",
"purescript-partial": "^1.0.0"
},
"devDependencies": {
"purescript-arrays": "^4.0.0",
Expand Down
12 changes: 11 additions & 1 deletion src/Data/List/NonEmpty.purs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ module Data.List.NonEmpty
, length
, concatMap
, appendFoldable
, sort
, sortBy
) where

import Prelude
Expand All @@ -21,11 +23,12 @@ import Data.Foldable (class Foldable)
import Data.List ((:))
import Data.List as L
import Data.List.Types (NonEmptyList(..))
import Data.Maybe (Maybe(..), maybe, fromMaybe)
import Data.Maybe (Maybe(..), maybe, fromMaybe, fromJust)
import Data.NonEmpty ((:|))
import Data.NonEmpty as NE
import Data.Tuple (Tuple(..))
import Data.Unfoldable (class Unfoldable, unfoldr)
import Partial.Unsafe (unsafePartial)

toUnfoldable :: forall f. Unfoldable f => NonEmptyList ~> f
toUnfoldable =
Expand Down Expand Up @@ -68,3 +71,10 @@ concatMap = flip bind
appendFoldable :: forall t a. Foldable t => NonEmptyList a -> t a -> NonEmptyList a
appendFoldable (NonEmptyList (x :| xs)) ys =
NonEmptyList (x :| (xs <> L.fromFoldable ys))

sort :: forall a. Ord a => NonEmptyList a -> NonEmptyList a
sort xs = sortBy compare xs

sortBy :: forall a. (a -> a -> Ordering) -> NonEmptyList a -> NonEmptyList a
sortBy cmp xs = unsafeFromList $ L.sortBy cmp (toList xs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option here is to sort the tail and insert the head into the sorted result, a la insertion sort. That would require us to change the type of insert though, or to provide an alternative version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paf31 are you suggesting we should go down that route? I understand that unsafeFromList is, in many cases, a last resort, but here it seems to be both safe and more efficient than the alternative.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote for the unsafeFromList version here too, personally. :)

where unsafeFromList ys = unsafePartial $ fromJust $ fromList ys
19 changes: 19 additions & 0 deletions test/Test/Data/List/NonEmpty.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Test.Data.List.NonEmpty (testNonEmptyList) where

import Prelude
import Data.List (fromFoldable)
import Data.List.NonEmpty (NonEmptyList(..), sort, sortBy)
import Data.NonEmpty ((:|))
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Test.Assert (ASSERT, assert)

testNonEmptyList ::
forall eff. Eff (assert :: ASSERT, console :: CONSOLE | eff) Unit
testNonEmptyList = do
let nel x xs = NonEmptyList $ x :| fromFoldable xs

log "sort should reorder a non-empty list into ascending order based on the result of compare"
assert $ sort (nel 1 [3, 2, 5, 6, 4]) == nel 1 [2, 3, 4, 5, 6]
log "sortBy should reorder a non-empty list into ascending order based on the result of a comparison function"
assert $ sortBy (flip compare) (nel 1 [3, 2, 5, 6, 4]) == nel 6 [5, 4, 3, 2, 1]
2 changes: 2 additions & 0 deletions test/Test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import Test.Data.List (testList)
import Test.Data.List.Lazy (testListLazy)
import Test.Data.List.Partial (testListPartial)
import Test.Data.List.ZipList (testZipList)
import Test.Data.List.NonEmpty (testNonEmptyList)

main :: forall eff. Eff (assert :: ASSERT, console :: CONSOLE | eff) Unit
main = do
testList
testListLazy
testZipList
testListPartial
testNonEmptyList