Skip to content

Haskell Pure Functions Guide — Referential Transparency and Function Signatures

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about Haskell Pure Functions Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Haskell pure functions are the foundation of the language -- they always produce the same output for the same input and have no side effects, making code predictable, testable, and safe to refactor through referential transparency.

Pure Functions

-- Pure: same input always gives same output
add :: Int -> Int -> Int
add x y = x + y

-- Pure: no side effects
double :: Int -> Int
double x = x * 2

-- Impure (IO): side effects are explicit
printDouble :: Int -> IO ()
printDouble x = print (x * 2)

Type Signatures

-- Function type: arg -> return
square :: Int -> Int
square x = x * x

-- Multiple arguments
multiply :: Int -> Int -> Int
multiply a b = a * b

-- Polymorphic
identity :: a -> a
identity x = x

Referential Transparency

-- These are equivalent:
result1 = add 5 (add 3 2)
-- Can replace (add 3 2) with 5:
result2 = add 5 5
-- Can replace (add 5 5) with 10:
result3 = 10
-- All produce the same result

Guards

describeAge :: Int -> String
describeAge age
  | age < 13  = "Child"
  | age < 20  = "Teenager"
  | age < 65  = "Adult"
  | otherwise = "Senior"

Common Mistakes

1. Mixing pure and impure code

Pure functions can't call IO functions directly. IO must be called from IO context.

2. Forgetting type signatures

While Haskell infers types, always write type signatures for top-level functions.

3. Expecting side effects in pure code

You can't print from a pure function. Return the data and print in the caller.

Practice Questions

1. What is referential transparency? An expression that can be replaced with its value without changing program behavior.

2. How do you distinguish pure from impure functions? Pure functions have no IO in their return type. Impure functions return IO a.

3. What does otherwise mean in guards? It's a synonym for True -- the default case in guard expressions.

FAQ

{{< faq question="Can I print for debugging in pure code?" >}} Use Debug.Trace.trace which outputs to stderr but is technically impure. Remove before production. {{< /faq >}}

{{< faq question="Why can't I use a pure computation result in IO?" >}} You can! Use let x = pureFunc arg inside a do block. Pure and IO compose naturally through monads. {{< /faq >}}

{{< faq question="What is the $ operator?" >}} Function application with low precedence: f $ x = f x. Eliminates parentheses: map show [1,2,3] vs map show $ [1,2,3]. {{< /faq >}}

What's Next

Now learn about Haskell's type system.

Topic Description Link
Types Algebraic data types {{< ref "04-types" >}}
Pattern Matching Destructuring data {{< ref "05-pattern-matching" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro