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



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.


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


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



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)


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



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



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



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



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

def unsafe_content; self.unsafe_data.first; end