Something like this? https://play.golang.com/p/rhu9PX9GSbp
On Saturday, April 2, 2022 at 5:41:52 AM UTC+7 sam.a....@gmail.com wrote: > Point-free programming, or "tacit programming", is a convention that > highlights the intent without syntactic noise. > > For those unfamiliar, wikipedia: > https://en.wikipedia.org/wiki/Tacit_programming > > I want better function composition. "Write a helper function to route > values out to values in, like a normal person." Sure, but who needs Go when > you have C, eh? A tacit sugaring merely provides a lexically distinctive > means to indicate the intent that function f0 should be called with the > return value of f1, and f1 of f2, and so on, with reduced syntax. > > There are a couple layers here, there's an easy win, a possible next step, > and well, madness. > > A. Go uses a thin-arrow, "<" + "-", as a receive/send operator and to > signify directionality of a channel. This same operator could be used like > so, "c := a <- b()" to assert the following: > 1. Token "a" resolves to a function pointer > 2. Token "b" returns none, one, or many values, such that "a(b())" is > legal. > 3. Token "c" can legally be assigned the value of the desugared > expression. > This suggestion imposes ambiguity between the meaning of "(chan > int)(x)<-y(z)" and "(func(int)int)(x)<-y(z)", and I have chaotic intuitions > about the meaning of "(func(int)int)(x) <- (chan int)(y)", or even > "(func(int)int)(x) <- (chan int)(y) <- z", but x(<-y) is clearly > (func[T](T)T)(x)(<-(chan[T] T)(y)). A minimally disruptive solution, then, > is to assert that the tip of such a tacit chain must be a full-syntax > invokation, e.g. for "f0 <-...f<N-1> <- ?", only "f<N>(...)" is valid. This > means expressions like "c0 <- f0 <- f1(f2 <-f3(<-c1))" are unambiguous > without a mountain of ellipses. > > B. At cost of introducing a new concept for Go entirely, it would be > convenient to declare a function as "f0 := f1 <- f2 <- f3", resolving as > suggested by the statement: "reflect.TypeOf(f0) == > reflect.FuncOf([]reflect.Type{reflect.TypeOf(f3).In(0), ..<etc>}, > []reflect.Type{reflect.TypeOf(f1).Out(0), ...<etc>})". The straightforward > path to implementation would resolve that naively, as suggested by the > following: "f0 := func[T handWaving.inT, U handWaving.outT](a... T) (...U) > {return f1(f2(f3(a...)))}". A statement like "go f0 <- f1 <-f2 <- f3", > assuming "go func[T handWaving.inT](a...T) {f0(f3(a...));}" is legal, would > be an attractive pattern. > > C. Naively, point B suggests that the functions thus concatenated could be > assembled as to preallocate the stack for the entire concatenation, > omitting the allocations and moves/copies between function calls, and > rather writing the return values to the stack for the predecessor function, > by analogy, like a reverse closure or a heterogenous recursion. For the > example "f0 := f1 <- f2 <- f3", because I expect that statement to only be > legal if "f1(f2(f3(..args..)))" is legal, the out-signature of f3 is > assignment-compatible with the in-signature of f2, and f2 to f1. Concerns > such as an element in the concatenation being recursive, blocking, or > corrupting only apply to the function at stack-head; pre-allocating even a > potentially large stack exposes only risk shared with allocating the same > stack progressively, but with lower instructional segmentation. A possible > but unlikely edge-case, if for some reason, a generic function cannot be > appropriately stenciled, the optimization being suggested might only > partially be applied, or else not applied at all. > > Ellipses are basically universal for "I give you control, but I expect it > back". Loops don't give up control, rather push it on a swing like a child. > Go-func commissions an agent, expecting no control. Point A would change > the expression somewhat, but by requiring the head of a concatenation to be > an execution, the language of "I give, but I expect" is kept, but uses the > existing language of sending on channels, "B to A, your turn A", and is > suggested as unambiguously extending the "I give, I expect" agreement > backwards towards the tail. The symbols suggested are certainly not sacred, > either. > > Point B and C are harder to recommend unequivocally, but could be potently > powerful tools for communicating very long but uncomplicated calls. Point B > has very few downsides, but represents introduction of a case where a human > might understand an expression differently than a parser, while Point C > introduces a layer of complexity to serve a use case that, for better or > worse, could serve to push a new idiom onto the Gopher community. > > These three points present no risk to the Go 1 compatibility promise, but > I will admit before anyone else that I haven't proven that Point C is worth > the investment, and I expect some difficult questions about Point B. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/82780772-5819-412b-a238-87f53ec22f77n%40googlegroups.com.