Skip to content

Haskell & Plutus Language Extensions

Bernard Sibanda edited this page May 20, 2025 · 6 revisions

Haskell & Plutus Language Extensions

Table of Contents

Extensions

1. GADTs

Category: Type System
Scope: Haskell
How to Enable: {-# LANGUAGE GADTs #-}

When to Use:
When you need more precise typing in data constructors (e.g., embedded DSLs).

Usage Example:

data Expr a where
  Lit :: Int -> Expr Int
  Add :: Expr Int -> Expr Int -> Expr Int

2. TypeFamilies

Category: Type System
Scope: Haskell
How to Enable: {-# LANGUAGE TypeFamilies #-}

When to Use:
When you need type-level functions associated with type classes.

Usage Example:

type family F a :: *
type instance F Int = Bool

3. MultiParamTypeClasses

Category: Type Classes
Scope: Haskell
How to Enable: {-# LANGUAGE MultiParamTypeClasses #-}

When to Use:
When a type class logically relates more than one type.

Usage Example:

class Convertible a b where
  convert :: a -> b

4. FunctionalDependencies

Category: Type Classes
Scope: Haskell
How to Enable: {-# LANGUAGE FunctionalDependencies #-}

When to Use:
To help GHC infer types in multi-parameter type classes.

Usage Example:

class Convertible a b | a -> b where
  convert :: a -> b

5. DataKinds

Category: Type-Level Programming
Scope: Haskell
How to Enable: {-# LANGUAGE DataKinds #-}

When to Use:
For type-level programming with promoted data constructors.

Usage Example:

data Nat = Zero | Succ Nat
data Vec (n :: Nat) a = ...

6. ViewPatterns

Category: Pattern Matching
Scope: Haskell
How to Enable: {-# LANGUAGE ViewPatterns #-}

When to Use:
When pattern matching requires function application results.

Usage Example:

f (length -> 0) = "Empty"
f _ = "Not Empty"

7. PatternSynonyms

Category: Pattern Matching
Scope: Haskell
How to Enable: {-# LANGUAGE PatternSynonyms #-}

When to Use:
To simplify or abstract complex patterns.

Usage Example:

pattern Zero <- 0
pattern Succ n <- (n + 1)

8. OverloadedStrings

Category: Literals
Scope: Haskell
How to Enable: {-# LANGUAGE OverloadedStrings #-}

When to Use:
When using string literals as Text, ByteString, etc.

Usage Example:

myText :: Text
myText = "hello"

9. TemplateHaskell

Category: Meta-programming
Scope: Haskell
How to Enable: {-# LANGUAGE TemplateHaskell #-}

When to Use:
For compile-time code generation (e.g., JSON derivation).

Usage Example:

$(deriveJSON defaultOptions ''MyType)

10. RecordWildCards

Category: Records
Scope: Haskell
How to Enable: {-# LANGUAGE RecordWildCards #-}

When to Use:
To reduce boilerplate in record pattern matching.

Usage Example:

printPerson Person{..} = putStrLn name

11. KindSignatures

Category: Type-Level Programming
Scope: Haskell
How to Enable: {-# LANGUAGE KindSignatures #-}

When to Use:
To explicitly specify the kind of a type parameter.

Usage Example:

data Proxy (a :: *) = Proxy

12. ScopedTypeVariables

Category: Type System
Scope: Haskell
How to Enable: {-# LANGUAGE ScopedTypeVariables #-}

When to Use:
When you need to reuse type variables across scopes.

Usage Example:

f :: forall a. a -> a
f x = let g :: a -> a
g y = y in g x

13. RankNTypes

Category: Type System
Scope: Haskell
How to Enable: {-# LANGUAGE RankNTypes #-}

When to Use:
When you need higher-rank polymorphism in function types.

Usage Example:

f :: (forall a. a -> a) -> Int

14. OverloadedLists

Category: Literals
Scope: Haskell
How to Enable: {-# LANGUAGE OverloadedLists #-}

When to Use:
To allow list literals to work with any IsList type.

Usage Example:

myVec :: Vector Int
myVec = [1, 2, 3]

15. DeriveGeneric

Category: Deriving
Scope: Haskell
How to Enable: {-# LANGUAGE DeriveGeneric #-}

When to Use:
To derive Generic instance for use with libraries like Aeson.

Usage Example:

data Person = Person String Int deriving (Generic)

16. StandaloneDeriving

Category: Deriving
Scope: Haskell
How to Enable: {-# LANGUAGE StandaloneDeriving #-}

When to Use:
To derive instances for types declared elsewhere or abstract.

Usage Example:

deriving instance Show MyType

17. LambdaCase

Category: Pattern Matching
Scope: Haskell
How to Enable: {-# LANGUAGE LambdaCase #-}

When to Use:
For concise anonymous functions with pattern matching.

Usage Example:

f = \case Just x -> x; Nothing -> 0

18. QuasiQuotes

Category: Meta-programming
Scope: Haskell
How to Enable: {-# LANGUAGE QuasiQuotes #-}

When to Use:
To embed DSLs or formatted literals inside Haskell code.

Usage Example:

[sql|SELECT * FROM users|]

19. RebindableSyntax

Category: Syntax
Scope: Haskell
How to Enable: {-# LANGUAGE RebindableSyntax #-}

When to Use:
To override built-in Haskell syntax like if, do, etc.

Usage Example:

ifThenElse :: Bool -> a -> a -> a

20. NamedFieldPuns

Category: Records
Scope: Haskell
How to Enable: {-# LANGUAGE NamedFieldPuns #-}

When to Use:
When you want to write concise record pattern bindings.

Usage Example:

greet Person{name} = putStrLn name

21. NoImplicitPrelude

Category: Prelude Control
Scope: Plutus
How to Enable: {-# LANGUAGE NoImplicitPrelude #-}

When to Use:
When working with PlutusTx which provides a custom Prelude.

Usage Example:

-- disables standard Prelude
import PlutusTx.Prelude

22. TemplateHaskell

Category: Meta-programming
Scope: Plutus
How to Enable: {-# LANGUAGE TemplateHaskell #-}

When to Use:
Required by PlutusTx compiler to generate on-chain data encodings.

Usage Example:

$(PlutusTx.makeIsData ''MyDatum)

23. DeriveAnyClass

Category: Deriving
Scope: Plutus
How to Enable: {-# LANGUAGE DeriveAnyClass #-}

When to Use:
Used to derive PlutusTx typeclass instances like ToData and FromData.

Usage Example:

data MyDatum = ... deriving (Generic, ToData)

24. DeriveGeneric

Category: Deriving
Scope: Plutus
How to Enable: {-# LANGUAGE DeriveGeneric #-}

When to Use:
Needed for DeriveAnyClass to derive ToData and similar.

Usage Example:

data MyDatum = MyDatum Int deriving (Generic)

25. TypeApplications

Category: Type System
Scope: Plutus
How to Enable: {-# LANGUAGE TypeApplications #-}

When to Use:
Explicitly apply types in functions like toData, fromData.

Usage Example:

PlutusTx.toData @MyDatum datum

26. table

Extension | Usage Example | When to Use | How to Enable | Category | Scope -- | -- | -- | -- | -- | -- GADTs | data Expr a where Lit :: Int -> Expr Int Add :: Expr Int -> Expr Int -> Expr Int | When you need more precise typing in data constructors (e.g., embedded DSLs). | {-# LANGUAGE GADTs #-} | Type System | Haskell TypeFamilies | type family F a :: *type instance F Int = Bool | When you need type-level functions associated with type classes. | {-# LANGUAGE TypeFamilies #-} | Type System | Haskell MultiParamTypeClasses | class Convertible a b where convert :: a -> b | When a type class logically relates more than one type. | {-# LANGUAGE MultiParamTypeClasses #-} | Type Classes | Haskell FunctionalDependencies | class Convertible a b \| a -> b where convert :: a -> b | To help GHC infer types in multi-parameter type classes. | {-# LANGUAGE FunctionalDependencies #-} | Type Classes | Haskell DataKinds | data Nat = Zero \| Succ Natdata Vec (n :: Nat) a = ... | For type-level programming with promoted data constructors. | {-# LANGUAGE DataKinds #-} | Type-Level Programming | Haskell ViewPatterns | f (length -> 0) = "Empty"f _ = "Not Empty" | When pattern matching requires function application results. | {-# LANGUAGE ViewPatterns #-} | Pattern Matching | Haskell PatternSynonyms | pattern Zero <- 0pattern Succ n <- (n + 1) | To simplify or abstract complex patterns. | {-# LANGUAGE PatternSynonyms #-} | Pattern Matching | Haskell OverloadedStrings | myText :: TextmyText = "hello" | When using string literals as `Text`, `ByteString`, etc. | {-# LANGUAGE OverloadedStrings #-} | Literals | Haskell TemplateHaskell | $(deriveJSON defaultOptions ''MyType) | For compile-time code generation (e.g., JSON derivation). | {-# LANGUAGE TemplateHaskell #-} | Meta-programming | Haskell RecordWildCards | printPerson Person{..} = putStrLn name | To reduce boilerplate in record pattern matching. | {-# LANGUAGE RecordWildCards #-} | Records | Haskell KindSignatures | data Proxy (a :: *) = Proxy | To explicitly specify the kind of a type parameter. | {-# LANGUAGE KindSignatures #-} | Type-Level Programming | Haskell ScopedTypeVariables | f :: forall a. a -> af x = let g :: a -> ag y = y in g x | When you need to reuse type variables across scopes. | {-# LANGUAGE ScopedTypeVariables #-} | Type System | Haskell RankNTypes | f :: (forall a. a -> a) -> Int | When you need higher-rank polymorphism in function types. | {-# LANGUAGE RankNTypes #-} | Type System | Haskell OverloadedLists | myVec :: Vector IntmyVec = [1, 2, 3] | To allow list literals to work with any `IsList` type. | {-# LANGUAGE OverloadedLists #-} | Literals | Haskell DeriveGeneric | data Person = Person String Int deriving (Generic) | To derive `Generic` instance for use with libraries like Aeson. | {-# LANGUAGE DeriveGeneric #-} | Deriving | Haskell StandaloneDeriving | deriving instance Show MyType | To derive instances for types declared elsewhere or abstract. | {-# LANGUAGE StandaloneDeriving #-} | Deriving | Haskell LambdaCase | f = \case Just x -> x | Nothing -> 0 | For concise anonymous functions with pattern matching. | {-# LANGUAGE LambdaCase #-} | Pattern Matching QuasiQuotes | [sql\|SELECT * FROM users\|] | To embed DSLs or formatted literals inside Haskell code. | {-# LANGUAGE QuasiQuotes #-} | Meta-programming | Haskell RebindableSyntax | ifThenElse :: Bool -> a -> a -> a | To override built-in Haskell syntax like `if`, `do`, etc. | {-# LANGUAGE RebindableSyntax #-} | Syntax | Haskell NamedFieldPuns | greet Person{name} = putStrLn name | When you want to write concise record pattern bindings. | {-# LANGUAGE NamedFieldPuns #-} | Records | Haskell NoImplicitPrelude | -- disables standard Preludeimport PlutusTx.Prelude | When working with PlutusTx which provides a custom Prelude. | {-# LANGUAGE NoImplicitPrelude #-} | Prelude Control | Plutus TemplateHaskell | $(PlutusTx.makeIsData ''MyDatum) | Required by PlutusTx compiler to generate on-chain data encodings. | {-# LANGUAGE TemplateHaskell #-} | Meta-programming | Plutus DeriveAnyClass | data MyDatum = ... deriving (Generic, ToData) | Used to derive PlutusTx typeclass instances like `ToData` and `FromData`. | {-# LANGUAGE DeriveAnyClass #-} | Deriving | Plutus DeriveGeneric | data MyDatum = MyDatum Int deriving (Generic) | Needed for `DeriveAnyClass` to derive `ToData` and similar. | {-# LANGUAGE DeriveGeneric #-} | Deriving | Plutus TypeApplications | PlutusTx.toData @MyDatum datum | Explicitly apply types in functions like `toData`, `fromData`. | {-# LANGUAGE TypeApplications #-} | Type System | Plutus

Clone this wiki locally