Class: Obfusk::List

Inherits:
Object
  • Object
show all
Includes:
ADT, Monad, MonadPlus
Defined in:
lib/obfusk/list.rb

Overview

Lazy List

Defined Under Namespace

Classes: Cons

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MonadPlus

included, #plus

Methods included from Monad

#>>, included

Methods included from ADT

#<=>, #==, #__adt_ctor__, #__adt_ctor_keys__, #__adt_ctor_name__, #__adt_data__, #clone, #eql?, included, #initialize, #inspect, #match

Class Method Details

.mreturn(x) ⇒ Object

-- Monad --



236
237
238
# File 'lib/obfusk/list.rb', line 236

def self.mreturn(x)
  Cons x, Nil()
end

Instance Method Details

#[](i) ⇒ Object

element at index

Raises:

  • (ArgumentError)


101
102
103
104
105
# File 'lib/obfusk/list.rb', line 101

def [](i)
  raise ArgumentError, 'negative index' if i < 0
  j = 0; each { |x| return x if i == j; j += 1 }
  raise ArgumentError, 'index too large'
end

#_Object

pretend to be lazy (so we don't need Obfusk.eager)



72
73
74
# File 'lib/obfusk/list.rb', line 72

def _
  self
end

#_compare_data(rhs) ⇒ Object



50
51
52
53
# File 'lib/obfusk/list.rb', line 50

def _compare_data(rhs)
   match  Nil:  -> (_) { 0 },
          Cons: -> (_) { [head,tail] <=> [rhs.head,rhs.tail] }
end

#_eq_data(rhs) ⇒ Object



45
46
47
48
# File 'lib/obfusk/list.rb', line 45

def _eq_data(rhs)
   match  Nil:  -> (_) { true },
          Cons: -> (_) { [head,tail] == [rhs.head,rhs.tail] }
end

#append(ys) ⇒ Object

append two lists



127
128
129
130
# File 'lib/obfusk/list.rb', line 127

def append(ys)
  match Nil:  -> (_) { ys._ },
        Cons: -> (_) { Cons(head) { tail.append ys } }
end

#chain(m, *a, &b) ⇒ Object

pretend to be lazy (see _)



77
78
79
# File 'lib/obfusk/list.rb', line 77

def chain(m,*a,&b)
  ::Obfusk.lazy { public_send(m,*a,&b) }
end

#concatObject

concatenate a list of lists



164
165
166
# File 'lib/obfusk/list.rb', line 164

def concat
  foldr(Nil()) { |x,ys| x.append ys }
end

#each(&b) ⇒ Object

--



57
58
59
60
# File 'lib/obfusk/list.rb', line 57

def each(&b)
  return enum_for :each unless b
  xs = self; while xs != Nil() do b[xs.head]; xs = xs.tail end
end

#filter(p = nil, &b) ⇒ Object

the list of those elements that satisfy the predicate



84
85
86
87
88
89
# File 'lib/obfusk/list.rb', line 84

def filter(p = nil, &b)
  g = p || b
  match Nil:  -> (_) { Nil() },
        Cons: -> (_) { g[head] ? Cons(head) { tail.filter(g) }
                               :              tail.filter(g) }
end

#foldr(z, f = nil, &b) ⇒ Object

foldr, applied to a binary operator, a starting value (typically the right-identity of the operator), and a list, reduces the list using the binary operator, from right to left:

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

NB: because ruby is not lazy, the secons argument of the binary operator is lazy and must be treated as such.



149
150
151
152
153
# File 'lib/obfusk/list.rb', line 149

def foldr(z, f = nil, &b)
  g = f || b
  match Nil:  -> (_) { z },
        Cons: -> (_) { g[head, tail.chain(:foldr, z, g)] }
end

#lengthObject

length



108
109
110
# File 'lib/obfusk/list.rb', line 108

def length
  n = 0; each { n += 1 }; n
end

#map(f = nil, &b) ⇒ Object

the list obtained by applying a function (or block) to each element



92
93
94
95
96
# File 'lib/obfusk/list.rb', line 92

def map(f = nil, &b)
  g = f || b
  match Nil:  -> (_) { Nil() },
        Cons: -> (_) { Cons(g[head]) { tail.map g } }
end

#nullObject Also known as: null?, empty?

empty?



113
114
115
# File 'lib/obfusk/list.rb', line 113

def null
  match Nil: -> (_) { true }, Cons: -> (_) { false }
end

#take(n) ⇒ Object

the prefix of length n (or the list itself if n > length)



192
193
194
195
196
# File 'lib/obfusk/list.rb', line 192

def take(n)
  return Nil() if n <= 0
  match Nil:  -> (_) { Nil() },
        Cons: -> (_) { Cons(head) { tail.take(n - 1) } }
end

#to_aObject



67
68
69
# File 'lib/obfusk/list.rb', line 67

def to_a
  each.to_a
end

#to_sObject



62
63
64
65
# File 'lib/obfusk/list.rb', line 62

def to_s
  *xs, x = self.class.name.split '::'; n = xs*'::' + '.' + x
  self == Nil() ? "<##{n}>" : "<##{n}(#{head},...)>"
end

#zipWith(ys, f = nil, &b) ⇒ Object

combine parallel elements of two lists using a binary operator



217
218
219
220
221
# File 'lib/obfusk/list.rb', line 217

def zipWith(ys, f = nil, &b)
  g = f || b
  self == Nil() || ys._ == Nil() ? Nil() :
    Cons(g[head, ys._.head]) { tail.zipWith(ys._.tail, g) }
end