2016-03-22 18 views
6

Ví dụ ngắn. Tôi đang khám phá hành vi của một hàm bằng cách thử nghiệm nó với "thông số kỹ thuật" khác nhau, f(spec). Tôi đã viết xuống một thông số bằng tay, spec1 và đang tạo thông số mới làm biến thể trên đó. Để làm điều này, tôi quyết định viết một hàm:Nhà máy chức năng đơn giản, sạch sẽ trong R

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 

Mục tiêu của tôi cho make_spec là ...

  1. all.equal(spec1, res1) và/hoặc identical(spec1, res1)
  2. cho str(res1) là con người có thể đọc được (không <environment: ptr> hoặc srcfilecopy)
  3. để tránh substituteeval hoàn toàn nếu có thể (không phải ưu tiên cao)
  4. để tránh phải viết ra arg thứ hai của substitute (xem "đầy đủ" ví dụ dưới đây)

Có một cách thành ngữ để đạt được một số hoặc tất cả các mục tiêu này?


Ví dụ đầy đủ. Tôi không chắc chắn nếu ví dụ trên đầy đủ bao gồm trường hợp sử dụng của tôi, vì vậy đây là cái sau:

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() 

Side lưu ý. Tôi không biết liệu "nhà máy chức năng" có phải là thuật ngữ đúng ở đây hay không, vì tôi không phải là nhà khoa học máy tính, nhưng dường như có liên quan. Tôi chỉ tìm thấy a paragraph on the concept related to R.

+0

Trên thực tế nó xuất hiện bạn chỉ không thích R và đang thực sự tìm kiếm một ngôn ngữ khác, Scala hoặc erlang có lẽ .. Lệnh 'chức năng str' là khá phức tạp nhưng bạn chắc chắn chào đón để viết lại nó. Đó sẽ là một dự án lớn, cao hơn những gì sẽ là một câu hỏi SO hợp lý. Khái niệm cố gắng lập trình trên ngôn ngữ mà không sử dụng 'eval' và' replace' có vẻ như ngược và hư không hợp lý. –

+1

@ 42- Cảm ơn bạn đã phản hồi. Ừm, tránh 'eval' và' replace' thấp trong danh sách các ưu tiên của tôi, nhưng nếu tôi chỉ ngớ ngẩn nhìn theo cách nào đó để tránh chúng, tôi muốn biết điều đó. – Frank

+1

bạn có thể lấy phần 1 (vụng về bởi vì bạn trả về nhiều hơn chỉ một hàm) bằng cách sử dụng 'thư viện (pryr)', 'res1 $ fx <- lapply (res1 $ fx, unenclose)', 'all.equal (res1, spec1) ' – Chris

Trả lời

3

Môi trường kèm theo của các chức năng khác nhau dẫn đến sự khác biệt về đầu ra/sự khác biệt trong deparsing. Vì vậy, có hai điều cần làm để có được những kết quả mong muốn:

  • làm cho môi trường cùng
  • thay thế các biến từ môi trường kèm theo vào cơ quan chức năng.

Tuy nhiên, thực hiện theo cách này bạn sẽ nhận được liều tăng gấp đôi của eval/thay thế mà bạn không muốn, vì vậy có thể sẽ có sự thay thế.

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

Cảm ơn. Tôi tốt với eval và thay thế như được sử dụng ở đây và như cách tiếp cận này. Sẽ rời khỏi câu hỏi mở một lúc, vì tôi sẽ không có cơ hội áp dụng bất kỳ giải pháp nào cho vấn đề ban đầu của tôi trong một thời gian. – Frank

Các vấn đề liên quan