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

Add list folds #70

Merged

Conversation

uncomputable
Copy link
Collaborator

Depends on #69. Better version of #22.

Fold a bounded list using a binary function fn f(element: E, accumulator: A) → A.

Lists are divided into blocks of decreasing size [1234][56][7]. f is generalized to work on blocks, passing the updated accumulator to the next element. The fold processes blocks in order [1234], [56], [7]. This seems like a left fold to me, which is usually inefficient, but in Simplicity there is no concept of recursion, so this inefficiency might no longer hold.

@apoelstra
Copy link
Contributor

Will wait for rebase after merge of #69, since this needs a rebase anyway to deal with merge conflicts.

Values of NonZeroPow2Usize are equal to 2^n for some n > 0.
Return n as NonZeroU32. Use unsafe to prevent unnecessary unwrap
NonZeroU32::new(n).unwrap().
Go to the next power of two by multiplying by two.
Go to the previous power of two by dividing by two.
We can use these methods for iteration.
A fold has the signature
  fold::<f, N>(list: List<E, N>, accumulator: A) -> A
Where the folded function has the signature
  f(element: E, accumulator: A) -> A

All elements of the list are processed by `f` in order. Each iteration
updates the accumulator, which is initialized when the fold is called.
The final accumulator is the output of the fold.

I wrote an alternative fold where `f` has readonly access to a context
which doesn't change across iterations. For brevity, I omitted this
version here. Contextual information can be passed inside the accumulator.

The above fold syntax has several advantages:
1. We avoid introducing function(pointer)s as a new type. This would be
   the case if we wrote fold::<N>(list, initial_acc, f). The "generic
   arguments" inside the diamond brackets are essentially lawless
   country where we can put non-values such as `f`.
2. The compiler knows the exact type of the parameters `list, initial_acc`
   to the fold. This means we can supply literal arguments such as
   `list![1, 2, 3]` (which could a list with any upper limit ≥ 4) or
   `42` (which could be any unsigned integer with at least 8 bits).
   Rust would require type annotations in these cases.

We translate folds into Simplicity in the next commit.
@uncomputable
Copy link
Collaborator Author

Rebased

@apoelstra
Copy link
Contributor

Can you address my outstanding comment from #69?

@uncomputable
Copy link
Collaborator Author

I don't see any outstanding comments in #69. Do you mean a different PR?

@apoelstra
Copy link
Contributor

Oh, I was confused. I meant BlockstreamResearch/rust-simplicity#237 which is in a different repo and of course has nothing to do with this PR.

@apoelstra
Copy link
Contributor

c416f28 looks good to me! I guess this is the first place where we meaningfully deviate from Rust syntax. It is a bit tempting to use fold(f, init, list) syntax to match Rust ... though you would need to special-case this in the syntax so that it would look like a normal function call but actually be a language construct. Probably not worth the trickery and weird error messages.

I did not carefully analyze your Simplicity code but it looks like it's right.

Copy link
Contributor

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

ACK c416f28

@uncomputable
Copy link
Collaborator Author

Basically, we need to add function types to Simfony. Function types are a huge topic in Rust, so I will not open this can of worms here. We will come back to this issue and revise the syntax.

@uncomputable uncomputable merged commit 5fac1b9 into BlockstreamResearch:master Jul 28, 2024
@uncomputable uncomputable deleted the 2024-07-list-fold branch July 28, 2024 20:12
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.

2 participants