2016-03-22 21 views
6

Kısa örnek. Bir fonksiyonun davranışını, farklı "spesifikasyonlar", f(spec) ile test ederek araştırıyorum. Bir spekülasyonu el ile yazdım, spec1 ve üzerinde varyasyon olarak yeni özellikler oluşturuyorum. str(res1) insan tarafından okunabilir olması için (... hayır <environment: ptr>Temiz, basit işlev fabrikaları R

  1. all.equal(spec1, res1) ve/veya identical(spec1, res1)
  2. make_spec için

    spec1 = list(fy = list(a = 1), fx = list(f1 = function(x) 10-x, f2 = function(x) 2-x)) 
    
    make_spec = function(f = function(x) 10-x, xtheta = 2) 
        list(fy = list(a = 1), fx = list(f1 = f, f2 = function(x) xtheta-x)) 
    
    res1 = make_spec() 
    
    # first problem: they don't match 
    
        all.equal(res1,spec1) 
        # [1] "Component “fx”: Component “f2”: target, current do not match when deparsed" 
        #^this happens, even though... 
        res1$fx$f2(4) == spec1$fx$f2(4) 
        # TRUE 
    
    # second problem: res1 is fugly 
    
        res1 
        # $fy 
        # $fy$a 
        # [1] 1 
        # 
        # 
        # $fx 
        # $fx$f1 
        # function (x) 
        # 10 - x 
        # <environment: 0x000000000f8f2e20> 
        # 
        # $fx$f2 
        # function (x) 
        # xtheta - x 
        # <environment: 0x000000000f8f2e20> 
    
        str(res1) 
        # even worse 
    

    Benim hedefler şunlardır: Bunu yapmak için, bir fonksiyon yazmaya karar Mümkünse

  3. veya substitute ve 'dan kaçınmak için substitute ikinci arg dışarı yazılmasını önlemek için

bu hedeflerin bazılarını veya tümünü elde etmek için deyimsel yolu var mı (aşağıda "tam" örnek bakınız)?


Tam örnek. Yukarıdaki örnek tamamen benim kullanma durumu kapsıyorsa yüzden burada ikincisiyse, emin değilim:

spec0 = list(
    v_dist = list(
     pdf = function(x) 1, 
     cdf = function(x) x, 
     q = function(x) x, 
     supp = c(0,1) 
    ) 
    , 
    ucondv_dist = { 
     ucondv_dist = list() 
     ucondv_dist$condmean = function(v) 10-v 
     ucondv_dist$pdf   = function(u,v) dnorm(u, ucondv_dist$condmean(v), 50) 
     ucondv_dist$cdf   = function(u,v) pnorm(u, ucondv_dist$condmean(v), 50) 
     ucondv_dist 
    } 
) 

make_spec = function(ycondx_condmean = function(x) 10-x, ycondx_sd = 50){ 

    s = substitute(list(
    x_dist = list(
     pdf = function(x) 1, 
     cdf = function(x) x, 
     q = function(x) x, 
     supp = c(0,1) 
    ) 
    , 
    ycondx_dist = { 
     ycondx_dist = list() 
     ycondx_dist$condmean = ycondx_condmean 
     ycondx_dist$pdf  = function(u,v) dnorm(u, ycondx_dist$condmean(v), ycondx_sd) 
     ycondx_dist$cdf  = function(u,v) pnorm(u, ycondx_dist$condmean(v), ycondx_sd) 
     ycondx_dist 
    } 
) 
    , list(ycondx_condmean=ycondx_condmean, ycondx_sd = ycondx_sd)) 

    eval(s, .GlobalEnv) 
} 

res0 = make_spec() 

Yan not. Burada "işlev fabrikası" nın doğru terim olup olmadığını bilmiyorum, çünkü bilgisayar bilimcisi değilim, ama ilgili görünüyor. Sadece a paragraph on the concept related to R'u buldum.

+0

Aslında sadece Ar sevmiyorum ve gerçekten belki başka bir dilde, Scala veya erlang aradığınız görünür .. 'str' fonksiyonu oldukça karmaşık ama kesinlikle yeniden yazmak için bekliyoruz. Bu, makul bir SO sorusunun ne olacağı kadar büyük bir proje olurdu. 'Eval' ve 'substitute' kullanmadan dili programlamaya çalışmak fikri sapık görünüyor ve hiçbir şekilde haklı görülemiyor. –

+1

@ 42- Geri bildirim için teşekkürler. Eh, 'eval' ve 'substitute' kaçınarak öncelikleri listemde düşük, ama ben sadece aptalca onlardan kaçınarak bir şekilde bakan, bunu bilmek isterdim. – Frank

+1

bölüm 1'e erişebilirsiniz (yalnızca bir işlevden daha fazlasını döndürdüğünüzden), "kitaplık (pryr)", "res1 $ fx <- gecikme (res1 $ fx, unenclose)", "all.equal (res1, spec1)) – Chris

cevap

3

İşlevlerin çevreleyen ortamları, ayrıştırmadaki çıkış/fark farklılıklarına yol açacak şekilde farklıdır.

  • aynı
  • yedek fonksiyon bedenlerine çevreleyen ortamlardan değişkenleri ortamlarını olun: Yani, istenilen çıktıyı elde etmek için iki şey vardır.

Ancak, bu şekilde yapmak istemediğiniz değerlendirme/ikame çift dozunu alırsınız, bu yüzden belki de alternatif olabilir.

make_spec <- function(f = function(x) 10-x, xtheta = 2) { 
    e <- parent.frame() 
    fixClosure <- function(func) 
    eval(eval(substitute(substitute(func)), parent.frame()), e) 

    list(fy = list(a = 1), fx = list(
    f1 = fixClosure(f), 
    f2 = fixClosure(function(x) xtheta-x) 
)) 
} 

spec1 <- list(fy = list(a = 1), fx = list(f1 = function(x) 10-x, f2 = function(x) 2-x)) 
res1 <- make_spec() 

all.equal(res1, spec1) 
[1] TRUE 
+0

Teşekkürler. Burada kullanılan ve bu yaklaşımı beğendiğim gibi değerlendirme ve ikame ile iyiyim. Soruyu bir süre açık bırakmaya gidiyorum, çünkü bir süredir orijinal problemime herhangi bir çözüm getirme şansım olmayacak. – Frank