Breve esempio. Sto esplorando il comportamento di una funzione provandola con diverse "specifiche", f(spec)
. Ho annotato una specifica a mano, spec1
, e sto creando nuove specifiche come variazioni su di essa. Per fare questo, ho deciso di scrivere una funzione:Fabbriche di funzioni semplici e pulite in 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
I miei obiettivi per make_spec
sono ...
all.equal(spec1, res1)
e/oidentical(spec1, res1)
- per
str(res1)
di essere leggibile (senza<environment: ptr>
tag o) - per evitare
substitute
eeval
del tutto se possibile (non ad alta priorità) - di evitare di scrivere il secondo arg di
substitute
(vedi esempio "pieno" di seguito)
C'è un modo idiomatico per raggiungere alcuni o tutti questi obiettivi?
Esempio completo. non sono sicuro se l'esempio precedente copre interamente il mio caso d'uso, quindi ecco il secondo:
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()
Nota a margine. Non so se "fabbrica di funzioni" è il termine giusto qui, dal momento che io non sono uno scienziato informatico, ma sembra correlato. Ho trovato solo a paragraph on the concept related to R.
In realtà sembra proprio non piace R e cercate un'altra lingua, Scala o Erlang forse .. La funzione 'str' è piuttosto complesso, ma si sono certamente benvenuto a riscriverlo. Quello sarebbe un grande progetto, ben al di sopra di quello che sarebbe una domanda ragionevole. L'idea di provare a programmare sulla lingua senza usare "eval" e "sostitutivi" sembra perversa e in nessun caso giustificata. –
@ 42- Grazie per il feedback. Beh, evitando 'eval' e' sostitutivi' è in basso nella mia lista di priorità, ma se sto solo stupidamente trascurando un modo per evitarli, mi piacerebbe saperlo. – Frank
è possibile ottenere la parte 1 (goffamente perché si restituisce più di una funzione) usando 'library (pryr)', 'res1 $ fx <- lapply (res1 $ fx, unenclose)', 'all.equal (res1, spec1) ' – Chris