2010-02-09 5 views
35

R에서 작성 연산자를 만들 수 있습니다.R의 상위 레벨 기능 - 공식 작성 연산자 또는 카레 기능이 있습니까?

 `%c%` = function(x,y)function(...)x(y(...)) 

다음과 같이 사용합니다.

 > numericNull = is.null %c% numeric 
> numericNull(myVec) 
[2] TRUE FALSE 

하지만 이런 종류의 작업을 수행하는 공식 함수가 있는지 알고 싶습니다. 그리고 R에서 currying과 같은 다른 작업. 대개 이것은 내 코드에서 괄호, 함수 키워드 등의 수를 줄이는 것입니다.

내 카레 기능 :

> curry=function(...){ 
    z1=z0=substitute(...);z1[1]=call("list"); 
    function(...){do.call(as.character(z0[[1]]), 
          as.list(c(eval(z1),list(...))))}} 
> p = curry(paste(collapse="")) 
> p(letters[1:10]) 
[1] "abcdefghij" 

이것은 특히 예를 들어 특히 좋습니다. 집합체 :

> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10]) 
> aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper) 
    l x 
1 1 ADG 
2 2 BCH 
3 3 EFIJ 

다음 중 어떤 것보다 더 우아하고 편집 가능한 것으로 나타났습니다 :

> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x))) 
    l x 
1 1 ADG 
2 2 BCH 
3 3 EFIJ 

기본적으로 알고 싶습니다.

+0

내 카레 호출은 현재 카레 변수가 호출 된 환경에서 카디 변수를 바인딩하지 않지만 반환 된 함수가 호출되는 곳에서 바인딩됩니다. 나는 그 일을하고있다. –

+2

더 나은 기본값을 가진 붙여 넣기 기능을 원한다면 왜 카레 시도가 필요할까요? 예를 들어 'paste0 <- function (x, ...) paste (toupper (x), collapse = "", ...)'그러면 aggregate (df $ t, df [ "l"], paste0)'를 호출 할 수있다. –

+4

입니다. 더 많은 기능을 스택하려는 경우 더 복잡해지기 때문입니다. –

답변

5

R의 함수 프로그래밍을위한 표준 장소는 이제 functional 라이브러리입니다. 라이브러리에서

:

기능 : 카레, 작성, 및 기타 고차 함수

예 :

library(functional) 
    newfunc <- Curry(oldfunc,x=5) 

CRAN : https://cran.r-project.org/web/packages/functional/index.html

PS :이 라이브러리 substit 라이브러리 ROxigen.

2

roxygen 패키지에는 Curry라는 기능이 있습니다.
R Mail 보관함에있는 this conversation을 통해 있습니다.

+0

슬프게도 링크가 작동하지 않습니다. 아마도 다음과 같습니다. https://stat.ethz.ch/pipermail/r-help/2009-December/221224.html –

+0

@FlorianJenn 감사합니다; 나는 대답의 링크를 업데이트했다. –

28

이러한 기능은 모두 실제로 피터 Danenberg에서 the roxygen package (see the source code here)에 존재하는 (원래 Byron Ellis's solution on R-Help에 기반) :

Curry <- function(FUN,...) { 
    .orig = list(...); 
    function(...) do.call(FUN,c(.orig,list(...))) 
} 

Compose <- function(...) { 
    fs <- list(...) 
    function(...) Reduce(function(x, f) f(x), 
         fs, 
         ...) 
} 

참고 일을하려고 할 때 매우 도움이 될 수있는 Reduce 기능의 사용, 자세한 내용은 Reduce를 참조하십시오 (MapFilter과 같은 다른 기능도 포함).

그리고 카레 (이 사용량이 약간 다른) 당신의 예 : 여기

> library(roxygen) 
> p <- Curry(paste, collapse="") 
> p(letters[1:10]) 
[1] "abcdefghij" 

가 (문자로 세 가지 다른 기능을 적용) Compose의 유틸리티를 보여주는 예입니다 :

> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters) 
[1] "ZYXWVUTSRQPONMLKJIHGFEDCBA" 

그리고 마지막 예는 다음과 같이 작동합니다.

> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper)) 
    l x 
1 1 ABG 
2 2 DEFH 
3 3 CIJ 

마지막으로, 여기에 (쉽게 by와 함께 할 수 또는 aggregate가 이미 표시된 수) plyr과 같은 일을 할 수있는 방법이다 :

당신이 변수의 '이름'을 원하는 경우 더 복잡한 접근 방식이 필요
> library(plyr) 
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse="")) 
    l V1 
1 1 ABG 
2 2 DEFH 
3 3 CIJ 
+2

함수형 프로그래밍을위한 글쓰 릭 프로그래밍에 패키지를 사용하는 것에 대해 잘못된 점이 있습니까? R 라이브러리의 모듈성에 대해 뭐라고 말합니까? – piccolbo

+9

FWIW,'Compose'와'Curry'가 잠시'functional' 패키지로 옮겨졌습니다. –

2

정확하게 통과해야합니다.

예를 들어 plot(rnorm(1000),rnorm(1000))을 입력하면 x 축과 y 축에 멋진 라벨이 표시됩니다. 이것의 또 다른 예는 data.frame이 컬럼에 유용한 이름을 할당 한 것을 data.frame

> data.frame(rnorm(5), rnorm(5), first=rpois(5,1), second=rbinom(5,1,0.5)) 
    rnorm.5. rnorm.5..1 first second 
1 0.1964190 -0.2949770  0  0 
2 0.4750665 0.8849750  1  0 
3 -0.7829424 0.4174636  2  0 
4 1.6551403 1.3547863  0  1 
5 1.4044107 -0.4216046  0  0 

되지 않습니다.

카레의 일부 구현은 올바르게 수행되지 않아 읽을 수없는 열 이름과 플롯 레이블을 만들 수 있습니다. 대신, 지금 같은 것을 사용

Curry <- function(FUN, ...) { 
    .orig = match.call() 
    .orig[[1]] <- NULL # Remove first item, which matches FUN 
    .orig[[1]] <- NULL # Remove another item, which matches Curried argument 
    function(...) { 
     .inner = match.call() 
     .inner[[1]] <- NULL # Remove first item, which matches Curry 
     do.call(FUN, c(.orig, .inner), envir=parent.frame()) 
    } 
} 

이 꽤 복잡합니다,하지만 나는 그것이 올바른 생각합니다. match.call은 args를 정의한 표현식을 완전히 기억하면서 모든 args를 잡아낼 것입니다 (이것은 멋진 레이블에 필수적입니다). 문제는 단지 ...뿐만 아니라 FUN도 너무 많은 args를 잡는다는 것입니다. 또한 호출되는 함수의 이름을 기억합니다 (Curry).

따라서 .orig에서 처음 두 항목을 삭제하여 .orig이 실제로는 ... 인수에 해당합니다. 그래서 .orig[[1]]<-NULL을 두 번 썼습니다. 매번 엔트리가 삭제되고 나머지는 왼쪽으로 이동합니다.

는이 정의를 완료하고 우리는 지금 envir=parent.frame()

Curry(data.frame, rnorm(5), rnorm(5))(first=rpois(5,1) , second=rbinom(5,1,0.5)) 

마지막 주 위와 같이 정확히 같은를 얻기 위해 다음을 수행 할 수 있습니다. 저는 .inner 나 .orig라는 외부 변수가 있으면 문제가되지 않도록이 방법을 사용했습니다. 이제는 모든 변수가 카레가 호출되는 위치에서 평가됩니다.

+0

(답변자) 오늘은 방금 이것을 발명했습니다. 나는 그것이 벌써 끝났다라고 생각한다? 그리고 아마도 내가 모르는 결함이있을 것입니다! –

관련 문제