Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119740 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 16933 invoked from network); 17 Mar 2023 14:45:43 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 17 Mar 2023 14:45:43 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B3D55180381 for ; Fri, 17 Mar 2023 07:45:42 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS19151 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 17 Mar 2023 07:45:42 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 6858F5C00C2 for ; Fri, 17 Mar 2023 10:45:39 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute4.internal (MEProxy); Fri, 17 Mar 2023 10:45:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm2; t=1679064339; x=1679150739; bh=YZDuifVBc8 RD1FoBOboMNlt+qNioJ2OSfdrF66tWyj0=; b=Zo7U4Y2lVAOr17RrnjuYVoJBN1 o1f3n/cVP+CU02GpT4CG/3g16ZjMuD7KOlFOxe8n+Lg8tP2RsQPbI4hULq02Ywo6 iMKVg6SNGPilK7B33jcqB+Ek9aH1rbFEYIX5rk4WTgSnA4tryqHh1AGMXRgTBu9v aiglKiLpGsozyAjXL80+wzmclGAvpG3tftSC4Ha4xkr95yMpr2fY3XzoiDzn6/my hHQRv2NNIi+FIoS0Yv3x1MAC8HxwxHkP0Cq0m7Y9HEAKTEZBDCCT4bjop81jfDk7 6lICXFH/7HqVp5/IdqPK6kmjtKVDXlaJW+gNPFVEPSsZrRykpMyU70gZNG5Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1679064339; x= 1679150739; bh=YZDuifVBc8RD1FoBOboMNlt+qNioJ2OSfdrF66tWyj0=; b=O 2f9MOx65gY/ZK1+vrQnsMup091vWWo9gCdLFi7i/v/2jOOVUrwjY2zWhgyZToNXG 5yTHf9ODsfKlZ6YUvmGvBalmTCdsKyPZ2IX3vGg7j2xHUeqws5NlSOdD9Rt60zyr A8Boa2qWF0Pg8yYDuVA42LodZO0g6b0zlniIjK3ZunNs/ndMBrjN8osoi6qa1IRX XnJ1301l1BbLpO9icvyfAwozoHrO7DBbs7J4OGg9wQys5BOSA/iNikr/JA9m+IU2 NH0EGolqzQhAfXCSK1B2Ts+f6cTl+1uH112MHMfcKAFMRNqn5OPQqHTZGLDu8zQF BK83HqszJC+PajJ5M94hA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrvdefvddgieejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuggftrfgrthhtvghrnheplefgfeehtdfgveevheefhfeiteelfeekheeuveef heehhfduiedtkeefgeeuvefgnecuffhomhgrihhnpehorhgrtghlvgdrtghomhenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehg rghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 253511700089; Fri, 17 Mar 2023 10:45:39 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.9.0-alpha0-221-gec32977366-fm-20230306.001-gec329773 Mime-Version: 1.0 Message-ID: In-Reply-To: References: <9975B833-EE24-4ED7-B28E-841B92988BA0@cschneid.com> <1A2CE63B-ECCA-403D-83AC-B1E26279323C@gmail.com> <9a2140b4-97bb-4a9c-90c5-809274c83f75@app.fastmail.com> <88c4a63c-859b-94d5-e314-3399fb2c3fb0@gmail.com> <1a4d4434-7318-4831-9fc0-8b48a6400a62@app.fastmail.com> <73033e11-a521-40a3-a29e-14d575332aea@app.fastmail.com> Date: Fri, 17 Mar 2023 09:45:18 -0500 To: "php internals" Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] First-class callable partial application From: larry@garfieldtech.com ("Larry Garfield") On Fri, Mar 17, 2023, at 3:54 AM, Micha=C5=82 Marcin Brzuchalski wrote: >> As a thought experiment, if we had that syntax and functions that were >> designed to be used with them, it would look like so: >> >> function amap(callable $c, iterable $it) { ... } >> function implode(string $sep, iterable $it) { ... } >> function length(string $s) { ... } >> >> $arr =3D [1, 2, 3]; >> >> $a2 =3D amap(...)->partial(chr(...))($arr); >> >> $str =3D implode(...)->partial(',')($a2); >> >> Or, if combined with pipes: >> >> $size =3D $arr >> |> amap(...)->partial(chr(...)) >> |> implode(...)->partial(',') >> |> length(...); >> >> Which... is not terrible, especially as it doesn't preclude using hig= her >> order functions for more control. >> > > Maybe we could introduce two additional methods on a Closure similar to > what Java have > https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.= html > * andThen() - which functionality is like a pipe operator > * apply() - which you can call without the option to bind/rebind and j= ust > pass arguments for execution > > The pipe operator can be introduced later, but we could already have t= he > functionality on Closure. > > The above example might look readable as well: > > $size =3D amap(...)->partial(chr(...)) > ->andThen(implode(...)->partial(',')) > ->andThen(length(...)) > ->apply($arr); See that brings up a subtle difference between two operations: pipe and = compose. Compose takes two functions A and B and returns a new function that is l= ogically identical to B(A()). (Or sometimes A(B()), depending on the la= nguage, which is all kinds of confusing.) Pipe takes an arbitrary value and unary function and calls the function = with that value immediately, returning the result. You can build a pipe equivalent out of compose, although it's a bit clun= ky and the semantics are not *quite* identical. (The order of execution= is different, which may or may not matter depending on the specifics of= each call.) In the example above, andThen() is acting as a compose operator, while a= pply() is just boring function application. It works but it's a bit clu= nky compared to a proper pipe. That said, there are user space librarie= s that do that. Thinking aloud... I said before it would be better to have a native ope= rator for all of these. (compose, pipe, and partial.) If we restrict o= urselves to Closure objects rather than all callables (since callables a= re a lot messier), that does open up some new options. Specifically, th= e following are already syntax errors today: $c =3D strlen(...); $d =3D array_map(...); $c + $d; // not allowed. $c . $d; // not allowed, thinks it's string concat and $c isn't stringab= le. $c[2, 3]; // not allowed. $c{5}; // not allowed, thinks it's a string offset. So that suggests to me the following: * Define $a + $b on closure objects to be a compose operator that return= s a new function equivalent to $b($a( )). It would only work on unary f= unctions, validate compatible types between the param and return values,= and have the correct type information. * Define $c{ ... } as a "partial application" call. The {} body would b= e similar to a function call now; or maybe the original PFA syntax with = ? and ... ? Debatable, but the {} would be a better signal to the engin= e that we're not calling a function, just partially calling. It's also = reasonably self-evident to developers. Those two together would allow for this: (amap{chr(...), ?} + implode{?, separator: ','} + length(...))($arr); Which is... pretty nice, really. It's very close to the original PFA sy= ntax and capabilities, compact, not easily confused with anything else, = type safe, and the engine can handle optimizing around not having unnece= ssary interstitial functions internally. I still think we should also add a pipe operator |> as well, but that wo= uld be just as compatible with the {}-based PFA syntax. It's also fairl= y trivial to implement. $size =3D $arr |> amap{chr(...), ?) |> implode(',', ?) |> length(...); Thoughts? --Larry Garfield