Haskell’s expressive type system means that type signatures can carry
a lot of information. Haskell’s polymorphism means that you sometime
write a function that works across an enormous range of types, and are
often left wondering “what do I actually call my variables?”. It is
often the case that there’s nothing to say beyond “this variable is a Functor
”,
or “this variable is a monadic action”, and so a single-letter variable
name is appropriate. An unofficial and largely undocumented convention
has emerged around these variable names, and so I wanted to write them
all down in one place.
It should go without saying that single-letter variable names are not always the answer. Like point-free style, it can sometimes obscures more than it helps and people get carried away with it. But when you have a highly polymorphic function and no good words to use, choosing the right letter can convey a surprising amount of meaning.
With the warning out of the way, the dictionary is after the jump.
a
, b
, c
,
d
Arbitrary types, usually of kind Type
, like the
a
in a Foldable t => t a
. Almost never used
as type variables for higher-kinded types, unless they’re
kind-polymorphic (like data Proxy (a :: k) = Proxy
).
a
(Rarely) the type of an Arrow
,
but because of the above common usage of a
, this is often
confusing. I recommend arr
or infix k
instead.
e
An “error” or exception type, though I personally prefer
ex
or exc
for true exceptions. Using
e
in a type like Either e a
indicates that
Either
is being used for its Monad
instance,
where Left
is considered an exceptional/early/error return,
and not as an unbiased choice between two types.
-- From packages `mtl`, `generic-lens`:
trySomething ::
MonadError e m, AsType SomeSpecificError e) =>
(SomeArgument ->
SomeResponse m
f
, g
, h
Used to indicate Functor
and “Functor
-like”
types including Applicative
,
Alternative
,
and their contravariant versions Contravariant
,
Divisible
,
and Decidable
.
i
, j
An index: a type that identifies an element in a structure (a key in
a key-value map; an Int
for a list, vector, or sequence;
etc).
-- From package `indexed-traversable`:
class Functor f => FunctorWithIndex i f | f -> i where
imap :: (i -> a -> b) -> f a -> f b
instance FunctorWithIndex Int List
instance FunctorWithIndex k (Map k)
k
Most commonly the k
eys of a key-value map, or the arrows
of a category. The latter (mnemonic: k
ategory) is sometimes
written infix. Also used as the “k
ind variable” for a
poly-kinded type.
-- From package `containers`:
mapWithKey ::
-> a -> b) ->
(k Map k a ->
Map k b
-- From package `categories`:
class Category k => HasTerminalObject k where
type Terminal k :: Type
terminate :: a `k` Terminal k
data Proxy (a :: k) = Proxy
-- ^-- The variable `a` has polymorphic kind.
m
A Monoid
or Monad
.
n
is sometimes also used when a second type variable is
needed, but is hard to visually distinguish from m
.
Consider m'
, m1
and m2
, or (for
Monad
s) f
and g
instead.
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
(>>=) :: Monad m => m a -> (a -> m b) -> m b
n
A type-level natural number.
p
, q
Mnemonically, a Profunctor
,
but often used for Bifunctor
s
as well. (The obvious first choice — b
— would clash with
the use of a
/b
/c
/d
for arbitrary types.)
-- From package `profunctors`:
class Profunctor p where
dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
lmap :: (a -> b) -> p b c -> p a c
rmap :: (b -> c) -> p a b -> p a c
class (forall a. Functor (p a)) => Bifunctor p where
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
first :: (a -> b) -> p a c -> p b c
second :: (b -> c) -> p a b -> p a c
r
A “return type”. Often used as the result type for streams and the like, as well as in type signatures for functions written in continuation-passing style:
-- From package `streaming`:
data Stream f m r
-- ^-- Result type of the stream.
-- From package `constraints-extras`:
class Has c f where
has :: forall a r. f a -> (c a => r) -> r
-- ^ ^
-- Continuation-passing style: the return type
-- of the function argument is the return type
-- of the whole function.
s
, t
, a
,
b
These four type variables often appear together in lenses or other
optics. The simplest complete example is a Lens s t a b
: it
can extract an a
from an s
and overwrite it
with a b
. Doing so would produce a value of type
t
.
-- A lens into the second part of a 2-tuple.
-- Inspired by package `lens`, but less polymorphic to make the point clear.
_2 :: Lens (x, c) (x, d) c d
-- ^ ^ ^ ^-- `b`: Type of the new value to put back in.
-- | | '---- `a`: Type of the value extracted from the tuple.
-- | '--------- `t`: Type of the tuple with a new value written back.
-- '---------------- `s`: Type of the initial tuple that is focused upon.
s
A state type, like the ones plumbed around by StateT
.
-- From package `mtl`.
modify :: MonadState s m => (s -> s) -> m ()
t
Traversable
structures. Foldable
is a superclass of Traversable
, so Foldable
s
are often called t
as well:
class Foldable t where
foldMap :: Monoid m => (a -> m) -> t a -> m
x
A type that is ignored, irrelevant, or inaccessible:
-- From package `streaming`:
maps ::
Monad m, Functor f) =>
(forall x. f x -> g x) ->
(-- ^-- The function passed in here cannot know anything
-- interesting about `x`, so it is "inaccessible".
Stream f m r ->
Stream g m r
-- From package `streaming`:
for ::
Monad m, Functor f) =>
(Stream (Of a) m r ->
-> Stream f m x) ->
(a -- ^-- This x is not referenced elsewhere; `for`
-- discards the result of the substreams.
Stream f m r
I have not seen as many important single-letter variable names in common use. This might be because arguments often carry more semantic information than types and so can be given usage-specific names, or it might be that point-free code has meant that it isn’t as necessary to invent names that often get elided.
b
An arbitrary ByteString
. I personally am not a fan of
using b
or bs
for this: there is often a short
word that describes what it actually is, and if it truly is an arbitrary
collection of bytes, then bytes
is only five
characters.
e
An error or exception, though I often prefer err
for
error types and ex
or exc
for true
exceptions.
f
, g
, h
Arbitrary functions.
h
Sometimes used for the h
ead of a sequence, but the
x:xs
notation is more common.
i
, j
, k
An integral value, or (less common) an index into a data structure.
k
A key for a key-value data structure like a
Data.Map.Map
, or a continuation parameter. (Mnemonic:
k
ontinuation)
-- From package `transformers`:
runCont :: Cont r a -> (a -> r) -> r
= runIdentity (runContT m (Identity . k))
runCont m k -- ^-- The continuation parameter.
m
A Monad
ic action or a Monoid
al value.
n
A numeric (often Natural
or at least Integral)
quantity, where it is the single induction variable.
p
, q
Most commonly stands for a Profunctor
or
Bifunctor
.
p
p
is sometimes used to name a p
roposition —
a Bool
with no semantic meaning that we can see. All we
care about is whether it is True
or False
.
It is also rarely used for “predicates”.
A predicate is (almost always) represented by a function
(a -> Bool)
but it generally written out either as the
abbreviation pred_
(pred
without the
underscore clashes with a method from class Enum
) or with
the standard variable name f
.
when :: Applicative f => Bool -> f () -> f ()
= if p then s else pure () when p s
s
Sometimes used for an arbitrary String
or
Text
. str
is usually more common, or
c:cs
or ch:chs
if recursing over individual
Char
s (the s
suffix denotes plural “chars”;
this is also discussed in the section on x
, y
,
z
).
t
An arbitrary Text
value, or sometimes a time value. I am
leery of using t
for times, as times often come with some
contextual meaning attached to them and can be given better names like
now
or createdAt
.
t
is sometimes also used for the t
ail of a
sequence, but the x:xs
notation is more common.
v
The value of an entry in a key-value data structure like a
Data.Map.Map
.
r
A result of some sort.
x
, y
, z
An arbitrary value about which nothing is known. Often seen with a
suffix s
to pluralise the variable and denote a collection
of arbitrary values. Read xs
, ys
,
zs
as “eckses”, “wyes”, and “zeds” (though American readers
may disagree on the final one).
map :: (a -> b) -> [a] -> [b]
map f list = case list of
-> []
[]
-- `x` binds one value from the list head;
-- `xs` binds many values from the list tail.
:xs -> f x : map f xs x
_
(Underscore)Not a variable name, but a blank pattern. A pattern that matches anything but binds no variable to the matched data.
Thanks to Fraser Tweedale for suggesting that I include type
variables {s
, t
, a
,
b
}; type variable k
as a polymorphic kind
variable; term variables h
and t
for head and
tail; term variables k
and v
for key-value
entries; and _
as blank pattern.
Thanks to /u/gasche
on Reddit for reminding me that
p
is often used for p
redicates and
p
ropositions.
Thanks to /u/maxigit
on discourse.haskell.org for
suggesting e
rror, n
atural number,
s
tate, and t
ime.
Thanks to /u/enobayram
on Reddit for also suggesting
n
.