Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module is meant to augment the Data.List module. You may want to import both modules using the same alias. For example:
import qualified Data.List as List import qualified Data.List.Singleton as List
Synopsis
- singleton :: a -> [a]
Documentation
singleton :: a -> [a] Source #
O(1) Create a list with a single element in it.
>>>
singleton "pepperoni"
["pepperoni"]
There are many other ways to construct lists, so why might you prefer to use
singleton
? Here's a comparison with a few popular methods:
If you already have the element as a named value like
x
, you can wrap it up in a list literal:[x]
. You should prefer doing that to callingsingleton
.-- Instead of this:
singleton
x -- Consider this instead: [x]If you don't already have the element named, you can introduce a name by using a lambda:
(\ x -> [x])
. This is perhaps the most common way to create a singleton list, but it focuses more on mechanics than intent. Also it can be get little noisy, especially with identifiers longer than single letters likex
.-- Instead of this: g . (\ x -> [x]) . f -- Consider this instead: g .
singleton
. fIf you don't want to introduce a name at all, you can use an operator section:
(: [])
. This is more advanced because it requires familiarity with operator sections, list constructors, and how lists are desugared. (If you're not familiar with those concepts, the expression(: [])
is the same as(\ x -> x : [])
, which is the same as(\ x -> [x])
.) While those concepts are perhaps fundamental to understanding Haskell, you can get surprisingly far without them.-- Instead of this: g . (: []) . f -- Consider this instead: g .
singleton
. fIf you want to avoid lambdas, lists, and operators completely, you can use the
pure
method from theApplicative
type class. This has a lot of upsides: it's short, it's in the Prelude, and it's easy to search for. Unfortunately it has one downside: it's polymorphic. That means it can return any type that has anApplicative
instance, likeMaybe
orIO
. By comparisonsingleton
is monomorphic and can only produce a list. Usually the fact thatpure
is polymorphic isn't a problem, but sometimes it can produce confusing errors. Usingsingleton
can be a good way to force polymorphic code to use a list.>>>
import Data.Char (chr)
>>>
print (pure (chr 72))
... <interactive>:2:8: error: * Ambiguous type variable `f0' arising from a use of `pure' prevents the constraint `(Applicative f0)' from being solved. Probable fix: use a type annotation to specify what `f0' should be. ...>>>
print (singleton (chr 72))
"H"-- Instead of this: g .
pure
. f -- Consider this instead: g .singleton
. f
Now that you've seen a bunch of ways to create singleton lists, you may be
wondering why you'd want to do that at all. It's not often that you'll want
to make a list with one element in it and call it a day. Usually it's part
of a bigger computation. An illustrative example is the foldMap
function,
which can allow you to create a large data structure (like an entire list)
by stitching together a bunch of tiny lists. This can be an effective way to
convert between data types. For example:
>>>
import qualified Data.List.Singleton as List
>>>
import qualified Data.Set as Set
>>>
let aList = [2, 1, 3, 1]
>>>
foldMap Set.singleton aList
fromList [1, 2, 3]>>>
let aSet = Set.fromList [2, 3, 1]
>>>
foldMap List.singleton aSet
[1, 2, 3]
The name "singleton" was chosen to mirror similar functions provided by other libraries. For example:
Note that singleton
is lazy in its argument.
>>>
length (singleton undefined)
1
If you want to create a NonEmpty
list with a single
element in it, consider using singleton
from
Data.List.NonEmpty.Singleton.
Since: 1.0.0.0