Visruth Srimath Kandali

Infinite Lists in R

Introduction

I’ve been reading Category Theory for Programmers (highly recommend), and have been encountering Haskell a bit. I don’t know much Haskell, but I have a very basic understanding of the language, and am learning functional programming principles. In chapter 7, Milewski mentions that you can create an infinite list in Haskell very tersely:

1nats :: [Integer]
2nats = [1..] 

The first line is a type definition, and the second line declares and instantiates the list, lazily, to be all natural numbers.

I was wondering how you could do something similar in R. Haskell is very lazy, more so than R I think, and obviously the languages are built for very different things–but I was curious if it were possible nonetheless. Here’s my implementation, using a linked list. You could iterate through this as long as you’d like and each new node would be computed on demand. This isn’t really the same as the Haskell implementation, but it is enough to sate my curiosity and didn’t take too much time. I don’t think this is the best way of going about this, but it works.

 1library(S7)
 2
 3inf_list <- new_class(
 4  "inf_list",
 5  properties = list(
 6    VALUE = new_property(
 7      class_numeric,
 8      getter = function(self) self@VALUE,
 9      setter = NULL
10    ),
11    nxt = new_property(class_any,
12      getter = function(self) {
13        inf_list(self@func(self@VALUE), self@func)
14      },
15      setter = NULL
16    ),
17    func = class_function
18  ),
19  constructor = function(VALUE, func = \(x) x + 1) {
20    force(VALUE)
21    force(func)
22    new_object(S7_object(), VALUE = VALUE, func = func)
23  }
24)
25
26method(print, inf_list) <- function(x, ...) {
27  cat("Starting value: ", x@VALUE, "\n")
28  cat("Link function: ", deparse(x@func), "\n")
29  invisible(x)
30}
31
32method(`[`, inf_list) <- function(x, i, j, ...) {
33  indices <- seq_len(max(i))
34  elements <- numeric(max(i))
35  names(elements) <- indices
36
37  current <- x
38  for (k in indices) {
39    elements[k] <- current@VALUE
40    current <- current@nxt
41  }
42
43  elements[i]
44}
45
46nums <- inf_list(1)
47nums
48#> Starting value:  1 
49#> Link function:  function (x)  x + 1 

It’s clearly not as elegant as the Haskell solution. You can set an arbitrary link function through @func, which recursively defines the next value.

 1odds <- inf_list(1, \(x) x + 2)
 2odds[1:10]
 3#>  1  2  3  4  5  6  7  8  9 10 
 4#>  1  3  5  7  9 11 13 15 17 19 
 5
 6negative_evens <- inf_list(0, \(x) x - 2)
 7negative_evens[1:10]
 8#>  1   2   3   4   5   6   7   8   9  10 
 9#>  0  -2  -4  -6  -8 -10 -12 -14 -16 -18 
10
11powers_of_two <- inf_list(1, \(x) x * 2)
12powers_of_two[1:10]
13#>  1   2   3   4   5   6   7   8   9  10 
14#>  1   2   4   8  16  32  64 128 256 512 

How it Works

I’m using S7, but I will assume familiarity with S7 constructs in this post (and will post about my S7 project soon.) The actual implementation is very simple–we create a linked list with new nodes computed on demand, applying the link function to the current value. This Markovian nature is demonstrated in the getter for @nxt, which is how the list is infinite.

I wrote methods for two generics–print and [–with the former being necessary and the latter being a very nice to have. The default S7 print method would cause a stack over flow–try it! You can see that in the defined print, we don’t access @nxt, but S7’s default print method outputs all properties, which causes the infinite loop. The subsetting method is just for ease of printing, so you don’t have to do odds@nxt@nxt@nxt@nxt... and can print out the sequence neatly.

Conclusions

I’m sure this isn’t the best way of doing this, and appreciate feedback. There’s no real purpose to constructing infinite lists like this, but I always like using S7 and it was an interesting exercise–fun to write, and I always learn something! This reminded me that I need to publish my S7 work soon, too. S7 has been my go to for all OOP stuff for a while, and I’m slowly getting even more comfortable with it.