Lambda-Like Functions in R

lambda-like functions in R?

You have to look at the source of curve to appreciate what is happening (just type curve at the prompt and press enter).

There you can find how the expression passed is parsed.

The only way a function is discovered as being just that, is when only its name is passed along (see the is.namepart). If that is not the case, the expression is called for every x. In your case: for every x, the result is a function, which is not a happy thought for plotting...

So in short: no you cannot do what you tried, but as @ROLO indicated, you can immediately pass the function body, which will be parsed as an expression (and should contain x). If this holds multiple statements, just enclose them in curly braces.

Is there a better clean approach to single-use functions in R?

You can use with with a list or data-frame as first argument. For example:

result <- with(list(a=3, b=4), {
foo <- a + b
foo^2
})

This keeps the global environment clean, because the part enclosed in brackets is evaluated in a separate environment that is destroyed after the evaluation takes place.

However, in my experience it can become cumbersome to program in this style. Sometimes I find more practical to clean up unwanted objects with rm() when they're no longer needed. It's not as elegant, this I agree.

Anonymous function in lapply

Instead of going over the data frame directly you could switch things around and have lapply go over a vector of the column names,

data(iris)

lapply(colnames(iris), function(x) c(class(iris[[x]]), x))

or over an index for the columns, referencing the data frame.

lapply(1:ncol(iris), function(x) c(class(iris[[x]]), names(iris[x])))

Notice the use of both single and double square brackets.

iris[[n]] references the values of the nth object in the list iris (a data frame is just a particular kind of list), stripping all attributes, making something like mean(iris[[1]]) possible.

iris[n] references the nth object itself, all attributes intact, making something like names(iris[1]) possible.

What is a lambda (function)?

Lambda comes from the Lambda Calculus and refers to anonymous functions in programming.

Why is this cool? It allows you to write quick throw away functions without naming them. It also provides a nice way to write closures. With that power you can do things like this.

Python

def adder(x):
return lambda y: x + y
add5 = adder(5)
add5(1)
6

As you can see from the snippet of Python, the function adder takes in an argument x, and returns an anonymous function, or lambda, that takes another argument y. That anonymous function allows you to create functions from functions. This is a simple example, but it should convey the power lambdas and closures have.

Examples in other languages

Perl 5

sub adder {
my ($x) = @_;
return sub {
my ($y) = @_;
$x + $y
}
}

my $add5 = adder(5);
print &$add5(1) == 6 ? "ok\n" : "not ok\n";

JavaScript

var adder = function (x) {
return function (y) {
return x + y;
};
};
add5 = adder(5);
add5(1) == 6

JavaScript (ES6)

const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6

Scheme

(define adder
(lambda (x)
(lambda (y)
(+ x y))))
(define add5
(adder 5))
(add5 1)
6

C# 3.5 or higher

Func<int, Func<int, int>> adder = 
(int x) => (int y) => x + y; // `int` declarations optional
Func<int, int> add5 = adder(5);
var add6 = adder(6); // Using implicit typing
Debug.Assert(add5(1) == 6);
Debug.Assert(add6(-1) == 5);

// Closure example
int yEnclosed = 1;
Func<int, int> addWithClosure =
(x) => x + yEnclosed;
Debug.Assert(addWithClosure(2) == 3);

Swift

func adder(x: Int) -> (Int) -> Int{
return { y in x + y }
}
let add5 = adder(5)
add5(1)
6

PHP

$a = 1;
$b = 2;

$lambda = fn () => $a + $b;

echo $lambda();

Haskell

(\x y -> x + y) 

Java see this post

// The following is an example of Predicate : 
// a functional interface that takes an argument
// and returns a boolean primitive type.

Predicate<Integer> pred = x -> x % 2 == 0; // Tests if the parameter is even.
boolean result = pred.test(4); // true

Lua

adder = function(x)
return function(y)
return x + y
end
end
add5 = adder(5)
add5(1) == 6 -- true

Kotlin

val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true

Ruby

Ruby is slightly different in that you cannot call a lambda using the exact same syntax as calling a function, but it still has lambdas.

def adder(x)
lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6

Ruby being Ruby, there is a shorthand for lambdas, so you can define adder this way:

def adder(x)
-> y { x + y }
end

R

adder <- function(x) {
function(y) x + y
}
add5 <- adder(5)
add5(1)
#> [1] 6

Loop over character vectors and use elements as column names within lambda function

Those are strings. We need to convert to symbol and evaluate (!!)

library(purrr)
library(dplyr)
out <- map(index, ~iris %>%
filter (!! rlang::sym(.x) > mean(!! rlang::sym(.x))))
names(out) <- index

-output

> str(out)
List of 2
$ Sepal.Length:'data.frame': 70 obs. of 5 variables:
..$ Sepal.Length: num [1:70] 7 6.4 6.9 6.5 6.3 6.6 5.9 6 6.1 6.7 ...
..$ Sepal.Width : num [1:70] 3.2 3.2 3.1 2.8 3.3 2.9 3 2.2 2.9 3.1 ...
..$ Petal.Length: num [1:70] 4.7 4.5 4.9 4.6 4.7 4.6 4.2 4 4.7 4.4 ...
..$ Petal.Width : num [1:70] 1.4 1.5 1.5 1.5 1.6 1.3 1.5 1 1.4 1.4 ...
..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 2 2 2 2 2 2 2 2 2 2 ...
$ Sepal.Width :'data.frame': 67 obs. of 5 variables:
..$ Sepal.Length: num [1:67] 5.1 4.7 4.6 5 5.4 4.6 5 4.9 5.4 4.8 ...
..$ Sepal.Width : num [1:67] 3.5 3.2 3.1 3.6 3.9 3.4 3.4 3.1 3.7 3.4 ...
..$ Petal.Length: num [1:67] 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.5 1.5 1.6 ...
..$ Petal.Width : num [1:67] 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.1 0.2 0.2 ...
..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

-testing with OP's expected

> expected <- list(Sepal.Length = iris %>% filter (Sepal.Length > mean(Sepal.Length)),
+ Sepal.Width = iris %>% filter (Sepal.Width > mean(Sepal.Width)))
>
> identical(out, expected)
[1] TRUE

Or subset with cur_data()

map(index, ~ iris %>%
filter(cur_data()[[.x]] > mean(cur_data()[[.x]])))

Or use across or if_all, which takes directly string

map(index, ~ iris %>%
filter(across(all_of(.x), ~ . > mean(.))))

Is there a way to invoke an AWS Lambda function within rShiny app?

Yes, this is a good use case for AWS Lambda. Lambda can be notified of a new object in S3, do whatever processing is required and write the output back.

Note: Double, triple check you are reading / writing to either different buckets or paths of a bucket and you don't create an infinite loop.

The Lambda function to make a call to AWS Simple Notification Service (SNS) to notify users that a task has finished after it has successfully written the data to S3.

If there are multiple users of this system then you might want to write a small manifest file to S3 which tells the Lambda function which data file to process and the email address of the person to notify.

The Lambda function would then just be triggered by the creation of the manifest.

What is the equivalent of \(x) in lower versions of r?

\ is a syntactic shortcut for the function keyword starting with R 4.1.0. From the documentation:

function( arglist ) expr
\( arglist ) expr

In fact, we can verify the syntactic equivalence ourselves by looking at an unevaluated expression:

quote(\(arglist) expr)
# function(arglist) expr

Why don't lambda functions handle replacement functions in their intuitive form?

Whenever you do an assignment in R, the value returned from that expression is the right hand side value. This is true even for "special" versions of assign functions. For example if you do this

x <- 1:2; y <- (names(x) <- letters[1:2])
> y
[1] "a" "b"

You can see that y gets the values of the names, not the updated value of x.

In your case if you want to return the updated value itself, you need to do so explicitly

lapply(a, function(x) {length(x) <- mx; x})


Related Topics



Leave a reply



Submit