仮想的な無限列(7)

Zipを作りました。それからarityや型的なものをちょっぴり名前に反映。OfNarutalとか。

Call = lambda {|f, *a|
  lambda { f[f, *a] }
}

Walk = lambda {|n, xs, eachf, lastf|
  Call[
    lambda {|fs, xs, n, eachf, lastf|
      if n > 0
        y, ys = xs[]
        eachf[y, ys]
        fs[fs, ys, n - 1, eachf, lastf]
      else
        lastf[xs]
      end
    }, xs, n, eachf, lastf
  ]
}

Show = lambda {|xs|
  Walk[10, xs,
    lambda {|y, ys| print "#{y}, "},
    lambda {|ys| puts "..." }
  ][]
}

DropFrom = lambda {|xs, n|
  Walk[n, xs,
    lambda {|y, ys|},
    lambda {|ys| ys}
  ][]
}

Zip = lambda {|op, s, t|
  x, xs = s[]
  y, ys = t[]
  lambda { return op[x, y], Zip[op, xs, ys] }
}

Sequence = lambda {|s, *a|
  lambda { return a[0], s[s, *a] }
}

Add = lambda {|x, y| x + y }

OfConstant = lambda {|s, a| Sequence[s, a]}
OfNatural = lambda {|s, a| Sequence[s, a + 1]}
OfFibonacci = lambda {|s, a, b| Sequence[s, b, a + b]}
DoubleOf = lambda {|s| Zip[Add, s, s]}

One = Sequence[OfConstant, 1]
Natural = Sequence[OfNatural, 0]
NaturalPlus = DropFrom[Natural, 1]
Fibonacci = Sequence[OfFibonacci, 0, 1]
Even = DoubleOf[Natural]
Odd = Zip[Add, Even, One]

Show[One]
Show[Natural]
Show[Fibonacci]
Show[NaturalPlus]
Show[Even]
Show[Odd]

上のプログラムで、

Even = DoubleOf[Natural]

のあたりにぐっと来ませんか?
実行結果です。

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, ...
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, ...