A predicate that tells you whether something is empty is conventionally named null
.
You can find the following function in the Prelude
module:null
in Prelude
null :: Foldable t => t a -> Bool
What things are Foldable
?Foldable
One example is lists. null
can tell you whether a list is empty.
λ> null []
True
λ> null [1,2,3]
False
String
is a type alias for [Char]
, so null
can also tell you whether a string is the empty string.
λ> filter (not . null) ["one", "", "two", "", ""]
["one","two"]
The expression null xs
is usually equivalent to length xs == 0
. But null
may be much faster. Consider what happens if the list is quite large; length
must evaluate the entire list, so it takes a while. But null
doesn’t need to go any further than the first element to figure out that a list is not empty.
λ> xs = [1..100000000]
λ> length xs == 0
False
λ> null xs
False
Remember also that lists can be infinite, which means that the length
approach may not even work at all. null
will, though.
λ> xs = cycle [1,2,3]
λ> null xs
False
λ> length xs == 0
-- doesn't terminate, don't try this at home
Plenty of other “collection”-like types have Foldable
instances,Set
, Map
, HashSet
, HashMap
, Vector
not just lists. So null
also works with Set
, Map
, HashSet
, HashMap
, Vector
, etc. All of these modules also define their own null
functions, so you can use a less-polymorphic version instead of the method from Foldable
if you like:
:: Set a -> Bool
Data.Set.null :: Map k a -> Bool
Data.Map.Lazy.null :: HashSet a -> Bool
Data.HashSet.null :: HashMap k a -> Bool
Data.HashMap.Lazy.null :: Vector a -> Bool Data.Vector.null
There are some typesText
, ByteString
like Text
and ByteString
that aren’t “collections” in this sense, because they don’t have a type parameter, but are still sort of list-like. Text
is conceptually a list of characters, and ByteString
is conceptually a list of Word8
.A Word8
is a byte. These modules too define their own functions called null
that follow this pattern.
:: Text -> Bool
Data.Text.null :: ByteString -> Bool Data.ByteString.null
There are a few classes outside of base
that generalize these kinds of parameterless collections.
Whereas collections whose element type is parameterized belong to the Foldable
class, collections that only work with oneMonoFoldable
is defined in the mono-traversable
package. specific type of element belong to the MonoFoldable
class. A type family called Element
specifies what kind of elements each of these collections holds. The functions in the mono-traversable
package are all prefixed with the letter o
to distinguish them from similar-named things in Prelude
, so the emptiness test in MonoFoldable
is called onull
.
class MonoFoldable mono
where
onull :: mono -> Bool
-- ... and many other methods...
type family Element mono
type instance Element ByteString = Word8
type instance Element Text = Char
λ> import Data.MonoTraversable
λ> Data.MonoTraversable.onull (Data.Text.pack "")
True
λ> Data.MonoTraversable.onull (Data.Text.pack "abc")
False
The ListLike
packageListLike
is the name of both the class and the package. also defines a class with a null
method. It takes a different approach to handling monomorphic collections, using a multi-parameter typeclass instead of a type family. The ListLike
class is more specific than Foldable
and MonoFoldable
; it only pertains to things that have a linear structure, like lists and Vector
s. Types like Map
are not list-like in this way. The ListLike
documentation points out that technically Map
could have a ListLike
instance, but it behaves oddly.
class (FoldableLL full item, Monoid full) =>
ListLike full item | full -> item
where
null :: full -> Bool
-- ... and many other methods...
λ> import Data.ListLike
λ> Data.ListLike.null (Data.Text.pack "")
True
λ> Data.ListLike.null (Data.Text.pack "abc")
False