NonEmptyList (empty) → 0.0.1
raw patch · 4 files changed
+281/−0 lines, 4 filesdep +QuickCheckdep +basesetup-changed
Dependencies added: QuickCheck, base
Files
- Data/List/NonEmpty.hs +226/−0
- LICENSE +27/−0
- NonEmptyList.cabal +25/−0
- Setup.lhs +3/−0
+ Data/List/NonEmpty.hs view
@@ -0,0 +1,226 @@+-- | A type-safe list that has at least one element.+module Data.List.NonEmpty(+ NonEmpty,+ -- * Accessors+ neHead,+ neTail,+ -- * Constructors+ nonEmpty,+ (|:),+ toNonEmpty,+ unsafeToNonEmpty,+ (.:),+ (.++),+ -- * List functions+ reverse,+ scanl,+ scanl1,+ scanr,+ scanr1,+ iterate,+ repeat,+ cycle,+ inits,+ tails,+ sort,+ insert,+ zip,+ unzip, + -- * Tests+ prop_neHead,+ prop_neTail,+ prop_nonEmpty,+ prop_nonEmptyAlias,+ prop_toNonEmpty,+ prop_unsafeNonEmpty,+ prop_cons,+ prop_append,+ prop_reverse+ ) where++import Control.Applicative+import Control.Monad+import Control.Arrow+import Data.Foldable+import Data.Maybe+import Data.Traversable+import qualified Data.List as L+import Prelude hiding (foldr, reverse, scanl, scanl1, scanr, scanr1, iterate, repeat, cycle, zip, unzip)+import Test.QuickCheck hiding (NonEmpty)++-- | An list with at least one element.+data NonEmpty a = NonEmpty {+ neHead :: a, -- ^ The head of the non-empty list.+ neTail :: [a] -- ^ The tail of the non-empty list.+} deriving (Eq, Ord)++instance Functor NonEmpty where+ fmap f (NonEmpty h t) = NonEmpty (f h) (fmap f t)++instance Applicative NonEmpty where+ pure = return+ (<*>) = ap++instance Monad NonEmpty where+ return = flip NonEmpty []+ NonEmpty h t >>= f = let NonEmpty a b = f h+ k = t >>= toList . f+ in NonEmpty a (b ++ k)++instance Foldable NonEmpty where+ foldr f x (NonEmpty h t) = foldr f x (h:t)+ foldl f x (NonEmpty h t) = foldl' f x (h:t)++instance Traversable NonEmpty where+ traverse f a = NonEmpty <$> head <*> tail <$> traverse f (toList a)++instance (Show a) => Show (NonEmpty a) where+ show (NonEmpty h t) = '|' : show (h:t) ++ "|"++-- | Constructs a non-empty list with the given head and tail.+nonEmpty :: a -- ^ The head.+ -> [a] -- ^ The tail.+ -> NonEmpty a+nonEmpty = NonEmpty++-- | Constructs a non-empty list with the given head and tail (an alias for @nonEmpty@).+(|:) :: a -- ^ The head.+ -> [a] -- ^ The tail.+ -> NonEmpty a+(|:) = nonEmpty++-- | Tries to convert a list to a @NonEmpty@ returning @Nothing@ if the given list is empty.+toNonEmpty :: [a] -- ^ The list to convert.+ -> Maybe (NonEmpty a)+toNonEmpty [] = Nothing+toNonEmpty (h:t) = Just (NonEmpty h t)++-- | /WARNING: Fails if given the empty list./+-- Tries to convert a list to a @NonEmpty@.+unsafeToNonEmpty :: [a] -- ^ The list to convert (must not be empty).+ -> NonEmpty a+unsafeToNonEmpty = fromMaybe (error "unsafeToNonEmpty on empty list") . toNonEmpty++-- | Prepends a value to a non-empty list.+(.:) :: a -- ^ The value to prepend.+ -> NonEmpty a -- ^ The non-empty list to prepend to.+ -> NonEmpty a+a .: NonEmpty h t = NonEmpty a (h:t)++-- | Prepends a non-empty list to another non-empty list.+(.++) :: NonEmpty a -- ^ The non-empty list to prepend.+ -> NonEmpty a -- ^ The non-empty list to prepend to.+ -> NonEmpty a+NonEmpty a b .++ NonEmpty c d = NonEmpty a (b ++ c:d)++-- | Reverses the elements of the (finite) non-empty list.+reverse :: NonEmpty a+ -> NonEmpty a+reverse = list L.reverse++scanl :: (b -> a -> b)+ -> b+ -> NonEmpty a+ -> NonEmpty b+scanl = (list .) . L.scanl++scanl1 :: (a -> a -> a)+ -> NonEmpty a+ -> NonEmpty a+scanl1 = list . L.scanl1++scanr :: (a -> b -> b)+ -> b+ -> NonEmpty a+ -> NonEmpty b+scanr = (list .) . L.scanr++scanr1 :: (a -> a -> a)+ -> NonEmpty a+ -> NonEmpty a+scanr1 = list . L.scanr1++iterate :: (a -> a)+ -> a+ -> NonEmpty a+iterate = (unsafeToNonEmpty .) . L.iterate++repeat :: a+ -> NonEmpty a+repeat = unsafeToNonEmpty . L.repeat++cycle :: (Foldable f) =>+ f a+ -> NonEmpty a+cycle = list L.cycle++inits :: [a]+ -> NonEmpty [a]+inits = unsafeToNonEmpty . L.inits++tails :: [a]+ -> NonEmpty [a]+tails = unsafeToNonEmpty . L.tails++sort :: (Ord a) =>+ NonEmpty a+ -> NonEmpty a+sort = list L.sort++insert :: (Ord a) =>+ a ->+ NonEmpty a ->+ NonEmpty a+insert a = unsafeToNonEmpty . L.insert a . toList++zip :: NonEmpty a ->+ NonEmpty b ->+ NonEmpty (a, b)+zip a b = unsafeToNonEmpty (L.zip (toList a) (toList b))++unzip :: NonEmpty (a, b) ->+ (NonEmpty a, NonEmpty b)+unzip = (unsafeToNonEmpty *** unsafeToNonEmpty) . L.unzip . toList++-----------+-- TESTS --+-----------++instance (Arbitrary a) => Arbitrary (NonEmpty a) where+ arbitrary = nonEmpty <$> arbitrary <*> arbitrary+ shrink = (unsafeToNonEmpty <$>) . shrink . toList++prop_neHead :: String -> [String] -> Bool+prop_neHead h t = neHead (nonEmpty h t) == h++prop_neTail :: String -> [String] -> Bool+prop_neTail h t = neTail (nonEmpty h t) == t++prop_nonEmpty :: String -> [String] -> Bool+prop_nonEmpty h t = toList (nonEmpty h t) == h:t++prop_nonEmptyAlias :: String -> [String] -> Bool+prop_nonEmptyAlias h t = nonEmpty h t == h |: t++prop_toNonEmpty :: [String] -> Bool+prop_toNonEmpty x = toNonEmpty x == case x of [] -> Nothing+ (h:t) -> Just (nonEmpty h t)++prop_unsafeNonEmpty :: [String] -> Property+prop_unsafeNonEmpty x = not (null x) ==> prop_toNonEmpty x++prop_cons :: String -> NonEmpty String -> Bool+prop_cons a as = toList (a .: as) == a : toList as++prop_append :: NonEmpty String -> NonEmpty String -> Bool+prop_append a b = toList (a .++ b) == neHead a : neTail a ++ neHead b : neTail b++prop_reverse :: NonEmpty String -> Bool+prop_reverse x = (reverse . reverse) x == x++------------------+-- Not exported --+------------------++list :: (Foldable f) => ([a] -> [b]) -> f a -> NonEmpty b+list = (unsafeToNonEmpty .) . (. toList)
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright 2009 Tony Morris++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ NonEmptyList.cabal view
@@ -0,0 +1,25 @@+Name: NonEmptyList+Version: 0.0.1+License: BSD3+License-File: LICENSE+Synopsis: A list with a length of at least one.+Description: A list with a length of at least one and type-safe head/tail operations.+Homepage: http://code.google.com/p/nonempty/+Category: Data+Author: Tony Morris, Oliver Taylor+Maintainer: code@tmorris.net+Copyright: 2010 Tony Morris+build-type: Simple+cabal-version: >= 1.2++Flag small_base+ Description: Choose the new, split-up base package.++Library+ if flag(small_base)+ Build-Depends: base < 5 && >= 3, QuickCheck >= 2+ else+ Build-Depends: base < 5 && >= 3, QuickCheck >= 2++ GHC-Options: -Wall+ Exposed-Modules: Data.List.NonEmpty
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain