Most Haskell functions are called with the function name followed by arguments (prefix notation). For functions that accept two arguments like (+), it sometimes makes sense to provide an argument before and after the function (infix).
&&
is logical AND, ||
is logical OR.
==
is equality, /=
non-equality, <
/ <=
lesser and >
/ >=
greater operators.
The numerical operators +
, -
and /
behave largely as you'd expect. (Division works only on fractional numbers to avoid rounding issues – integer division must be done with quot
or div
). More unusual are Haskell's three exponentiation operators:
^
takes a base of any number type to a non-negative, integral power. This works simply by (fast) iterated multiplication. E.g.
4^5 ≡ (4*4)*(4*4)*4
^^
does the same in the positive case, but also works for negative exponents. E.g.
3^^(-2) ≡ 1 / (2*2)
Unlike ^
, this requires a fractional base type (i.e. 4^^5 :: Int
will not work, only 4^5 :: Int
or 4^^5 :: Rational
).
**
implements real-number exponentiation. This works for very general arguments, but is more computionally expensive than ^
or ^^
, and generally incurs small floating-point errors.
2**pi ≡ exp (pi * log 2)
There are two concatenation operators:
:
(pronounced cons) prepends a single argument before a list. This operator is actually a constructor and can thus also be used to pattern match (“inverse construct”) a list.
++
concatenates entire lists.
[1,2] ++ [3,4] ≡ 1 : 2 : [3,4] ≡ 1 : [2,3,4] ≡ [1,2,3,4]
!!
is an indexing operator.
[0, 10, 20, 30, 40] !! 3 ≡ 30
Note that indexing lists is inefficient (complexity O(n) instead of O(1) for arrays or O(log n) for maps); it's generally preferred in Haskell to deconstruct lists by folding ot pattern matching instead of indexing.
$
is a function application operator.
f $ x ≡ f x
≡ f(x) -- disapproved style
This operator is mostly used to avoid parentheses. It also has a strict version $!
, which forces the argument to be evaluated before applying the function.
.
composes functions.
(f . g) x ≡ f (g x) ≡ f $ g x
>>
sequences monadic actions. E.g. writeFile "foo.txt" "bla" >> putStrLn "Done."
will first write to a file, then print a message to the screen.
>>=
does the same, while also accepting an argument to be passed from the first action to the following. readLn >>= \x -> print (x^2)
will wait for the user to input a number, then output the square of that number to the screen.
In Haskell, you can define any infix operator you like. For example, I could define the list-enveloping operator as
(>+<) :: [a] -> [a] -> [a]
env >+< l = env ++ l ++ env
GHCi> "**">+<"emphasis"
"**emphasis**"
You should always give such operators a fixity declaration, like
infixr 5 >+<
(which would mean >+<
binds as tightly as ++
and :
do).
Because infixes are so common in Haskell, you will regularly need to look up their signature etc.. Fortunately, this is just as easy as for any other function:
The Haskell search engines Hayoo and Hoogle can be used for infix operators, like for anything else that's defined in some library.
In GHCi or IHaskell, you can use the :i
and :t
(info and type) directives to learn the basic properties of an operator. For example,
Prelude> :i +
class Num a where
(+) :: a -> a -> a
...
-- Defined in ‘GHC.Num’
infixl 6 +
Prelude> :i ^^
(^^) :: (Fractional a, Integral b) => a -> b -> a
-- Defined in ‘GHC.Real’
infixr 8 ^^
This tells me that ^^
binds more tightly than +
, both take numerical types as their elements, but ^^
requires the exponent to be integral and the base to be fractional.
The less verbose :t
requires the operator in parentheses, like
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool