@@ -31,10 +31,11 @@ module PlutusTx.Ratio (
3131 recip ,
3232 abs ,
3333 negate ,
34- half ,
35- fromGHC ,
36- toGHC ,
3734 gcd ,
35+
36+ -- * Conversion from/to Haskell
37+ fromHaskellRatio ,
38+ toHaskellRatio ,
3839) where
3940
4041import PlutusTx.Applicative qualified as P
@@ -49,13 +50,14 @@ import PlutusTx.Maybe qualified as P
4950import PlutusTx.Numeric qualified as P
5051import PlutusTx.Ord qualified as P
5152import PlutusTx.Trace qualified as P
53+ import PlutusTx.Enum
5254
55+ import Data.Ratio qualified as HS
5356import PlutusTx.Builtins qualified as Builtins
5457
5558import Control.Monad (guard )
5659import Data.Aeson (FromJSON (parseJSON ), ToJSON (toJSON ), object , withObject , (.:) )
5760import GHC.Generics
58- import GHC.Real qualified as Ratio
5961import PlutusTx.Blueprint.Class (HasBlueprintSchema (.. ))
6062import PlutusTx.Blueprint.Definition (HasBlueprintDefinition (.. ), HasSchemaDefinition )
6163import Prelude (Ord (.. ), Show , (*) )
@@ -72,6 +74,8 @@ The following two invariants are maintained:
7274data Rational = Rational Integer Integer
7375 deriving stock (Haskell.Eq , Show , Generic )
7476
77+ makeLift ''Rational
78+
7579instance Pretty Rational where
7680 pretty (Rational a b) = " Rational:" <+> pretty a <+> pretty b
7781
@@ -228,12 +232,6 @@ ratio n d
228232 (d `Builtins.quotientInteger` gcd')
229233{-# INLINEABLE ratio #-}
230234
231- {-| Converts a 'Rational' to a GHC 'Ratio.Rational', preserving value. Does not
232- work on-chain.
233- -}
234- toGHC :: Rational -> Ratio. Rational
235- toGHC (Rational n d) = n Ratio. % d
236-
237235{-| Returns the numerator of its argument.
238236
239237= Note
@@ -259,20 +257,11 @@ denominator :: Rational -> Integer
259257denominator (Rational _ d) = d
260258{-# INLINEABLE denominator #-}
261259
262- -- | 0.5
263- half :: Rational
264- half = Rational 1 2
265- {-# INLINEABLE half #-}
266-
267260-- | Converts an 'Integer' into the equivalent 'Rational'.
268261fromInteger :: Integer -> Rational
269262fromInteger num = Rational num P. one
270263{-# INLINEABLE fromInteger #-}
271264
272- -- | Converts a GHC 'Ratio.Rational', preserving value. Does not work on-chain.
273- fromGHC :: Ratio. Rational -> Rational
274- fromGHC r = unsafeRatio (Ratio. numerator r) (Ratio. denominator r)
275-
276265{-| Produces the additive inverse of its argument.
277266
278267= Note
@@ -342,6 +331,7 @@ round :: Rational -> Integer
342331round x =
343332 let (n, r) = properFraction x
344333 m = if r P. < P. zero then n P. - P. one else n P. + P. one
334+ half = Rational 1 2
345335 flag = abs r P. - half
346336 in if
347337 | flag P. < P. zero -> n
@@ -375,7 +365,53 @@ euclid x y
375365 | P. True = euclid y (x `Builtins.modInteger` y)
376366{-# INLINEABLE euclid #-}
377367
378- $ (makeLift ''Rational)
368+ instance Enum Rational where
369+ {-# INLINEABLE succ #-}
370+ succ (Rational n d) = Rational (n P. + d) d
371+ {-# INLINEABLE pred #-}
372+ pred (Rational n d) = Rational (n P. - d) d
373+ {-# INLINEABLE toEnum #-}
374+ toEnum = fromInteger
375+ {-# INLINEABLE fromEnum #-}
376+ fromEnum = truncate
377+ {-# INLINEABLE enumFromTo #-}
378+ enumFromTo x lim
379+ -- See why adding half is needed in the Haskell report: https://www.haskell.org/onlinereport/haskell2010/haskellch6.html
380+ | x > lim P. + Rational 1 2 = []
381+ | P. True = x : enumFromTo (succ x) lim
382+ {-# INLINEABLE enumFromThenTo #-}
383+ enumFromThenTo x y lim =
384+ if delta >= P. zero
385+ then up_list x
386+ else dn_list x
387+ where
388+ delta = y P. - x
389+ -- denominator of delta cannot be zero because it is constructed from two well-formed ratios. So it is safe to use unsafeRatio
390+ mid = numerator delta `unsafeRatio` (denominator delta P. * 2 )
391+ up_list x1 =
392+ -- See why adding mid is needed in the Haskell report: https://www.haskell.org/onlinereport/haskell2010/haskellch6.html
393+ if x1 > lim P. + mid
394+ then []
395+ else x1 : up_list (x1 P. + delta)
396+ dn_list x1 =
397+ -- See why adding mid is needed in the Haskell report: https://www.haskell.org/onlinereport/haskell2010/haskellch6.html
398+ if x1 < lim P. + mid
399+ then []
400+ else x1 : dn_list (x1 P. + delta)
401+
402+ {-| Converts a GHC 'Ratio.Rational', preserving value.
403+
404+ Note: Does not work on-chain.
405+ -}
406+ fromHaskellRatio :: HS. Rational -> Rational
407+ fromHaskellRatio r = unsafeRatio (HS. numerator r) (HS. denominator r)
408+
409+ {-| Converts a 'Rational' to a GHC 'Ratio.Rational', preserving value.
410+
411+ Note: Does not work on-chain.
412+ -}
413+ toHaskellRatio :: Rational -> HS. Rational
414+ toHaskellRatio (Rational n d) = n HS. % d
379415
380416{- HLINT ignore -}
381417
0 commit comments