pact icon indicating copy to clipboard operation
pact copied to clipboard

Add support for progn-equivalent for sequencing

Open bts opened this issue 6 years ago • 5 comments

It would be nice to have some equivalent to Common Lisp’s progn / Scheme’s begin / Clojure’s do to sequence side-effecting forms in an expression. Except not named progn 😄:

(if (< x 5)
  (do
    (begin-tx)
    (print "in tx")
    (commit-tx))
  (print "not running tx"))

At the moment, the only option is to create a separate function wherein these side effecting expressions are sequenced:

(defun helper ()
  "Runs tx"
  (begin-tx)
  (print "in tx")
  (commit-tx))

(if (< x 5)
  (helper)
  (print "not running tx"))

bts avatar Feb 27 '18 15:02 bts

As much as I resist introducing Clojure-isms into Pact, do is by far the best one. begin: well, where does it end? progn: barf.

sirlensalot avatar Mar 24 '18 18:03 sirlensalot

Brian do you want to take a crack at this sometime?

sirlensalot avatar Apr 12 '18 17:04 sirlensalot

Proposal:

In order to cleanly support do and to clean up support for a number of other natives/special forms, I recommend adding essentially varargs support to the function type system. (Support for users to write vararg functions completely optional.)

Specifically, I propose amending the Arg type (part of FunType, defined in Lang.hs) so that an Arg object can be marked as matching any number of arguments of its type. Only one Arg so marked would be permitted in each FunType, so that there's no ambiguity in matching up actual function arguments to the specified function type. We could add this to data Arg o:

_aVararg :: Bool

(Alternatively, we could add a TyMany alternative to Type, but that could unnecessarily pollute code not dealing with FunTypes.)

I suggest prettying/mangling this by adding " *" at the end of the arg name, space character included to ensure it's not a legal user symbol. Thus, do would have this function type:

(stmts *:* stmt-last:<a> -> <a>)

This gives us a lot of flexibility to type things like the functions bench and list (shown here):

(values *:<a> -> [<a>])

And like with do, we could give with-read and others like it a more legit function type, rather than leaving out the body statements from the signature as is currently done, or pretending that only one body statement is permitted, as in let and let*. Plus we can get rid of related work-arounds and special cases, as in the handling of return values from forms like with-read in the type checker (search "-- assoc binding with app return").

This could permit changing format to be a vararg function rather than taking a list, but it's probably easier and slightly more flexible to keep it a list, even if it's somewhat less convenient.

This could also be used to extend +, *, and, and or to be n-ary, as in most Lisps.

pdillinger avatar May 16 '18 21:05 pdillinger

I'm not a huge fan of varargs to begin with (except in Java where there are no decent list literals) ... especially so for user functions as I think it makes for a confusing API (it really means a list, so how do you put that in JSON?)

Pact 1.x had varargs -- format was originally varargs, and we didn't have list literals but only list. During the typechecker development we set out to ditch them, breaking format with 2.0, and deprecating list once literals were in. bench should probably take a list but it's a REPL-only function so it's less critical.

Body forms on the other hand would be nice to support. We can simply introduce &body or similar since they're always the same shape/type. To my mind the best home for that would be in FunType itself, as Arg gets used in more places than defun arg lists (e.g. also for bindings).

sirlensalot avatar Jul 17 '18 23:07 sirlensalot

Also, like other elements of Pact, we would not allow &body in user code; it would really just allow us to denote special forms properly to the typechecker and docs.

sirlensalot avatar Jul 17 '18 23:07 sirlensalot