-
Notifications
You must be signed in to change notification settings - Fork 10
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
Add list folds #70
Conversation
98c7958
to
5686b79
Compare
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.
5686b79
to
c416f28
Compare
Rebased |
Can you address my outstanding comment from #69? |
I don't see any outstanding comments in #69. Do you mean a different PR? |
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. |
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 I did not carefully analyze your Simplicity code but it looks like it's right. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK c416f28
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. |
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.