Class: Funkr::Types::Maybe

Inherits:
ADT show all
Extended by:
Applicative::ClassMethods, Monad::ClassMethods, Monoid::ClassMethods
Includes:
Alternative, Applicative, Functor, Categories, Monad, Monoid
Defined in:
lib/funkr/types/maybe.rb

Overview

Algebraïc Data Type representing the possibility of a missing value : nothing. It cleanly replace the ‘nil’ paradigm often found in ruby code, and often leading to bugs. The Maybe type belongs to multiple categories, making it extremly expressive to use (functor, applicative, alternative, monad, monoid … !).

You will get maximum performance and maximum expressiveness if you can use provided high level functions (map, apply, or_else, …) instead of pattern-matching yourself.

Constant Summary

Constants inherited from ADT

ADT::MATCHER

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ADT

adt, #initialize, #match, matcher, #to_s, #unsafe_const, #unsafe_data

Constructor Details

This class inherits a constructor from Funkr::ADT

Class Method Details

.box(value) ⇒ Object

Box nil as nothing, and the rest as just x

[View source]

137
138
139
140
# File 'lib/funkr/types/maybe.rb', line 137

def self.box(value)
  if value.nil? then self.nothing
  else self.just(value) end
end

.concat(maybes) ⇒ Object

concat
Maybe a

-> [a]

The Maybe.concat function takes a list of Maybes and returns
a list of all the Just values.
[View source]

145
146
147
148
149
150
151
152
# File 'lib/funkr/types/maybe.rb', line 145

def self.concat(maybes)
  maybes.inject([]) do |a, e|
    e.match do |on|
      on.just{|v| a + [v]}
      on.nothing{ a }
    end
  end
end

Instance Method Details

#apply(to) ⇒ Object

see applicative apply

Maybe can be made an applicative functor, for example :

f = Maybe.curry_lift_proc{|x,y| x + y}
a = Maybe.just(3)
b = Maybe.just(4)
c = Maybe.nothing
f.apply(a).apply(b) => Just 7
f.apply(a).apply(c) => Nothing
[View source]

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/funkr/types/maybe.rb', line 54

def apply(to)
  # This implementation isn't safe but is a bit faster than the
  # safe one. A safe implementation would be as follow :
  #   self.match do |f_on|
  #     f_on.just do |f|
  #       to.match do |t_on|
  #         t_on.just {|t| self.class.unit(f.call(t)) }
  #         t_on.nothing { to }
  #       end
  #     end
  #     f_on.nothing { self }
  #   end
  if self.just? and to.just? then
    self.class.unit(self.unsafe_content.call(to.unsafe_content))
  else self.class.nothing end
end

#bind(&block) ⇒ Object

[View source]

103
104
105
106
107
108
109
110
111
112
# File 'lib/funkr/types/maybe.rb', line 103

def bind(&block)
  # This implementation isn't safe but is a bit faster than the
  # safe one. A safe implementation would be as follow :
  #   self.match do |on|
  #     on.just {|v| yield(v)}
  #     on.nothing {self}
  #   end
  if self.just? then yield(self.unsafe_content)
  else self end
end

#map(&block) ⇒ Object

see functor map

Maybe.nothing.map{|x| something(x)} # => nothing
Maybe.just(x).map{|x| something(x)} # => just something(x)
[View source]

31
32
33
34
35
36
37
38
39
40
# File 'lib/funkr/types/maybe.rb', line 31

def map(&block)
  # This implementation isn't safe but is a bit faster than the
  # safe one. A safe implementation would be as follow :
  #   self.match do |on|
  #     on.just {|v| self.class.just(yield(v))}
  #     on.nothing { self }
  #   end
  if self.just? then self.class.just(yield(unsafe_content))
  else self end
end

#mplus(m_y) ⇒ Object

[View source]

86
87
88
89
90
91
92
93
94
95
96
# File 'lib/funkr/types/maybe.rb', line 86

def mplus(m_y)
  self.match do |x_on|
    x_on.nothing { m_y }
    x_on.just do |x|
      m_y.match do |y_on|
        y_on.nothing { self }
        y_on.just {|y| self.class.just(x.mplus(y))}
      end
    end
  end
end

#or_else(&block) ⇒ Object

[View source]

74
75
76
77
78
79
# File 'lib/funkr/types/maybe.rb', line 74

def or_else(&block)
  self.match do |on|
    on.just {|v| self}
    on.nothing { yield }
  end
end

#unbox(default = nil) ⇒ Object

Unbox a maybe value. You must provide a default in case of nothing. This method is not as safe as the others, as it will escape the content from the Maybe type safety.

Maybe.just(5).unbox(:foobar) # => 5 Maybe.nothing.unbox(:foobar) # => :foobar

[View source]

120
121
122
123
124
125
# File 'lib/funkr/types/maybe.rb', line 120

def unbox(default=nil)
  self.match do |on|
    on.just {|v| v }
    on.nothing { default }
  end
end

#unsafe_contentObject

unsafe access to content, for performance purpose only

[View source]

134
# File 'lib/funkr/types/maybe.rb', line 134

def unsafe_content; self.unsafe_data.first; end