Discussion on Polyadic Calculus

From Rholang Wiki
Jump to navigation Jump to search


This page documents a discord conversation held between Tomislav Grospic, Joshy Orndorff, and Isaac DeFrain 15 - 19 February 2019.

The question came up as to whether polyadic sends (analogous to multiple-argument function calls) added expressivity or convenience to rholang given that tuples are present as a ground term. After some discussion it was generally agreed that tuples alone are sufficient and maintaining a polyadic calculus adds confusion.


Isaac DeFrain's KFramework implementation of Coop Rholang does not currently support polyadic sends.

Rhoxy Does not support polyadic sends.

Simplified Rholang seeks to standardize a language without polyadic sends.


IsaacDeFrain02/15/2019 Tuple comms are working! I can't believe how easy that was, I was totally overthinking it before. My goal of showing something that is functioning next week seems very realistic all of a sudden :smiley_cat: tgrospic02/15/2019 This sounds great! I'll be happy to see it.

It seems that I missed you explanation, what exactly do you mean by "Tuple comms"? IsaacDeFrain02/15/2019 By tuple comm, I mean a comm of the form

   x!(1,2,3) | for( a , c , b <- x ){ P(a,b,c) } -> P(1,3,2)

JoshyOrndorff02/16/2019 Congrats on getting it working! I'm cross-posting this longish example of why polyadic calculus isn't a good idea when you have tuples as a ground term. Curious what you guys think. Here's a nice way to write a forwarder that uses tupling inside a monadic rholang // Some destination contract that does something useful contract destination((x, y)) = {

 // Do something useful with x and y

} |

// A contract that forwards messages to the destination contract forwarder (destinationArgs, ack) = {

 // Acknowledge that the message has made it this far
 ack!(Nil) |
 // Pass the args on to the destination

} |

// Actually use the forwarder forwarder!((2, 3), *ack)

Here's how a polyadic rholang ruins that idiom // Destination contract is written in polyadic style contract destination(x, y) = {

 // Do something useful with x and y

} |

// Forwarder now has to take a seperate argument for each destination argument // So this forwarder is only useful for arity 2 destinations now contract forwarder (destinationX, destinationY, ack) = {

 // Acknowledge that the message has made it this far
 ack!(Nil) |
 // Pass the args on to the destination
 destination!(*destinationX, *destinationY)

} |

// Actually use the forwarder forwarder!(2, 3, *ack) IsaacDeFrain02/16/2019 Thanks! That's right, you sent this to me earlier. IsaacDeFrain02/16/2019 In the first example, we listen on destination for a 2-tuple which we are viewing as a single process. In the second example, we are listening on destination for two processes which we view as a single 2-tuple. I'm not understanding why that's an issue. Doesn't it just give the programmer more options? JoshyOrndorff02/16/2019 In the second example, we are listening on destination for two processes which we view as a single 2-tuple. I'm not 100% sure what you mean by that, but I don't think it's right. The second example does not use tuples at all, it uses polyadic sends and receives. It would work just fine if rholang had no tuples at all.

The second code does work. Because it used polyadic sends, the payload that gets passed on from the forwarder to the final destination, is not a single item. Thus this forwarder only works when destination expects exactly two arguments communicated via a polyadic send. A completely new forwarder would be needed for a destination with 1 or 3 polyadic arguments. The first example OTOH can be used for any destination that accepts tupled arguments regardless of of the tuple's arity because it is always a single tuple. Maybe these examples help? Tuples and polyadic sends cannot be mixed. // Polyadic comm chan!(1, 2, 3) | for (a, b, c <- chan) { Nil }

// Monadic comm chan!((1, 2, 3)) | for (tuple <- chan) { Nil }

// Monadic comm with pattern matching chan!((1, 2, 3)) | for ((a, b, c) <- chan) { Nil }

// No comm (polyadic arity mismatch) chan!(1, 2, 3) | // Send is arity 3 for (tuple <- chan) { Nil } // Receive is arity 1

// No comm (polyadic arity mismatch despite pattern matching) chan!(1, 2, 3) | // Send is arity 3 for((a, b, c) <- chan) { Nil } // Receive is arity 1 (and needs a particular structure)

// No comm (polyadic arity mismatch) chan!((1, 2, 3)) | // Send is arity 1 for (a, b, c <- chan) { Nil } // Receive is arity 3 tgrospic02/16/2019 @JoshyOrndorff you want to say that forwarder!(2, 3, *ack) should be viewed as forwarder sending the 3-tuple? tgrospic02/16/2019 This is interesting for me from C# perspective because now it has tuples which have the same problem. print((2, 3)) means calling a function with a tuple. I'm more on your side to say that all functions in C# accepts only one argument, a tuple. :smiley: Maybe chan!((1, 2, 3)) should be the same as chan!(1, 2, 3)? tgrospic02/16/2019 I'm wondering if polyadic arguments are the problem if we have good implementation of the spread operator. In my compose exmaple I used list just because of that. https://gist.github.com/tgrospic/5e32fb9e9090c0a95af29c17e8e6c8a3#file-compose-rho-L9

// We can now deconstruct arguments contract forwarder (...@dest)

for(...@dest <- ...)

// But these things doesn't work :( contract forwarder (...@dest, ack)

@forwarder!(...dest) Or is there higher reason why spread operator cannot be implemented in more advanced way? IsaacDeFrain02/16/2019 I think I'm using the phrase "sending tuples" rather loosely here because in my implementation in k, I have the sorts

      Send ::= Name "!" "(" Proc ")" | Name "!" RhoTuple
  RhoTuple ::= "(" Proc ",)" | "(" Procs ")"
     Procs ::= Proc "," Proc | Proc "," Procs

IsaacDeFrain02/16/2019 And also Proc ::= RhoTuple tgrospic02/16/2019 What are sorts in this contexts? Are the sort part of the parser for K syntax? JoshyOrndorff02/16/2019 I would prefer if the semantics in rholang were such that only single processes can be sent.

// Programmer writes chan!(1, 2, 3)

// Means same as chan!((1, 2, 3))

One idea: say the comma is what makes a tuple, and the parentheses are just the grouping characters for expressions. Python does that, but then makes the same mistake as rholang by adding a special case for multiple argument function calls. IsaacDeFrain02/16/2019 Yeah I thought it was a little weird that sending a one tuple works there same as sending a process @tgrospic the sorts here are Name, Proc, Procs, Send, RhoTuple. That's what k calls them. Sorts or syntactic categories. tgrospic02/16/2019 Send could be defined without parentheses chan!42 and with grouping chan!{"Rick" | "Morty"}. Is it then make sense to have chan! 42 "Rick" with 2 arguments? IsaacDeFrain02/16/2019 That is definitely possible. We would just need to let send take space separated proc lists. Send does already take comma separated proc lists. If there were no parentheses for send then the tuple stuff wouldn't be an issue anymore, I think. IsaacDeFrain02/16/2019 @JoshyOrndorff Yeah it doesn't seem to take anything away from the language if you only allow sends of single processes especially since tuples can hold any kind of processes, including tuples themselves. In fact, it seems like it does away with some of those cases that don't result in comms that you mentioned above. I guess that was your point all along. In the case of only sending tuples, should for( @a, @b, @c <- x ){...} mean the same thing as for( @(a,b,c) <- x ){...}? JoshyOrndorffLast Sunday at 11:10 AM @IsaacDeFrain imo those _should_mean the same thing. According to coop implementation they don't. According to coop implementation, the first receive has arity 3, and the second has arity 1. There does not exist any send that would comm with both of those receives. @tgrospic nice spread operators would definitely solve the forwarder problem caused by polyadic sends. Those spread operators would also be nice for pattern matching against arbitrary tuples. So while I agree that polyadic sends could be made less of an inconvenience, I still don't see how they add anything that isn't already possible with tuples. IsaacDeFrainLast Sunday at 11:14 AM Thanks for clarifying tgrospicLast Sunday at 4:04 PM @JoshyOrndorff I totally agree. I don't see additional benefit for polyadic variant. I would argue the same in C# or Python also but maybe I'm missing something. JoshyOrndorffLast Monday at 8:32 PM Yeah, I agree about python and c# too.