From murdoch@dunc@n @end|ng |rom gm@||@com  Wed Dec  9 16:20:11 2020
From: murdoch@dunc@n @end|ng |rom gm@||@com (Duncan Murdoch)
Date: Wed, 9 Dec 2020 10:20:11 -0500
Subject: [Rd] New pipe operator
In-Reply-To: <d5010e6f-f997-48f5-744c-2c9bc760d523@eoos.dds.nl>
References: <e55c2093-0bb5-5f9b-5521-0ca8bdf35953@gmail.com>
 <CALyqOb8c1hHOSaMV+fqXTwpeOsP--KJ_t-oeqMYYafVXeNpqZg@mail.gmail.com>
 <7586e034-e287-0970-6480-f82d747b5445@gmail.com>
 <CADfFDC7bT58_+52uvmpHuMMQRNbbmqV3_7t_fc4sgJ_Esw=xag@mail.gmail.com>
 <CAJmOi+PO_8XDC23=rT=pQ76ENL=gx2V-41ax2fHSVs87xURcEA@mail.gmail.com>
 <CAP01uRkkd3jOjvaS9JgKYCD1KA83HfzCd+MQSv_2aYJPgcOmSQ@mail.gmail.com>
 <CAP01uRkPcbCBRGwAzKM=W19Ohh-zDGwZH8gM7=A-sK2rRaQxaQ@mail.gmail.com>
 <CAD4oTHFBY4rBhiRsJUkA6jwD2YWaxPMz2OZDOqSvHfv6A7DZPg@mail.gmail.com>
 <CAP01uRmTYna1nM+ugELHrCqLjfWuWwHSfE4cvqoaq2537sHpAw@mail.gmail.com>
 <CAD4oTHHFWkiirncPRWngY+_k9HcB=8zo7VdXAONXQoXdNhKzDA@mail.gmail.com>
 <7e28d84a-f6d0-1e18-c131-163650e7cd75@gmail.com>
 <CAP01uR=vTJ_uy+RURVZnA8vbnnPRTOUkn6a2AEkg4HG2Lu3kaQ@mail.gmail.com>
 <d5010e6f-f997-48f5-744c-2c9bc760d523@eoos.dds.nl>
Message-ID: <d8a8296b-27d4-bbe3-f632-b10b3f308d00@gmail.com>

On 09/12/2020 9:55 a.m., Jan van der Laan wrote:

> 
> I think only allowing functions on the right hand side (e.g. only the |>
> operator and not the |:>) would be enough to handle most cases and seems
> easier to reason about. The limitations of that can easily be worked
> around using existing functionality in the language.

I agree that would be sufficient, but I don't see how it makes reasoning 
easier.  The transformation is trivial, so I'll assume that doesn't 
consume any mental energy compared to understanding what the final 
expression actually does.  Using your currying example, the choice is 
between

  x |> mean(na.rm = TRUE)

which transforms to mean(x, na.rm = TRUE), or your proposed

  x |> curry(mean, na.rm = TRUE)

which transforms to

  curry(mean, na.rm = TRUE)(x)

To me curry(mean, na.rm = TRUE)(x) looks a lot more complicated than 
mean(x, na.rm = TRUE), especially since it has the additional risk that 
users can define their own function called "curry".

Duncan Murdoch

> 
> The problem with only allowing
> 
> x |> mean
> 
> and not
> 
> x |> mean()
> 
> is with additional arguments. However, this can be solved with a
> currying function, for example:
> 
> x |> curry(mean, na.rm = TRUE)
> 
> The cost is a few additional characters.
> 
> In the same way it is possible to write a function that accepts an
> expression and returns a function containing that expression. This can
> be used to have expressions on the right-hand side and reduces the need
> for anonymous functions.
> 
> x |> fexpr(. + 10)
> dta |> fexpr(lm(y ~ x, data = .))
> 
> You could call this function .:
> 
> x |> .(. + 10)
> dta |> .(lm(y ~ x, data = .))
> 
> 
> Dummy example code (thanks to  a colleague of mine)
> 
> 
> fexpr <- function(expr){
>     expr <- substitute(expr)
>     f <- function(.) {}
>     body(f) <- expr
>     f
> }
> . <- fexpr
> 
> curry <- function(fun,...){
>     L <- list(...)
>     function(...){
>       do.call(fun, c(list(...),L))
>     }
> }
> 
> `%|>%` <- function(e1, e2) {
>     e2(e1)
> }
> 
> 
> 1:10 %>% mean
> c(1,3,NA) %|>% curry(mean, na.rm = TRUE)
> c(1,3,NA) %|>% .( mean(., na.rm = TRUE) ) %>% identity
> c(1,3,NA) %|>% .( . + 4)
> c(1,3,NA) %|>% fexpr( . + 4)
> c(1,3,NA) %|>% function(x) mean(x, na.rm = TRUE) %>% fexpr(. + 1)
> 
> --
> Jan
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



[Rd] New pipe operator
Duncan Murdoch