Function Composition in R (and high level functions)
You may make compositing function like this:
composite<-function(f,g) function(...) f(g(...))
f<-function(x) x+1;
g<-function(x) x*2;
composite(f,g)(7)
composite(g,f)(7)
or make operator of this.
About the second point, there are lots of such; I think the most used are the *apply family (sapply, mapply, tapply, lapply, apply...).
Function composition assigned to %@% operator in R
I don't know whether it is appropriate, but my first intention would be the following:
`%@%` <- function(f,g) {
if(is.function(f) && is.function(g)) {
#both functions, composition as usual
return(function(...) {f(g(...))} )
}
if(!is.function(f)) {
#f is no function, hence a constant value, return it.
return(f)
}
if(is.function(f) && !is.function(g)) {
#f is function, g not, hence g is the argumemnt to f
return(f(g))
}
}
Some test:
sq <- function(x) x^2
sq %@% sq %@% 5 #625
base::identity %@% base::identity %@% 5 #5
exp %@% log %@% 5 #5
5 %@% sin #5
tanh %@% exp %@% abs %@% sin %@% -pi/4 #0.1903985
A function within a function in the R language
Using the accepted answer in another post, just use Reduce
to create the composition, g
.
composite <- function(g, h) {function(...)g(h(...))}
g <- Reduce(composite, list(f, f, f, f, f))
g(2)
f(f(f(f(f(2)))))
identical(g(2), f(f(f(f(f(2))))))
#[1] TRUE
How can I write a recursive compose function in R?
1) Try this:
comp1 <- function(f, ...) {
if (missing(f)) identity
else function(x) f(comp1(...)(x))
}
# test
comp1(sin, cos, tan)(pi/4)
## [1] 0.5143953
# compose is defined in the question
compose(sin, cos, tan)(pi/4)
## [1] 0.5143953
functional::Compose(tan, cos, sin)(pi/4)
## [1] 0.5143953
sin(cos(tan(pi/4)))
## [1] 0.5143953
library(magrittr)
(pi/4) %>% tan %>% cos %>% sin
## [1] 0.5143953
(. %>% tan %>% cos %>% sin)(pi/4)
## [1] 0.5143953
1a) A variation of (1) which uses Recall
is:
comp1a <- function(f, ...) {
if (missing(f)) identity
else {
fun <- Recall(...)
function(x) f(fun(x))
}
}
comp1a(sin, cos, tan)(pi/4)
## [1] 0.5143953
2) Here is another implementation:
comp2 <- function(f, g, ...) {
if (missing(f)) identity
else if (missing(g)) f
else Recall(function(x) f(g(x)), ...)
}
comp2(sin, cos, tan)(pi/4)
## [1] 0.5143953
3) This implementation is closer to the code in the question. It makes use of of
defined in the question:
comp3 <- function(...) {
if(...length() == 0) identity
else of(..1, do.call("comp3", list(...)[-1]))
}
comp3(sin, cos, tan)(pi/4)
## [1] 0.5143953
How to do Higher Order Composition in Rust?
In Rust, currying is hard. The strict type system, lifetimes, and nested impl
traits not existing all conspire to ruin your day when you try. However, it is possible to create a macro to curry functions, and I did so for code golf at one point. The ungolfed version is here:
macro_rules! curry{
(
$f:ident
$(
($args:ident : $types:ty)
)*
) => {
$(move |$args: $types|)*
$f(
$($args),*
)
}
}
This matches on expressions of the form name(arg1, type1)(arg2, type2)...(argN, typeN)
and returns a chain of move
closures leading to the function call. Most of the time, however, you can just use _
for the type and let inference figure it out. Using it with compose
is simple:
let inc = |x| x as u32 + 1;
let double = |x| x * 2;
let curried = curry!(compose(f: _)(g: _));
assert_eq!(curried(inc)(double)(7), 16);
The code generated by the macro, in this case, looks like this:
move |f: _| move |g: _| compose(f, g)
It simply takes the supplied name and type and pastes it into the closure heads, so you can use it to force arguments for generic functions into concrete types.
Playground
N times function composition
You are on the right path. Based on the requirements, I would try to start from those equations:
compunere 1 f x == f x
The above says that applying f
once to x
is exactly the same as doing (f x)
.
compunere 2 f x == f (f x)
Likewise, applying f
twice should compute f (f x)
. If you replace (f x)
by a call to compunere
, you have:
compunere 2 f x == f (f x) = f (compunere 1 f x)
The general pattern of recursion seems to be:
compunere n f x == f (compunere (n - 1) f x)
Note that the most general type of f
is a -> b
, but when f
is called again with a value of type b
, that means that a
and b
should be the same type, and so f
really is an endomorphism, a function of type a -> a
. That is the case for N >= 1, but in degenerate case of N=0, you could have a different behaviour.
Applying f
zero time to x
could mean "return x", which means that compunere
could theoretically return a value of type a
for zero, for any f
being a a -> b
function, a
and b
possibly distinct; you could distinguish both cases with more code, but here we can simply let the typechecker enforce the constraint that a = b
in all cases and have an uniform behaviour. You can also make 0 invalid (like negative numbers) by throwing an exception (negative applications could theoretically be postitive applications of the inverse function, but you cannot compute that when knowing nothing about f; f could be non-invertible).
Your code is a little bit different:
compunere 3 f x == (compunere 2 f (f x))
== (compunere 1 f (f (f x)))
== (compunere 0 f (f (f (f x))))
...
The advantage of your approach is that the recursive call to compunere
is directly giving the result for the current computation: it is in tail position which allows the compiler to perform tail-call elimination.
When you reach N=0, the value locally bound x
gives the result you want. Here, for N=0 as an input, the only natural interpretation is also to return x
.
Scheme function that return composition of functions
A clean solution would be
(define (comp-func . procs)
(define (comp-rec arg procs)
(if (null? procs)
arg
((car procs) (comp-rec arg (cdr procs)))))
comp-rec)
However with this solution you need to call it like this ((comp-func f g h) 1 (list f g h))
.
Here is a solution that will work if you call it like in your examples, however it is a bit uglier because we need to use set!
to change procs
argument.
(define (comp-func . procs)
(define (comp-rec arg)
(if (null? procs)
arg
(let ((proc (car procs))
(rest (cdr procs)))
(set! procs rest)
(proc (comp-rec arg)))))
comp-rec)
Related Topics
R 'Inf' When It Has Class 'Date' Is Printing 'Na'
Replicate a List to Create a List-Of-Lists
Can You Pass a Vector to a Vararg: Vector to Sprintf
Freezing Header and First Column Using Data.Table in Shiny
Alignment of Numbers on the Individual Bars with Ggplot2
How to Ensure That a Partition Has Representative Observations from Each Level of a Factor
Weighted Means by Group and Column
Removing Traces by Name Using Plotlyproxy (Or Accessing Output Schema in Reactive Context)
How to Create a Variable of Rownames
Navlistpanel: Make Tabs Sequentially Active in Shiny App
How to Install R-Packages Not in the Conda Repositories
How Is Data Passed from Reactive Shiny Expression to Ggvis Plot
Determine Season from Date Using Lubridate in R