Class: Proc

Inherits:
Object show all
Defined in:
lib/raskell/proc.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#is_tupledObject

Returns the value of attribute is_tupled.



4
5
6
# File 'lib/raskell/proc.rb', line 4

def is_tupled
  @is_tupled
end

Class Method Details

.pure(arg) ⇒ Object



10
11
12
# File 'lib/raskell/proc.rb', line 10

def self.pure(arg)
  ->(x) { arg }
end

Instance Method Details

#*(lamb) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/raskell/proc.rb', line 62

def *(lamb)
  # You, then me
  # like function composition
  if lamb.class != Proc
    lamb | self
  else
    ->(x) { self.( lamb.( x ) ) }
  end
end

#**(lamb) ⇒ Object

<*> from Control.Applicative



14
15
16
# File 'lib/raskell/proc.rb', line 14

def **(lamb) ## <*> from Control.Applicative
  ->(x) { self.(x, lamb.(x)) }
end

#+(lamb) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/raskell/proc.rb', line 82

def +(lamb)
  ## later need to check if they have the same arity, once I've fixed the arity function to handle nesting lambdas
  this = self
  
  result = ->(xs) { 
    if lamb.is_tupled && this.is_tupled 
      this.(xs) + lamb.(xs)
    elsif lamb.is_tupled
      [this.(xs)] + lamb.(xs)
    elsif this.is_tupled
      this.(xs) + [lamb.(xs)]
    else
      [this.(xs),lamb.(xs)] 
    end
  }
  result.is_tupled = true
  result
end

#<<(val) ⇒ Object



101
102
103
104
# File 'lib/raskell/proc.rb', line 101

def <<(val)
  # feed data from the right
  self.(val.())
end

#>>(lamb) ⇒ Object



106
107
108
109
# File 'lib/raskell/proc.rb', line 106

def >>(lamb)
  # feed data from the left, assuming I am a wrapped Object of some sort
  lamb.(self.())
end

#[](*args) ⇒ Object

Just a friendly reminder .() is shorthand for .call() and self.arity is the number of arguments this Proc takes



32
33
34
# File 'lib/raskell/proc.rb', line 32

def [](*args)
  call(*args)
end

#^(lamb) ⇒ Object

<**> from Control.Applicative



20
21
22
# File 'lib/raskell/proc.rb', line 20

def ^(lamb)
  ->(x) { lamb.(self.(x), x) }
end

#bind(lamb) ⇒ Object



24
25
26
# File 'lib/raskell/proc.rb', line 24

def bind(lamb)
  ->(x) { lamb.(self.(x), x)}
end

#call(*args) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/raskell/proc.rb', line 36

def call(*args)
  args_to_consume = args.take(self.arity < 0 ? self.arity.abs : self.arity) ## the < 1 here is because ruby stores *args as an arity of one more than the required args, in a negative number
  remaining_args = args.drop(self.arity < 0 ? self.arity.abs : self.arity)
  
  if !args_to_consume.respond_to?(:length) ## then we're dealing with a *args-only lambda, and we have enough args. just apply them all
      result = self.standard_ruby_call(*args)
  elsif self.arity == 0
    result = self.standard_ruby_call()
  elsif args.length == 0
    #interpret application with no arguments on a non-zero-arity function as a no-op
    return self
  elsif (self.arity < 0 && args.length >= self.arity.abs - 1) ## then we're dealing with a *args-based lambda, and we have enough args. just apply them all
    result = self.standard_ruby_call(*args)
  elsif args_to_consume.length < self.arity 
    #if you have too few arguments, return a lambda asking for more before attempting to re-apply
    return ->(x) { self.call( *( args + [x] ) ) }
  elsif self.arity < 0
    return ->(*xs) { self.call( *( args + xs.deep_clone ) ) }
  else
    #otherwise, apply the arguments
    result = self.standard_ruby_call(*args_to_consume)
  end
  # if the result is a proc, make sure to unwrap further by recursively calling with any remaining arguments
  (result.kind_of?(Proc) && remaining_args.length > 0) || (result.kind_of?(Proc) && remaining_args.length == 0 && result.respond_to?(:arity) && result.arity == 0) ? result.call(*remaining_args) : result
end

#fmap(lamb) ⇒ Object



6
7
8
# File 'lib/raskell/proc.rb', line 6

def fmap(lamb)
  self * lamb
end

#standard_ruby_callObject



3
# File 'lib/raskell/proc.rb', line 3

alias_method :standard_ruby_call, :call

#|(lamb) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/raskell/proc.rb', line 72

def |(lamb)
  # Me, then you
  # like unix pipes
  if lamb.class != Proc
    lamb * self
  else
    ->(x) { lamb.( self.( x ) ) }
  end
end