وظائف المستوى الأعلى في R - هل هناك مشغل يؤلف رسميا أو وظيفة كاري؟
-
19-09-2019 - |
سؤال
يمكنني إنشاء مشغل يؤلف في R:
`%c%` = function(x,y)function(...)x(y(...))
لاستخدامها مثل هذا:
> numericNull = is.null %c% numeric
> numericNull(myVec)
[2] TRUE FALSE
ولكن أود أن أعرف ما إذا كان هناك مجموعة رسمية من الوظائف للقيام بهذا النوع من الأشياء وغيرها من العمليات مثل الكهرج في R. هذا إلى حد كبير للحد من عدد الأقواس، والكلمات الرئيسية الوظيفية وغيرها في التعليمات البرمجية.
وظيفة الكاري الخاصة بي:
> 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
أساسا أريد أن أعرف - هل تم ذلك بالفعل ل R؟
المحلول
المكان القياسي للبرمجة الوظيفية في R هو الآن functional
مكتبة.
من المكتبة:
وظيفية: الكاري، وتأليف، وغيرها من وظائف الدرجة العليا
مثال:
library(functional)
newfunc <- Curry(oldfunc,x=5)
Cran:https://cran.r-project.org/web/packages/functional/index.html.
PS: هذه المكتبة بديل ROxigen
مكتبة.
نصائح أخرى
كل من هذه الوظائف موجودة بالفعل في ال roxygen
صفقة (انظر شفرة المصدر هنا) من بيتر دانينبرغ (كان أساسا أساسا حل Byron Ellis على 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
وظيفة، والتي يمكن أن تكون مفيدة للغاية عند محاولة القيام برمجة وظيفية في R. انظر؟ تقلل لمزيد من التفاصيل (والتي تغطي أيضا وظائف أخرى مثل Map
و Filter
).
ومثالك على الكاري (مختلفة قليلا في هذا الاستخدام):
> 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
أخيرا، إليك طريقة للقيام بنفس الشيء plyr
(يمكن أيضا القيام به بسهولة by
أو aggregate
كما هو موضح بالفعل):
> library(plyr)
> ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))
l V1
1 1 ABG
2 2 DEFH
3 3 CIJ
هناك وظيفة تسمى الكاري في روكسجين صفقة.
وجدت عبر هذه المحادثة على أرشيف البريد الإلكتروني.
مطلوب نهج أكثر تعقيدا إذا كنت تريد "أسماء" المتغيرات لتمرير بدقة.
على سبيل المثال، إذا قمت بذلك plot(rnorm(1000),rnorm(1000))
ثم ستحصل على ملصقات لطيفة على محاور X و Y. مثال آخر على هذا هو 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
ليس أن Data.Frame قد عين أسماء مفيدة للأعمدة.
قد لا تفعل بعض تطبيقات الكاري هذا بشكل صحيح، مما يؤدي إلى أسماء الأعمدة غير القابلة للقراءة وتسميات المؤامرة. بدلا من ذلك، أنا الآن استخدم شيئا مثل هذا:
Curry <- function(FUN, ...) {
.orig = match.call()
.orig[[1]] <- NULL # Remove first item, which matches Curry
.orig[[1]] <- NULL # Remove another item, which matches FUN
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 (هذا ضروري للملصقات اللطيفة). المشكلة هي أنه يمسك الكثير من Args - وليس فقط ...
ولكن أيضا FUN
. وبعد كما يتذكر اسم الوظيفة التي يتم استدعاؤها (Curry
).
لذلك، نريد حذف هذه الإدخالات الأولى .orig
لهذا السبب .orig
حقا يتوافق فقط مع ...
الحجج. لهذا السبب نفعل .orig[[1]]<-NULL
مرتين - في كل مرة يحذف إدخال وتتحول كل شيء آخر إلى اليسار.
هذا يكمل التعريف ويمكننا الآن القيام بما يلي للحصول عليه بالضبط نفس أعلاه
Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )
ملاحظة أخيرة على envir=parent.frame()
. وبعد لقد استخدمت هذا لضمان عدم وجود مشكلة إذا كان لديك متغيرات خارجية تسمى ".inner" أو ".orig". الآن، يتم تقييم جميع المتغيرات في المكان الذي يطلق عليه الكاري.