Operators in Haskell
Explore arithmetic, comparison, boolean, list, and function operators in Haskell - where every operator is just a function in disguise
Operators in Haskell are not a special syntactic category - they are ordinary functions written in infix form. The expression 2 + 3 is really (+) 2 3, and you can define your own operators using any combination of symbols. This uniformity, combined with Haskell’s strong static type system and type classes, gives operators a clean and predictable behavior.
Because Haskell is purely functional, operators never mutate state. There are no compound assignment operators like += or ++ (in the C sense), and no increment or decrement. Every operator is a pure function that takes its arguments and returns a new value. Even the boolean operators && and || are functions - but with the helpful property that they short-circuit thanks to lazy evaluation.
This tutorial covers arithmetic, comparison, boolean, list, and function-level operators. You will see how to use familiar operators, how to turn any function into an operator with backticks, how to turn any operator into a function with parentheses, and how function composition (.) and application ($) form the backbone of idiomatic Haskell.
A Comprehensive Example
Create a file named operators.hs:
| |
This single program touches every major operator category. Notice that show converts values to their String representation so they can be concatenated with ++ and printed. The type annotations :: Double and :: Int exist only to pin down numeric types that would otherwise be ambiguous.
Operators as Functions, Functions as Operators
A defining feature of Haskell is that any operator is just a function with a symbolic name, and any function can be used in infix position.
Create a file named infix_demo.hs:
| |
The takeaways:
- Wrap an operator in parentheses, like
(+), to use it as a regular function. - Wrap a function name in backticks, like
`div`, to use it in infix position. - A section like
(+ 10)or(/ 2)is a partially applied operator - itself a function.
Operator Precedence and Associativity
Each operator has a precedence from 0 (lowest) to 9 (highest) and an associativity (left, right, or none). Function application has the highest binding strength of all, tighter than any operator. You can ask GHCi:
ghci> :info (+)
class Num a where
(+) :: a -> a -> a
...
infixl 6 +
ghci> :info (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
infixr 9 .
A small mental model:
^,^^,**(power): infixr 8*,/,`div`,`mod`: infixl 7+,-: infixl 6:,++(list cons and concat): infixr 5==,/=,<,<=,>,>=: infix 4&&: infixr 3||: infixr 2$(application): infixr 0 - the lowest, which is why it acts like “everything to my right is one argument”
The result: print $ 1 + 2 * 3 evaluates as print (1 + (2 * 3)), printing 7.
Running with Docker
| |
Expected Output
Output from runghc operators.hs:
--- Arithmetic ---
7 + 3 = 10
7 - 3 = 4
7 * 3 = 21
7 / 3 = 2.3333333333333335
7 `div` 3 = 2
7 `mod` 3 = 1
2 ^ 10 = 1024
--- Comparison ---
5 == 5: True
5 /= 3: True
5 > 3: True
5 <= 3: False
--- Boolean ---
True && False: False
True || False: True
not True: False
--- Lists & Strings ---
"Hello, " ++ "World!" = Hello, World!
1 : [2,3,4] = [1,2,3,4]
[1,2] ++ [3,4]= [1,2,3,4]
[10,20,30] !! 1 = 20
--- Composition (.) and Application ($) ---
((*2) . (+1)) 3 = 8
show $ 1 + 2 = 3
Output from runghc infix_demo.hs:
(+) 4 5 = 9
div 17 5 = 3
17 `div` 5 = 3
addTen 5 = 15
halve 9 = 4.5
foldr (+) 0 [1..5] = 15
Key Concepts
- Operators are functions. Any operator can be used as a regular function by wrapping it in parentheses:
(+) 2 3equals2 + 3. - Functions can be operators. Any named function can be called in infix style by wrapping it in backticks:
17 `div` 5. /vsdivvsmod.(/)requires aFractionaltype (likeDouble); usedivandmodfor integer division and remainder onIntegraltypes.- No mutation operators. Haskell has no
+=,++(increment), or--. Values are immutable, so every operator returns a new value. - Boolean short-circuiting comes from laziness.
&&and||are ordinary functions, but lazy evaluation means the right operand is only evaluated if needed. - Sections create partial applications.
(+ 10)is a function that adds 10;(10 -)is a function that subtracts its argument from 10. (Note:(- 10)is the number negative ten, not a section - usesubtract 10instead.) $for application,.for composition.f $ g xmeansf (g x)and removes parentheses;f . gbuilds a new function that runsgfirst, thenf.- Precedence matters. Function application binds tighter than any operator, so
f x + 1means(f x) + 1, notf (x + 1).
Comments
Loading comments...
Leave a Comment