Skip to content

⚙️ Plutus Tutorial: Haskell Language Extensions for Smart Contracts

Bernard Sibanda edited this page Oct 28, 2025 · 1 revision

📑 Table of Contents

  1. 💎 Introduction
  2. 🧩 What Are Haskell Language Extensions?
  3. 🧠 Why Plutus Needs Them
  4. 🌐 Plutus Extensions Map (Visual Overview)
  5. ⚒️ Core On-Chain Extensions
  6. 🔧 Deriving and Serialization Extensions
  7. 🧮 Type-Level and Typed-Script Extensions
  8. 🧩 Syntax and Functional Control Extensions
  9. 🪄 Off-Chain and Emulator Extensions
  10. 🧾 Glossary of Key Extensions
  11. 🧭 Conclusion

1. 💎 Introduction

Plutus, the smart contract language for Cardano, is built entirely in Haskell, but with restrictions and extensions that tailor it for blockchain execution.

Writing Plutus code means writing two worlds of Haskell:

  • 🟦 On-chain — compiled to Plutus Core, run by Cardano nodes.
  • 🟩 Off-chain — runs on users’ machines/wallets.

Because these environments differ, Plutus uses a special set of Haskell language extensions to safely compile, serialize, and manage contracts.

2. 🧩 What Are Haskell Language Extensions?

Language extensions modify the compiler’s behavior to unlock features not included in standard Haskell 2010.

Declared at the top of your file:

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}

Each extension enables additional syntax, typing rules, or compile-time features — crucial for converting your high-level code into Plutus Core bytecode.

3. 🧠 Why Plutus Needs Them

Purpose Why It’s Needed
🧱 Compile-time generation Converts Haskell into Plutus Core using PlutusTx.compile.
⚙️ Type-level programming Safely enforce Datum, Redeemer, and ScriptContext types.
🧮 Serialization Automatically derive IsData, FromJSON, etc.
🚫 Safety Removes unsafe or non-deterministic Haskell features.
🧭 Clarity Reduces ambiguity between on-chain and off-chain code.

4. 🌐 Plutus Extensions Map (Visual Overview)

Below is a color-coded classification of extensions used in Plutus development.

Layer Color Description
🟦 On-chain 🔵 Used for validators, minting policies, and scripts compiled to Plutus Core.
🟩 Off-chain 🟢 Used for contract endpoints, wallet logic, and emulators.
🟣 Shared 🟣 Used in both environments.

🧭 Visual Map

                           ┌────────────────────────────┐
                           │        Shared 🟣            │
                           │  DeriveAnyClass             │
                           │  DeriveGeneric              │
                           │  TypeApplications           │
                           │  ScopedTypeVariables        │
                           └────────────┬────────────────┘
                                        │
      ┌─────────────────────────────────┼─────────────────────────────────┐
      │                                 │                                 │
┌───────────────┐               ┌──────────────────┐               ┌────────────────┐
│ On-Chain 🔵   │               │ Off-Chain 🟢     │               │ Serialization 🟣│
│ TemplateHaskell│              │ OverloadedLabels │               │ IsData, ToJSON │
│ NoImplicitPrelude│            │ OverloadedStrings│               │ DeriveGeneric  │
│ DataKinds        │            │ NamedFieldPuns   │               │ DeriveAnyClass │
│ GADTs, TypeOps   │            │ FlexibleInstances│               │ TypeFamilies   │
│ TypeFamilies     │            │ QuasiQuotes      │               │ DerivingStrategies │
└─────────────────┘             └──────────────────┘               └────────────────┘

🧩 Interpretation:

  • Blue: On-chain extensions necessary for deterministic blockchain execution.
  • Green: Off-chain Haskell features to handle wallet, emulator, and API interactions.
  • Purple: Shared features — safe to use in both layers.

5. ⚒️ Core On-Chain Extensions

These extensions are fundamental for writing validators and minting policies.

Extension 🧰 Purpose 💡 Example
TemplateHaskell Compiles Haskell to Plutus Core. `$$(PlutusTx.compile [ mkValidator ])`
NoImplicitPrelude Replaces standard Prelude with PlutusTx.Prelude. import PlutusTx.Prelude
DataKinds Promotes data constructors to the type level. type Example = 'True
ScopedTypeVariables Keeps type variables in scope. foo :: forall a. a -> a
BangPatterns Enables strict evaluation. f !x = x + 1

🟦 Used in: On-chain scripts, validators, minting policies.

✅ Example

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ScopedTypeVariables #-}

import qualified PlutusTx
import qualified PlutusTx.Prelude as P

6. 🔧 Deriving and Serialization Extensions

These help Plutus automatically derive serialization logic for datums and redeemers.

Extension 🧰 Purpose 💡 Example
DeriveAnyClass Derive IsData for blockchain serialization. deriving (PlutusTx.IsData)
DeriveGeneric Provides Generic for auto-derived instances. deriving (Generic)
DerivingStrategies Controls deriving style. deriving stock (Eq)
GeneralizedNewtypeDeriving Inherit behaviors in newtypes. newtype MyDatum = MyDatum Int deriving newtype (Eq)
StandaloneDeriving Allows separate deriving declarations. deriving instance Eq MyDatum

🟣 Used in: Both on-chain (serialization) and off-chain (Aeson JSON).

7. 🧮 Type-Level and Typed-Script Extensions

Critical for type-safe scripts and custom validator types.

Extension 🧠 Purpose 💡 Example
TypeApplications Specify type parameters explicitly. foo @Integer 10
TypeFamilies Associate types with classes. type family DatumType s
TypeOperators Custom infix type constructors. a :-> b
GADTs Used in typed Plutus scripts. data MyType a where ...
KindSignatures Annotate kinds for clarity. data MyData (a :: Type)

🟦 Used in: Typed validators (Typed.Scripts.V2), state machines.

8. 🧩 Syntax and Functional Control Extensions

These enhance expressiveness and clarity in contracts.

Extension 🧰 Purpose 💡 Example
LambdaCase Concise pattern-matching lambdas. foo = \case Just x -> x; Nothing -> 0
OverloadedStrings String literals as BuiltinByteString. P.trace "debug"
MultiParamTypeClasses Classes with multiple type params. `class Convertible a b a -> b`
FunctionalDependencies Guides inference with above. ` a -> b`
RecordWildCards Extract record fields easily. TxInfo{..}
NamedFieldPuns Simplify field naming. TxInfo{txInputs}

🟣 Used in: Both layers for code clarity and developer ergonomics.

9. 🪄 Off-Chain and Emulator Extensions

Used for wallet logic, endpoints, and emulator testing.

Extension 🧰 Purpose 💡 Example
OverloadedLabels Endpoint syntax like @"deposit". callEndpoint @"lock" h1 param
FlexibleInstances Flexible instance definitions. instance FromJSON MyDatum
DuplicateRecordFields Same record field names in different types. data Wallet = Wallet {id :: Int}
QuasiQuotes Embed mini DSLs. `[quasi ... ]`
NumericUnderscores Improves number readability. 1_000_000

🟩 Used in: Plutus.Contract, Plutus.Trace.Emulator, Ledger.Value.

10. 🧾 Glossary of Key Extensions

Extension Description
TemplateHaskell Enables compile-time metaprogramming (PlutusTx.compile).
NoImplicitPrelude Uses deterministic PlutusTx Prelude instead of Haskell’s.
DataKinds Promotes constructors to type level.
DeriveAnyClass / DeriveGeneric Auto-generate serialization logic.
TypeApplications Apply types directly at call sites.
OverloadedStrings Interprets "hello" as BuiltinByteString.
OverloadedLabels Used in Contract endpoints.
GADTs / TypeFamilies Advanced type safety for validator logic.

11. 🧭 Conclusion

Plutus relies heavily on Haskell extensions to safely bridge high-level code and blockchain-level execution. ✅ On-chain code must stay deterministic and minimal — it uses extensions like:

TemplateHaskell
NoImplicitPrelude
DataKinds
TypeApplications

Off-chain code can be flexible, using:

OverloadedLabels
DeriveGeneric
FlexibleInstances

Shared extensions (DeriveAnyClass, ScopedTypeVariables, etc.) work seamlessly across both environments.

Clone this wiki locally