Skip to content

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
effectfully committed May 15, 2024
1 parent 29f0b1a commit 1fed980
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 19 deletions.
4 changes: 2 additions & 2 deletions plutus-tx/src/PlutusTx/Builtins/HasBuiltin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ import Data.ByteString (ByteString)
import Data.Kind qualified as GHC
import Data.Text (Text)

-- Also see Note [Built-in types and their Haskell versions].
-- Also see Note [Built-in types and their Haskell counterparts].
-- | A class for converting values of Haskell-defined built-in types to their Plutus Tx
-- counterparts.
type HasToBuiltin :: GHC.Type -> GHC.Constraint
class PLC.DefaultUni `PLC.Contains` a => HasToBuiltin a where
type ToBuiltin a
toBuiltin :: a -> ToBuiltin a

-- Also see Note [Built-in types and their Haskell versions].
-- Also see Note [Built-in types and their Haskell counterparts].
-- | A class for converting values of Plutus Tx built-in types to their Haskell-defined
-- counterparts.
type HasFromBuiltin :: GHC.Type -> GHC.Constraint
Expand Down
33 changes: 19 additions & 14 deletions plutus-tx/src/PlutusTx/Builtins/HasOpaque.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,29 +75,29 @@ instance IsString BuiltinString where
fromString = Magic.noinline stringToBuiltinString
{-# INLINE fromString #-}

{- Note [Built-in types and their Haskell versions]
{- Note [Built-in types and their Haskell counterparts]
'HasToBuiltin' allows us to convert a value of a built-in type such as 'ByteString' to its Plutus
Tx counterpart, 'BuiltinByteString' in this case. The idea is the same for all built-in types: just
take the Haskell version and make it the Plutus Tx one.
'HasToOpaque' is different, we use it for converting values of only those built-in types that exist
in the Plutus Tx realm. I.e. we cannot convert a 'ByteString', since 'ByteString's don't exist in
Plutus Tx, only 'BuiltinByteString's do.
in the Plutus Tx realm, within the Plutus Tx realm. I.e. we cannot convert a 'ByteString', since
'ByteString's don't exist in Plutus Tx, only 'BuiltinByteString's do.
Consider, say, the built-in pair type. In Plutus Tx, we have an (opaque) type for this. It's opaque
because you can't actually pattern match on it, instead you can only in fact use the specific
functions that are available as builtins.
We _also_ have the normal Haskell pair type. This is very different: you can
pattern match on it, and you can use whatever user-defined functions you like on it.
We _also_ have the normal Haskell pair type. This is very different: you can pattern match on it,
and you can use whatever user-defined functions you like on it.
Users would really like to use the latter, and not the former. So we often want
to _wrap_ our built-in functions with little adapters that convert between the
"opaque builtin" "version" of a type and the "normal Haskell" "version" of a type.
Users would really like to use the latter, and not the former. So we often want to _wrap_ our
built-in functions with little adapters that convert between the opaque "version" of a
type and the "normal Haskell" "version" of a type.
This is what the 'HasToOpaque' and 'HasFromOpaque' classes do. They let us write wrappers for
builtins relatively consistently by just calling 'toOpaque' on their arguments and 'fromOpaque' on
the result. They shouldn't really be used otherwise.
the result. They shouldn't probably be used otherwise.
Ideally, we would not have instances for types which don't have a different Haskell representation
type, such as 'Integer'. 'Integer' in Plutus Tx user code _is_ the opaque built-in type, we don't
Expand All @@ -108,6 +108,11 @@ into a Haskell list, and then traverse it again to conver the contents). Then we
for all built-in types, so we provide a @default@ implementation for both 'toOpaque' and
'fromOpaque' that simply returns the argument back and use it for those types that don't require any
conversions.
Summarizing, 'toBuiltin'/'fromBuiltin' should be used to cross the boundary between Plutus Tx and
Haskell, while 'toOpaque'/'fromOpaque' should be used within Plutus Tx to convert values to/from
their @Builtin*@ representation, which we need because neither pattern matching nor standard library
functions are available for values of @Builtin*@ types that we get from built-in functions.
-}

{- Note [HasFromOpaque/HasToOpaque instances for polymorphic builtin types]
Expand All @@ -133,7 +138,7 @@ representation type that needs to be instantiated later, but it's *not* okay to
type application on a type variable. So fundeps are much nicer here.
-}

-- See Note [Built-in types and their Haskell versions].
-- See Note [Built-in types and their Haskell counterparts].
-- See Note [HasFromOpaque/HasToOpaque instances for polymorphic builtin types].
-- See Note [Fundeps versus type families in HasFromOpaque/HasToOpaque].
-- | A class for converting values of transparent Haskell-defined built-in types (such as '()',
Expand All @@ -146,12 +151,12 @@ class HasToOpaque a arep | a -> arep where
toOpaque = id
{-# INLINABLE toOpaque #-}

-- See Note [Built-in types and their Haskell versions].
-- See Note [Built-in types and their Haskell counterparts].
-- See Note [HasFromOpaque/HasToOpaque instances for polymorphic builtin types].
-- See Note [Fundeps versus type families in HasFromOpaque/HasToOpaque].
-- | A class for converting values of transparent Haskell-defined built-in types (such as '()',
-- 'Bool', '[]' etc) to their opaque Plutus Tx counterparts. Instances for built-in types that are
-- not transparent are provided as well, simply as identities, since such types are already opaque.
-- | A class for converting values of opaque Plutus Tx types to their transparent Haskell-defined
-- counterparts (a.k.a. pattern-matchable) built-in types (such as '()', 'Bool', '[]' etc). If no
-- transparent counterpart exists, then the implementation is identity.
type HasFromOpaque :: GHC.Type -> GHC.Type -> GHC.Constraint
class HasFromOpaque arep a | arep -> a where
fromOpaque :: arep -> a
Expand Down
2 changes: 1 addition & 1 deletion plutus-tx/src/PlutusTx/Lift/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ trying to pattern match on them. So the types don't quite match up with what we
to put inside the constant.
Fortunately, we have To/FromBuiltin, which happen to do what we want.
See Note [Built-in types and their Haskell versions].
See Note [Built-in types and their Haskell counterparts].
This is arguably slightly an abuse: the versions of the types that we want in
Plutus Tx source code and the versions that we use as the implementations of
the builtin types in the universe could be different. But in practice they
Expand Down
4 changes: 2 additions & 2 deletions plutus-tx/src/PlutusTx/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,12 @@ odd n = if even n then False else True
{-# INLINABLE takeByteString #-}
-- | Returns the n length prefix of a 'ByteString'.
takeByteString :: Integer -> BuiltinByteString -> BuiltinByteString
takeByteString n bs = Builtins.sliceByteString 0 (toOpaque n) bs
takeByteString n bs = Builtins.sliceByteString 0 n bs

{-# INLINABLE dropByteString #-}
-- | Returns the suffix of a 'ByteString' after n elements.
dropByteString :: Integer -> BuiltinByteString -> BuiltinByteString
dropByteString n bs = Builtins.sliceByteString (toOpaque n) (Builtins.lengthOfByteString bs - n) bs
dropByteString n bs = Builtins.sliceByteString n (Builtins.lengthOfByteString bs - n) bs

{- Note [-fno-full-laziness in Plutus Tx]
GHC's full-laziness optimization moves computations inside a lambda that don't depend on
Expand Down

0 comments on commit 1fed980

Please sign in to comment.