Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value representation rework #734

Closed
wants to merge 13 commits into from
Closed

Value representation rework #734

wants to merge 13 commits into from

Conversation

SeungheonOh
Copy link
Collaborator

@SeungheonOh SeungheonOh commented Oct 30, 2024

nothing much yet

closes #630 and probably bunch more

@SeungheonOh SeungheonOh changed the base branch from master to staging October 30, 2024 01:16
@SeungheonOh SeungheonOh force-pushed the seungheonoh/rework branch 2 times, most recently from 2e2539a to 84bbaa6 Compare October 30, 2024 01:19
@L-as
Copy link
Member

L-as commented Oct 30, 2024

What's your idea?

@SeungheonOh
Copy link
Collaborator Author

SeungheonOh commented Oct 30, 2024

Have PStruct and PRec represent any kind of composite data types, and have PDataRec, PScottRec, ... to represent their encoded format. This will give types that encodes same structure differently for free and also conversion from and to different encoding for free.

So let's say Maybe for example, currently, we need PMaybe and PMaybeData. With this design,

data MyPMaybe s a
  = MyJust (Term s a)
  | MyNothing
  deriving stock (GHC.Generic)
instance SOP.Generic (MyPMaybe s a)

type S' = forall s. s

type MyPMaybeRepr a = UnTermStruct (MyPMaybe S' a)

test :: PStruct (MyPMaybeRepr PInteger) s
test = PStruct $ hcoerce $ from $ MyJust (10 :: Term s PInteger)

testData :: Term s (PDataStruct (MyPMaybeRepr PInteger))
testData = pconDataStruct test

testScott :: Term s (PScottStruct (MyPMaybeRepr PInteger))
testScott = pconScottStruct test

handler :: MyPMaybe s PInteger -> Term s PInteger
handler (MyJust x) = 1 + x
handler MyNothing = 0

matchTestData :: Term s PInteger
matchTestData = pmatchDataStruct @(MyPMaybeRepr PInteger) testData (handler . to . hcoerce . unPStruct)

matchTestScott :: Term s PInteger
matchTestScott = pmatchScottStruct @(MyPMaybeRepr PInteger) testScott (handler . to . hcoerce . unPStruct)

pmatchDataStruct pconScottStruct converts encoding for free

@SeungheonOh
Copy link
Collaborator Author

Having to deal with

type MyPMaybeRepr a = UnTermStruct (MyPMaybe S' a)

is kind of annoying : / Any suggestions are welcome

Comment on lines 149 to 150
hashRawTerm' (RPlaceHolder hash) = addHashIndex 9 . flip hashUpdate hash
hashRawTerm' (RCompiled code) = addHashIndex 10 . flip hashUpdate (hashUTerm @alg code hashInit)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather we kept existing hashing choices the same. It probably doesn't matter, but I'd rather the hash index of RCompiled stayed as 9.

Comment on lines +101 to +104
class PDataRepresentable (a :: S -> Type)
instance PDataRepresentable (PDataStruct struct)
instance PDataRepresentable PInteger
instance PDataRepresentable PByteString
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this type class actually mean?

@L-as
Copy link
Member

L-as commented Oct 31, 2024

Why does MyPMaybeRepr exist at all? I think there is a way of making the functions generic over it too BTW.

I also think you can do this without having it in the types at all.

@SeungheonOh
Copy link
Collaborator Author

I think there is a way of making the functions generic over it too.
any examples? I don't understand.

Also, I'm somewhat sure this can be done without embedding these into types, but I don't want to use Haskell's generics, they are pain to deal with. Also don't want TH for similar reasons

@L-as
Copy link
Member

L-as commented Oct 31, 2024

You can change the AST a bit such that operations over data types are more abstract. Everything could be SOP-like in the AST. When you lower it to UPLC you could choose at each site what is most convenient, and according to user preference.

There are multiple strategies here, some optimize size, some performance, and some of the problems are in NP.

(hash :: Dig) <- hashOpenTerm t
pure (hash, Term $ const $ pure $ TermResult (RPlaceHolder hash) [])

pletSmart :: Term s a -> (Term s a -> Term s b) -> Term s b
Copy link
Member

@L-as L-as Oct 31, 2024

Choose a reason for hiding this comment

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

Does this account for stuff like

let x = ... in map (\_ -> x) list

Note that UPLC is strict.

EDIT: Consider the above as pseudo-UPLC.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah, it won't be able to figure out if bound term will be used multiple times or not

Copy link
Member

Choose a reason for hiding this comment

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

The solution is to cover a small set of cases that are useful and happen in practice and are easy enough to detect.
You can replace it with checking whether the bound variable ever appears under a delay or lam. If it does not, that should mean it's always only evaluated exactly once, hence you can inline it without changing almost anything.

Three properties to uphold:

  • Algorithmic complexities must not change
  • What errs without optimizations must not err with optimizations.
  • What succeeds without optimizations must succeed with optimizations.

The bottom two are a very unfortunate side effect of UPLC's design. I made a CIP cardano-foundation/CIPs#469 to fix this, but it wasn't very popular.

Copy link
Member

@L-as L-as Oct 31, 2024

Choose a reason for hiding this comment

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

The topmost one wouldn't be affected by doing laziness like Haskell though, since sharing doesn't happen under lambdas. It does though on HVM and stuff like that AFAIU.

@SeungheonOh
Copy link
Collaborator Author

Waiting on module restructuring

@SeungheonOh
Copy link
Collaborator Author

superceeded by #767

@SeungheonOh SeungheonOh closed this Dec 1, 2024
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.

3 participants