1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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 61 62
|
Maybe = Algebrick.type do
variants None = atom,
Some = type { fields Object }
end # => Maybe(None | Some)
# Types can be extended with usual syntax for modules and using Ruby supports module reopening.
module Maybe
def maybe(&block)
case self
when None
when Some
block.call value
end
end
end
# #maybe method is defined on both values (None, Some) of Maybe.
None.maybe { |_| raise 'never ever happens' } # => nil
# Block is called with the value.
Some[1].maybe { |v| v*2 } # => 2
# It also works as expected when modules like Comparable are included.
Season = Algebrick.type do
variants Spring = atom,
Summer = atom,
Autumn = atom,
Winter = atom
end # => Season(Spring | Summer | Autumn | Winter)
module Season
include Comparable
ORDER = Season.variants.each_with_index.each_with_object({}) { |(season, i), h| h[season] = i }
def <=>(other)
Type! other, Season
ORDER[self] <=> ORDER[other]
end
end
Quarter = Algebrick.type do
fields! year: Integer, season: Season
end # => Quarter(year: Integer, season: Season)
module Quarter
include Comparable
def <=>(other)
Type! other, Quarter
[year, season] <=> [other.year, other.season]
end
end
# Now Quarters and Seasons can be compared as expected.
[Winter, Summer, Spring, Autumn].sort # => [Spring, Summer, Autumn, Winter]
Quarter[2013, Spring] < Quarter[2013, Summer] # => true
Quarter[2014, Spring] > Quarter[2013, Summer] # => true
Quarter[2014, Spring] == Quarter[2014, Spring] # => true
[Quarter[2013, Spring], Quarter[2013, Summer], Quarter[2014, Spring]].sort
# => [Quarter[year: 2013, season: Spring], Quarter[year: 2013, season: Summer], Quarter[year: 2014, season: Spring]]
|