Skip to content

Conversation

@bezirg
Copy link
Contributor

@bezirg bezirg commented Nov 19, 2025

Pre-submit checklist:

  • Branch
    • Tests are provided (if possible)
    • Commit sequence broadly makes sense
    • Key commits have useful messages
    • Changelog fragments have been written (if appropriate)
    • Relevant tickets are mentioned in commit messages
    • Formatting, PNG optimization, etc. are updated
  • PR
    • (For external contributions) Corresponding issue exists and is linked in the description
    • Targeting master unless this is a cherry-pick backport
    • Self-reviewed the diff
    • Useful pull request description
    • Reviewer requested

@bezirg bezirg changed the title Bezirg/derive eq Add deriveEq for Plinth similar to deriving stock Eq Nov 19, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 24, 2025

Execution Budget Golden Diff

f96714c (master) vs 97a7b4b

output

plutus-benchmark/cardano-loans/test/9.6/main.golden.eval

Metric Old New Δ%
Flat Size 8_666 8_673 +0.08%

plutus-benchmark/coop/test/9.6/certMpBurning.golden.eval

Metric Old New Δ%
Flat Size 8_031 8_035 +0.05%

plutus-benchmark/coop/test/9.6/certMpMinting.golden.eval

Metric Old New Δ%
Flat Size 8_554 8_558 +0.05%

plutus-benchmark/coop/test/9.6/fsMpBurning.golden.eval

Metric Old New Δ%
Flat Size 7_395 7_399 +0.05%

plutus-benchmark/coop/test/9.6/fsMpMinting.golden.eval

Metric Old New Δ%
Flat Size 9_213 9_217 +0.04%

plutus-benchmark/linear-vesting/test/9.6/main.golden.eval

Metric Old New Δ%
Flat Size 2_860 2_864 +0.14%

plutus-benchmark/nofib/test/9.6/clausify-F5.golden.eval

Metric Old New Δ%
Flat Size 1_477 1_484 +0.47%

plutus-benchmark/nofib/test/9.6/knights10-4x4.golden.eval

Metric Old New Δ%
CPU 1_023_470_754 1_025_262_754 +0.18%
Memory 5_395_058 5_406_258 +0.21%
Flat Size 1_674 1_682 +0.48%

plutus-benchmark/nofib/test/9.6/queens4-bt.golden.eval

Metric Old New Δ%
Flat Size 1_764 1_767 +0.17%

plutus-benchmark/nofib/test/9.6/queens5-fc.golden.eval

Metric Old New Δ%
Flat Size 1_764 1_767 +0.17%

plutus-benchmark/script-contexts/test/V3/Data/9.6/purposeIsWellFormed-4.golden.eval

Metric Old New Δ%
Flat Size 1_839 1_843 +0.22%

This comment will get updated when changes are made.

@bezirg bezirg marked this pull request as ready for review November 24, 2025 10:07
@bezirg bezirg marked this pull request as draft November 24, 2025 10:07
@bezirg bezirg self-assigned this Nov 24, 2025
@bezirg bezirg force-pushed the bezirg/derive_eq branch 2 times, most recently from 5b30be7 to 5d931a0 Compare November 25, 2025 10:05
@bezirg bezirg marked this pull request as ready for review November 25, 2025 10:05
@bezirg bezirg requested review from SeungheonOh and Unisay and removed request for SeungheonOh November 25, 2025 10:05
@bezirg bezirg marked this pull request as draft November 25, 2025 13:42
@bezirg bezirg marked this pull request as ready for review November 25, 2025 13:50
@bezirg bezirg force-pushed the bezirg/derive_eq branch 5 times, most recently from 7593c53 to 3ca2a2e Compare November 26, 2025 11:18
Copy link
Collaborator

@SeungheonOh SeungheonOh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too confident in my ability to review TH code. So perhaps a look from @Unisay would be nice. But everything looks right from what I can tell.

Comment on lines +17 to +43
deriveEq ''()
deriveEq ''(,)
deriveEq ''(,,)
deriveEq ''(,,,)
deriveEq ''(,,,,)
deriveEq ''(,,,,,)
deriveEq ''(,,,,,,)
deriveEq ''(,,,,,,,)
deriveEq ''(,,,,,,,,)
deriveEq ''(,,,,,,,,,)
deriveEq ''(,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,,,,,)
deriveEq ''(,,,,,,,,,,,,,,,,,,,,,,,,,,)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The great pyramid

@SeungheonOh
Copy link
Collaborator

Also, can you check if this works with polymorphic phantom types? I'm curious as per #4537

@bezirg
Copy link
Contributor Author

bezirg commented Dec 1, 2025

Also, can you check if this works with polymorphic phantom types? I'm curious as per #4537

I will test it out

@bezirg
Copy link
Contributor Author

bezirg commented Dec 1, 2025

Also, can you check if this works with polymorphic phantom types? I'm curious as per #4537

Indeed, it does not work with polymorphic phantom types.

I don't know yet how to make it work.
One idea I had is to look at the datatype's kind using https://hackage.haskell.org/package/th-abstraction-0.7.1.0/docs/Language-Haskell-TH-Datatype.html#t:DatatypeInfo .

Unfortunately, it returns me kind the wrong kind *, whereas I was expecting kind forall k. k -> *. If I had the latter kind then I could infer that k is phantom. I think it is too much work , for little benefit. What do you think?

@bezirg bezirg requested a review from zliu41 December 4, 2025 16:52
@bezirg bezirg force-pushed the bezirg/derive_eq branch 3 times, most recently from 673b24b to f6a08c0 Compare December 15, 2025 14:00
@bezirg
Copy link
Contributor Author

bezirg commented Dec 15, 2025

Also, can you check if this works with polymorphic phantom types? I'm curious as per #4537

Phantom types should work now

Copy link
Member

@zliu41 zliu41 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use deriveEq on all the plutus-ledger-api Types?

@bezirg
Copy link
Contributor Author

bezirg commented Dec 15, 2025

Why not use deriveEq on all the plutus-ledger-api Types?

Good idea

@bezirg bezirg force-pushed the bezirg/derive_eq branch 2 times, most recently from d9a2637 to d5851d7 Compare December 16, 2025 16:58
@bezirg bezirg requested a review from zliu41 December 16, 2025 16:59

instance Haskell.Semigroup Value where
(<>) = unionWith (+)
instance Haskell.Eq Value where
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zliu41 Some cleanup along the way, and use a single implementation between PlutusTx && Haskell

Comment on lines +253 to +257
-- MAYBE: get rid of these and switch to deriving stock, when deriveOrd is merged
instance Eq a => Haskell.Eq (Extended a) where
(==) = (PlutusTx.==)

-- MAYBE: get rid of these and switch to deriving stock, when deriveOrd is merged
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be changed to stock deriving when deriveOrd PR is merged

Comment on lines +314 to +330
instance Haskell.Eq Value where
(==) = (PlutusTx.==)

instance Semigroup Value where
instance PlutusTx.Semigroup Value where
{-# INLINEABLE (<>) #-}
(<>) = unionWith (+)

instance Haskell.Monoid Value where
mempty = Value Map.empty
instance Haskell.Semigroup Value where
(<>) = (PlutusTx.<>)

instance Monoid Value where
instance PlutusTx.Monoid Value where
{-# INLINEABLE mempty #-}
mempty = Value Map.empty

instance Haskell.Monoid Value where
mempty = PlutusTx.mempty

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same cleanup and sharing between implementations

Comment on lines 111 to 113
-- FIXME: need deriveOrd to be merged to add this
-- deriveEq ''TxInfo

Copy link
Contributor Author

@bezirg bezirg Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because we have inside the datatype Maps, and keys to Maps need an Ord instance. I think it would be easier if we have the ord pr apply these changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is different, we don't have Eq AssocMap instances because of problem with duplicated entries

@bezirg
Copy link
Contributor Author

bezirg commented Dec 16, 2025

@zliu41 Can you take a look at the last commit only?

@bezirg bezirg force-pushed the bezirg/derive_eq branch 2 times, most recently from dd788a1 to ce324dd Compare December 17, 2025 11:24
@bezirg bezirg requested a review from a team December 20, 2025 13:52

{-| derive a PlutusTx.Eq instance for a datatype/newtype, similar to Haskell's `deriving stock Eq`.
One shortcoming compared to Haskell's deriving is that you cannot `PlutusTx.deriveEq` for polymorphic phantom types. -}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation claims you cannot derive for polymorphic phantom types, but PhantomADT test demonstrates it does work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a public function, it would make sense to better document limitations, etc:

{-| Derive a PlutusTx 'Eq' instance for a datatype or newtype.

Similar to Haskell's @deriving stock Eq@, this generates structural equality 
with short-circuit evaluation and INLINEABLE pragmas for optimal on-chain performance.

__Usage:__

@
data MyType = Con1 Integer | Con2 Bool
deriveEq ''MyType
@

__Generated code:__

* Pattern-matching clauses for each constructor
* Short-circuit evaluation (stops at first inequality)
* @INLINEABLE@ pragma for cross-module optimization
* Proper handling of phantom type parameters

__Supported types:__

* Regular datatypes with any number of constructors
* Newtypes
* Types with phantom type parameters
* Types with strict or lazy fields

__Unsupported:__

* GADTs (may produce type errors)
* Type families (not tested)

See 'PlutusTx.Eq.Class.Eq' for the class definition.
-}
deriveEq :: Name -> Q [Dec]

Copy link
Contributor Author

@bezirg bezirg Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation claims you cannot derive for polymorphic phantom types, but PhantomADT test demonstrates it does work?

Forgot to clean the comment. Phantom types do work now.

Comment on lines +57 to +72
( clause
[conP name (fmap varP argsL), conP name (fmap varP argsR)]
( normalB $
case fields of
[] -> conE 'True
_ ->
foldr1 (\e acc -> infixE (pure e) (varE '(&&)) (pure acc)) $
zipWith
( \argL argR ->
infixE (pure $ varE argL) (varE '(==)) (pure $ varE argR)
)
argsL
argsR
)
[]
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant brackets:

Suggested change
( clause
[conP name (fmap varP argsL), conP name (fmap varP argsR)]
( normalB $
case fields of
[] -> conE 'True
_ ->
foldr1 (\e acc -> infixE (pure e) (varE '(&&)) (pure acc)) $
zipWith
( \argL argR ->
infixE (pure $ varE argL) (varE '(==)) (pure $ varE argR)
)
argsL
argsR
)
[]
)
clause
[conP name (fmap varP argsL), conP name (fmap varP argsR)]
( normalB $
case fields of
[] -> conE 'True
_ ->
foldr1 (\e acc -> infixE (pure e) (varE '(&&)) (pure acc)) $
zipWith
( \argL argR ->
infixE (pure $ varE argL) (varE '(==)) (pure $ varE argR)
)
argsL
argsR
)
[]

Comment on lines +1 to +4
### Added

- A `deriveEq` command to derive PlutusTx.Eq instances for datatypes/newtypes, similar to Haskell's
`deriving stock Eq`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Added
- A `deriveEq` command to derive PlutusTx.Eq instances for datatypes/newtypes, similar to Haskell's
`deriving stock Eq`
### Added
- A `deriveEq` Template Haskell function to automatically derive PlutusTx.Eq instances
for datatypes and newtypes, similar to Haskell's `deriving stock Eq`.
Usage: `PlutusTx.deriveEq ''MyType`
This generates short-circuiting equality checks with proper INLINEABLE pragmas for
optimal on-chain performance.

runTestNested
["test", "Eq", "Golden"]
[ $(goldenCodeGen "SomeLargeADT" (deriveEq ''SomeLargeADT))
, $(goldenCodeGen "PhantomADT" (deriveEq ''PhantomADT))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind adding tests for newtypes and records with fields?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, do you know if (self/manually)-recursive types are supported? Would be nice to have a comment (if not) or tests (if yes)


instance P.Ord Rational where
{-# INLINEABLE compare #-}
compare (Rational n d) (Rational n' d') = P.compare (n P.* d') (n' P.* d)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why is compare the only function removed here?

Copy link
Contributor Author

@bezirg bezirg Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will take a look at this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants