Yep. That’s the status quo. My tongue-in-cheek response to that as
objection is “If simply sufficient utility for a given task were valid as
objection to a new utility, why Go over C?” If you’re not posing that as
objection, no need to dwell on it.

Yeah. That’s exactly the kind of behavior I want to improve on. If you
reimplemented as “[T constraints.Number]”, then you would have a reasonably
efficient means of expressing even very deep pipelines of numerical
transformations, with the caveat that one is not able to change the arity
for any stage boundary. You can’t reduce the constraint on T, lest you be
unable to do mathematical operations without reverting to interface and
type-assertion semantics, losing the benefit of generics over interfaces. Now
you have two sets of almost identical pipeline boilerplate — more if you
intend stochastic gradients or other matrix operations.

Generics also can’t cover the case of multiple values at the boundary of a
stage. You could define types for various combinations of values, function
pointers, and errors, and create the most godawful, disgusting pile of
moldering spaghetti.

The three most effective ways to get around this are to A,
marshal/unmarshal from a byte-slice, B, use variadic parameters of type
empty interface, and C, codegen. All three add unnecessarily heavy mental
overhead, and excepting C, sacrifice safety and performance guarantees.

So in short, yes, that playground snippet is exactly the kind of utility
that works in the same way that a tape-covered racket works as an oar.

On Fri, Apr 1, 2022 at 10:35 PM Henry <henry.adisuma...@gmail.com> wrote:

> 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 a topic in the
> Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/golang-nuts/Iv2kyFY70eA/unsubscribe.
> To unsubscribe from this group and all its topics, 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
> <https://groups.google.com/d/msgid/golang-nuts/82780772-5819-412b-a238-87f53ec22f77n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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/CAAxgZyQwo45uG7EXqniSB3rniiMBBbWF46aBciLjSWZvbQxO1w%40mail.gmail.com.

Reply via email to