#!/usr/bin/ruby -w # TODO create a LazyEvaluationArray to handle infinite lists class Array def head self[0] end # last() is already defined def tail self[1..-1] end def init self[0..-2] end def null size == 0 end # TODO ++, map, filter, concat, length, !! # TODO unified syntax for foldl and foldl1 (default params?) # TODO passing a block to fold (see reduce) # foldl (+) 0 [a,b,c] => 0 + (a + (b + c)) def foldl op, val each{ |elem| val = val.send(op, elem) } val end # foldl1 (+) [a,b,c] => a + (b + c) def foldl1 op val = head tail.each{ |elem| val = val.send(op, elem) } val end # scanl (+) 0 [a,b,c] => [0, a + 0, b + (a + 0), c + (b + (a + 0))] # scanl (+) 0 [1..10] => [0,1,3,6,10,15,21,28,36,45,55] def scanl op, val res = [val] each{ |elem| res << res.last.send(op, elem) } res end def scanl1 op res = [head] tail.each{ |elem| res << res.last.send(op, elem) } res end # foldr (+) 0 [a,b,c] => a + (b + (c + 0)) def foldr op, val reverse.foldl op, val # XXX is this correct??? end # TODO scanr[1] def iterate fn, n # fn is a proc # XXX problem: infinite list => closures that keep yielding results raise "inf" res = [n] loop { #res << apply(&fn, res.last) } res end # expressed otherwise in Ruby: # repeat # replicate def cycle raise "inf" end def take n self[0..(n-1)] end def drop n self[n..-1] end def split_at n [take(n), drop(n)] end def take_while res = [] each{ |elem| break unless yield(elem) res << elem } res end def drop_while res = [] each{ |elem| next if yield(elem) res << elem } res end def span # in terms of take_while and drop_while??? end def break end # TODO span break lines words unwords unlines reverse and or any all elem # not_elem lookup sum product maximum minimum zip zip3 unzip unzip3 def zip other res = [] each_index{ |i| res << [self[i], other[i]] } res end end a = (1..10).to_a p a.head #=> 1 p a.last #=> 10 p a.tail #=> [2, 3, 4, 5, 6, 7, 8, 9, 10] p a.init #=> [1, 2, 3, 4, 5, 6, 7, 8, 9] p a.foldl(:+, 0) #=> 55 p a.foldl(:*, 1) #=> 3628800 p a.foldl1(:+) #=> 55 p a.foldl1(:*) #=> 3628800 p a.scanl(:+, 0) #=> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55] p a.scanl1(:+) #=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] p a.foldr(:+, 0) p a.take(4) #=> [1, 2, 3, 4] p a.drop(4) #=> [5, 6, 7, 8, 9, 10] p a.split_at(7) #=> [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10]] p a.take_while{|i| i < 5} #=> [1, 2, 3, 4] p a.drop_while{|i| i < 5} #=> [5, 6, 7, 8, 9, 10] p a.zip(a.reverse) # FIXME "{take,split_at} 0" gives weird stuff # take 0 must give [] see hugs # split_at 0 must give [[],[1,2,3,4,5,6,7,8,9,10]] # 11.times{|i| p a.take(i) } # 11.times{|i| p a.split_at(i) }