2011-10-26 19 views
16

Hôm qua tôi đã học từ Bill Venables cách địa phương() có thể giúp tạo ra các chức năng tĩnh và các biến, ví dụ như,Địa phương() khác với các cách tiếp cận khác để đóng cửa trong R như thế nào?

example <- local({ 
    hidden.x <- "You can't see me!" 
    hidden.fn <- function(){ 
    cat("\"hidden.fn()\"") 
    } 
    function(){ 
    cat("You can see and call example()\n") 
    cat("but you can't see hidden.x\n") 
    cat("and you can't call ") 
    hidden.fn() 
    cat("\n") 
    } 
}) 

mà ứng xử như sau từ dấu nhắc lệnh:

> ls() 
[1] "example" 
> example() 
You can see and call example() 
but you can't see hidden.x 
and you can't call "hidden.fn()" 
> hidden.x     
Error: object 'hidden.x' not found 
> hidden.fn() 
Error: could not find function "hidden.fn" 

Tôi đã nhìn thấy này loại điều được thảo luận trong Static Variables in R, nơi một cách tiếp cận khác được sử dụng.

Ưu và nhược điểm của hai phương pháp này là gì?

Trả lời

12

Encapsulation

Ưu điểm của phong cách này của chương trình là các đối tượng ẩn sẽ không có khả năng được ghi đè bởi bất cứ điều gì khác, do đó bạn có thể tự tin hơn mà chúng chứa những gì bạn nghĩ. Họ sẽ không được sử dụng do nhầm lẫn vì họ không thể dễ dàng được truy cập. Trong bài đăng được liên kết trong câu hỏi có một biến toàn cầu, count, có thể được truy cập và ghi đè từ bất kỳ đâu, vì vậy nếu chúng tôi đang gỡ lỗi mã và xem count và xem nó đã thay đổi, chúng tôi không thể chắc chắn phần nào của mã đã thay đổi nó. Ngược lại, trong mã ví dụ của câu hỏi, chúng tôi đảm bảo rằng không có phần nào khác của mã được tham gia.

Lưu ý rằng chúng tôi thực sự có thể truy cập vào các chức năng ẩn mặc dù nó không phải là dễ dàng:

# run hidden.fn 
environment(example)$hidden.fn() 

Object Oriented Programming

Cũng lưu ý rằng đây là rất gần với đối tượng lập trình hướng nơi examplehidden.fn là phương thức và hidden.x là một thuộc tính. Chúng ta có thể làm điều đó như thế này để làm cho nó rõ ràng:

library(proto) 
p <- proto(x = "x", 
    fn = function(.) cat(' "fn()"\n '), 
    example = function(.) .$fn() 
) 
p$example() # prints "fn()" 

proto không giấu xfn nhưng nó không phải là dễ dàng để truy cập chúng do nhầm lẫn vì bạn phải sử dụng p$xp$fn() để truy cập chúng mà không phải là thực sự là khác nhau hơn là khả năng viết e <- environment(example); e$hidden.fn()

EDIT:

cách tiếp cận hướng đối tượng không thêm khả năng thừa kế, ví dụ người ta có thể xác định một đứa trẻ của p hoạt động như p ngoại trừ việc nó ghi đè fn.

ch <- p$proto(fn = function(.) cat("Hello from ch\n")) # child 
ch$example() # prints: Hello from ch 
6

local() có thể thực hiện một mẫu singleton - ví dụ, gói snow sử dụng này để theo dõi các trường hợp Rmpi ​​duy nhất mà người dùng có thể tạo ra.

getMPIcluster <- NULL 
setMPIcluster <- NULL 
local({ 
    cl <- NULL 
    getMPIcluster <<- function() cl 
    setMPIcluster <<- function(new) cl <<- new 
}) 

local() cũng có thể sử dụng để quản lý bộ nhớ trong một kịch bản, ví dụ, phân bổ đối tượng trung gian lớn yêu cầu phải tạo ra một đối tượng cuối cùng trên dòng cuối cùng của mệnh đề. Các đối tượng trung gian lớn có sẵn để thu gom rác khi trả lại local.

Sử dụng hàm để tạo đóng là mẫu nhà máy - ví dụ bank account trong tài liệu Giới thiệu về R, mỗi lần open.account được gọi, tài khoản mới được tạo.

Như @otsaw đề cập, memoization có thể được thực hiện bằng cách sử địa phương, ví dụ như, đến các trang web trong bộ nhớ cache một trình thu thập

library(XML) 
crawler <- local({ 
    seen <- new.env(parent=emptyenv()) 
    .do_crawl <- function(url, base, pattern) { 
     if (!exists(url, seen)) { 
      message(url) 
      xml <- htmlTreeParse(url, useInternal=TRUE) 
      hrefs <- unlist(getNodeSet(xml, "//a/@href")) 
      urls <- 
       sprintf("%s%s", base, grep(pattern, hrefs, value=TRUE)) 
      seen[[url]] <- length(urls) 
      for (url in urls) 
       .do_crawl(url, base, pattern) 
     } 
    } 
    .do_report <- function(url) { 
     urls <- as.list(seen) 
     data.frame(Url=names(urls), Links=unlist(unname(urls)), 
        stringsAsFactors=FALSE) 
    } 
    list(crawl=function(base, pattern="^/.*html$") { 
     .do_crawl(base, base, pattern) 
    }, report=.do_report) 
}) 

crawler$crawl(favorite_url) 
dim(crawler$report()) 

(ví dụ thông thường của memoization, số Fibonacci, là không thỏa mãn - phạm vi các con số không làm tràn biểu diễn dạng số của R là nhỏ, vì vậy, một số có thể sử dụng bảng tra cứu các giá trị được tính toán hiệu quả). Thú vị như thế nào trình thu thập thông tin ở đây là một singleton; có thể dễ dàng theo dõi mẫu nhà máy, do đó, một trình thu thập thông tin trên mỗi URL cơ sở.

+1

Một mẫu khác mà 'cục bộ 'tạo thuận lợi là ghi nhớ. Có một ví dụ ở đâu đó trong The R Inferno. – otsaw

+0

Suy nghĩ của bạn về trình thu thập thông tin là một singleton rất thú vị bởi vì một thay thế cho địa phương là ngay lập tức đánh giá một hàm ẩn danh mà không có đối số - một mẫu nhà máy có thể sử dụng một đóng trên url cơ sở. – hadley

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