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à ...
all.equal(spec1, res1)
và/hoặcidentical(spec1, res1)
- cho
str(res1)
là con người có thể đọc được (không<environment: ptr>
hoặcsrcfilecopy
) - để tránh
substitute
vàeval
hoàn toàn nếu có thể (không phải ưu tiên cao) - để 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.
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ý. –
@ 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
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