Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R中的惰性序列_R_Clojure_Lazy Sequences - Fatal编程技术网

R中的惰性序列

R中的惰性序列,r,clojure,lazy-sequences,R,Clojure,Lazy Sequences,在Clojure中,使用惰性序列构造函数很容易创建无限序列。比如说, (def N (iterate inc 0)) 返回与无限序列等价的数据对象N (0 1 2 3 ...) 计算值N会导致无限循环。计算(取20 N)返回前20个数字。由于序列是惰性的,因此只有在您要求时才迭代inc函数。由于Clojure是同象的,所以惰性序列是递归存储的 在R中,有可能做类似的事情吗?你能给出一些示例R代码,它生成一个数据对象N,它等价于自然数的完整无限序列吗?对完整对象N求值应该会产生一个循环,但是像

在Clojure中,使用惰性序列构造函数很容易创建无限序列。比如说,

(def N (iterate inc 0))
返回与无限序列等价的数据对象
N

(0 1 2 3 ...)

计算值
N
会导致无限循环。计算
(取20 N)
返回前20个数字。由于序列是惰性的,因此只有在您要求时才迭代
inc
函数。由于Clojure是同象的,所以惰性序列是递归存储的

在R中,有可能做类似的事情吗?你能给出一些示例R代码,它生成一个数据对象
N
,它等价于自然数的完整无限序列吗?对完整对象
N
求值应该会产生一个循环,但是像
head(N)
这样的东西应该只返回前导数字

注意:我对惰性序列而不是自然数本身更感兴趣

编辑:这是
惰性seq
的Clojure源代码:

(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))    

我正在寻找一个在R中具有相同功能的宏。

迭代器
库可能能够实现您想要的:

library(iterators)
i <- icount()
nextElem(i)
# 1
nextElem(i)
# 2
库(迭代器)

我你没有说明你的目标,所以我要指出,用任何语言

j <- 1
while(TRUE) { x[j+1] <- x[j]+1  ; j<-j+1}

j因为R在向量上工作得最好,所以人们似乎经常需要一个返回向量的迭代器

library(iterators)
ichunk <- function(n, ..., chunkSize) {
    it <- icount(n)              # FIXME: scale by chunkSize
    chunk <- seq_len(chunkSize)
    structure(list(nextElem=function() {
        (nextElem(it) - 1L) * chunkSize + chunk
    }), class=c("abstractiter", "iter"))
}
库(迭代器)
ichunk替代实现
介绍
自从这篇文章发表以来,我有机会更频繁地在R中工作,所以我提供了一个备用的BaseR实现。我再次怀疑,通过降低到C扩展级别,您可以获得更好的性能。休息后再回答原来的问题

基本R中的第一个挑战是缺少真正的
cons
(即在R级别公开)。R使用
c
进行混合cons/concat操作,但这不会创建一个链表,而是创建一个新的向量,该向量包含两个参数的元素。特别是,必须知道两个参数的长度,而惰性序列则不是这样。此外,连续的
c
操作表现出二次性能,而不是恒定时间。现在,您可以使用长度为2的“列表”(实际上是向量,而不是链表)来模拟cons单元格,但是

第二个挑战是在数据结构中强制承诺。R有一些使用隐式承诺的惰性评估语义,但这些都是二等公民。用于返回显式承诺的函数(
delay
)已被弃用,取而代之的是implicit
delayedAssign
,该函数仅针对其副作用执行--“未评估的承诺永远不应可见”。函数参数是隐式承诺,因此您可以使用它们,但是,如果不强制执行,就无法将承诺放入数据结构中

CS 101 事实证明,这两个挑战可以通过回顾计算机科学101来解决。数据结构可以通过闭包实现

cons <- function(h,t) function(x) if(x) h else t

first <- function(kons) kons(TRUE)
rest <- function(kons) kons(FALSE)  

cons“输出自然数的完整无限序列”?你有无限的时间吗?“因为Clojure是同象的,所以惰性序列是递归存储的”这句话没有任何意义。同源性在这里一点都不相关,而且“递归存储”的含义也不是100%清楚。@amalloy:数据(0 1 2 3…)和代码(iterate inc 0)作为值是等价的。所谓“递归存储”,我的意思是无限序列由一个递归公式(使用iterate)表示,该公式可用于计算完整序列。我认为您可能用一些不相关的Clojure术语抛弃了
R
用户。用一些嘲弄的例子可能会更清楚这一点;斐波那契总是一个很好的例子。无论如何,我已经尝试了一个答案,至少可以证明你在问什么。您可能会问
R
专家是否有更好的方法来完成我所做的工作。我想它最终会溢出。根据它的第一个参数的文档:
“计数:迭代器将触发的次数。如果没有指定,它将永远计数。”
。“唯一的解释是魔法。”斯科特里奇,我重写了我的问题,使意图更加清楚。感谢您对
迭代器
库的精彩引用。对于重写的问题,你认为这个库一般可以用来构造惰性序列吗?我认为@A.Webb的答案就是你想要的答案这是一个很棒的答案,@A.Webb。它工作得很好。非常感谢。该包使您能够创建Quosure,它充当“第一类承诺”——它们捕获表达式和计算上下文,但与承诺不同的是,它们在引用时会重新计算。
fibonacci <- function(a,b) cons(a, fibonacci(b, a+b))
fibs <- fibonacci(1,1)
filterz <- function(pred, s) {
  if(is.null(s)) return(NULL)
  f <- first(s)
  r <- rest(s)
  if(pred(f)) cons(f, filterz(pred, r)) else filterz(pred, r) }

take_whilez <- function(pred, s) {
   if(is.null(s) || !pred(first(s))) return(NULL)
   cons(first(s), take_whilez(pred, rest(s))) }

reduce <- function(f, init, s) {
  r <- init
  while(!is.null(s)) {
    r <- f(r, first(s))
    s <- rest(s) }
  return(r) }
reduce(`+`, 0, filterz(function(x) x %% 2 == 0, take_whilez(function(x) x < 4e6, fibs)))
# [1] 4613732
numbers <- function(x) as.LazySeq(c(x, numbers(x+1)))
nums <- numbers(1)

take(10,nums) 
#=> [1]  1  2  3  4  5  6  7  8  9 10

#Slow, but does not overflow the stack (level stack consumption)
sum(take(100000,nums))
#=> [1] 5000050000
fibonacci <- function(a,b) { 
 as.LazySeq(c(a, fibonacci(b, a+b)))}

fibs <- fibonacci(1,1)

take(10, fibs)
#=> [1]  1  1  2  3  5  8 13 21 34 55

nth(fibs, 20)
#=> [1] 6765
is.LazySeq <- function(x) inherits(x, "LazySeq")

as.LazySeq <- function(s) {
  cache <- NULL
  value <- function() {
    if (is.null(cache)) {
      cache <<- force(s)
      while (is.LazySeq(cache)) cache <<- cache()}
    cache}
  structure(value, class="LazySeq")}
first <- function(x) UseMethod("first", x)
rest <- function(x) UseMethod("rest", x)

first.default <- function(s) s[1]

rest.default <- function(s) s[-1]

first.LazySeq <- function(s) s()[[1]]

rest.LazySeq <- function(s) s()[[-1]]

nth <- function(s, n) {
  while (n > 1) {
    n <- n - 1
    s <- rest(s) }
  first(s) }

#Note: Clojure's take is also lazy, this one is "eager"
take <- function(n, s) {
  r <- NULL
  while (n > 0) {
    n <- n - 1
    r <- c(r, first(s))
    s <- rest(s) }
  r}