Pisanie funkcji w R, pamiętając o zakresach

Często piszę funkcje, które muszą widzieć inne obiekty w moim środowisku. Na przykład:

> a <- 3
> b <- 3
> x <- 1:5
> fn1 <- function(x,a,b) a+b+x
> fn2 <- function(x) a+b+x
> fn1(x,a,b)
[1]  7  8  9 10 11
> fn2(x)
[1]  7  8  9 10 11

Zgodnie z oczekiwaniami obie te funkcje są identyczne, ponieważ fn2 może "widzieć" a i b podczas wykonywania. Ale za każdym razem, gdy zaczynam z tego korzystać, w ciągu około 30 minut kończę wołanie funkcji bez jednej z niezbędnych zmiennych(np. a lub b). Jeśli tego nie wykorzystam, to czuję się, jakbym niepotrzebnie przerzucał przedmioty.

Czy lepiej być jasno o tym, czego wymaga funkcja? A może powinno się o to zadbać poprzez wbudowane komentarze lub inną dokumentację funkcji? Jest lepszy sposób?

 30
Author: AakashM, 2009-07-23

4 answers

Jeśli wiem, że będę potrzebował funkcji parametryzowanej przez pewne wartości i wywoływanej wielokrotnie, unikam globali używając zamknięcia:

make.fn2 <- function(a, b) {
    fn2 <- function(x) {
        return( x + a + b )
    }
    return( fn2 )
}

a <- 2; b <- 3
fn2.1 <- make.fn2(a, b)
fn2.1(3)    # 8
fn2.1(4)    # 9

a <- 4
fn2.2 <- make.fn2(a, b)
fn2.2(3)    # 10
fn2.1(3)    # 8

Pozwala to uniknąć odwoływania się do zmiennych globalnych, zamiast tego używa środowiska zamkniętego funkcji dla a i b. modyfikacja globali a i b nie prowadzi do niezamierzonych efektów ubocznych podczas wywoływania instancji fn2.

 36
Author: ars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-26 05:03:56

Istnieje powód, dla którego niektóre języki nie zezwalają na zmienne globalne: mogą łatwo prowadzić do uszkodzenia kodu.

Reguły zakresów w R pozwalają na pisanie kodu w leniwy sposób - pozwolenie funkcjom na używanie zmiennych w innych środowiskach może zaoszczędzić trochę pisania, i świetnie nadaje się do zabawy w prostych przypadkach.

Jeśli jednak robisz coś zdalnie skomplikowanego, polecam przekazać funkcję wszystkim zmiennym, których potrzebuje (lub przynajmniej mieć jakieś dokładne sprawdzenie stanu zdrowia psychicznego w miejscu, aby mieć awaryjny w przypadku, gdy zmienne nie istnieją).

W powyższym przykładzie:

Najlepszą praktyką jest stosowanie fn1.

Alternatywnie spróbuj czegoś podobnego

 fn3 <- function(x)
   {
      if(!exists("a", envir=.GlobalEnv))
      {
         warning("Variable 'a' does not exist in the global environment")
         a <- 1
      }

      if(!exists("b", envir=.GlobalEnv))
      {
         warning("Variable 'b' does not exist in the global environment")
         b <- 2
      }

      x + a + b
   }
 8
Author: Richie Cotton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-23 08:49:28

Czy problem pojawia się, gdy używasz zmiennej globalnej w funkcji lub gdy próbujesz przypisać zmienną? Jeśli to ta ostatnia, to podejrzewam, że to dlatego, że nie używasz <<- jako przypisania w funkcji. I podczas używania <<- wydaje się być ciemną stroną 1 może bardzo dobrze działać dla Twoich celów. Jeśli jest to pierwsza, funkcja prawdopodobnie maskuje zmienną globalną.

Nazywanie zmiennych globalnych w taki sposób, że trudno byłoby je zamaskować lokalnie może pomóc. np.: global.pimultiples <- 1:4*pi

 3
Author: Tyler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-23 05:15:11

Użycie zmiennych globalnych jest ogólnie zalecane w większości języków, A R nie jest wyjątkiem. Bardzo często funkcja short używa krótkich i ogólnych nazw zmiennych, które mogą być wypełniane w środowisku globalnym. Najbezpieczniej jest a) włączyć wszystkie zmienne w definicji funkcji B) a nie przypisać wartości domyślne. Np. napisz f=function(A,b), a raczej f = function (a = 0, B = NA).

 0
Author: gappy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 01:13:09