safedata gem / library - safe (algebraic) union data types with (enumerated) variants
- home :: github.com/s6ruby/safedata
- bugs :: github.com/s6ruby/safedata/issues
- gem :: rubygems.org/gems/safedata
- rdoc :: rubydoc.info/gems/safedata
Union.new( :Message, :Quit,
:Move, {x:0, y:0},
:Write, {text:''},
:ChangeColor, {r:0, g:0, b:0} )
# -or-
data :Message, [:Quit,
:Move, {x:0, y:0},
:Write, {text:''},
:ChangeColor, {r:0, g:0, b:0}]
# -or-
data :Message, :Quit,
:Move, {x:0, y:0},
:Write, {text:''},
:ChangeColor, {r:0, g:0, b:0}
msg = Quit()
# -or-
msg = Move(2,3)
# -or-
msg = Write("Hello")
# -or-
msg = ChangeColor(0, 160, 255)
Message.match msg,
Quit: ->() { puts "Quit has no data" },
Move: ->(x,y) { puts "Move in the x: #{x} / y: #{y} direction" },
Write: ->(text) { puts "Text message: #{text}" },
ChangeColor: ->(r,g,b) { puts "Change color to red: #{r} / green: #{g} / blue: #{b}" }
...
data :Shape, :Circle, { radius: 0 },
:Square, { side: 0 },
:Rectangle, { height: 0, width: 0 }
shape = Circle(15)
# -or-
shape = Square(10)
# -or-
shape = Rectangle(5, 10)
def Shape.area( shape )
match shape,
Circle: ->(radius) { Math.PI * radius * radius },
Square: ->(s) { s * s }
Rectangle: ->(h, w) { h * w }
end
circle = Circle(15)
puts "Area of circle that has radius #{circle.radius}: #{Shape.area(circle)}"
square = Square(10)
puts "Area of square that has side #{square.side}: #{Shape.area(square)}"
rect = Rectangle(5, 10)
puts "Area of rectangle that has height #{rect.height} and width #{rect.width} is #{Shape.area(rect)}"
data :Tree, :Tip,
:Node, { value: 0, left: Tip(), right: Tip() }
# -or-
data :Tree, :Tip,
:Node, [:value, :left, :right]
tree = Node(0, Node(1, Node(2, Tip(), Tip()),
Node(3, Tip(), Tip())),
Node(4, Tip(), Tip()))
def Tree.sum( tree )
match tree,
Tip: ->() { 0 }
Node: ->(value, left, right) { value + sum(left) + sum(right) }
end
puts Tree.sum( tree ) #=> 10
...
data :Expression, :Number, { n: 0 },
:Add, { x: 0, y: 0 },
:Multiply { x: 0, y: 0 },
:Variable { id: '' }
def Expression.evaluate( env, exp )
match exp,
Number: ->(n) { n },
Add: ->(x, y) { evaluate( env, x ) + evaluate( evn, y ),
Multiply: ->(x, y) { evaluate( env, x ) * evaluate( env, y ),
Variable: ->(id) { env[id] }
end
env = {"a" => 1,
"b" => 2,
"c" => 3}
## Create an expression tree that represents
## the expression: a + 2 * b.
exp = Add( Variable("a"),
Multiply( Number(2), Variable("b"))
## Evaluate the expression a + 2 * b, given the
## table of values for the variables.
result = Expression.evaluate( env, exp ) #=> 5
# When this code is executed, the value of result is 5.
## Result Data Types
data :Result, :Ok { msg: '' }, # rust-like "short" form
:Err { msg: ''}
data :Result, :Success { msg: '' }, # haskell-like "long" form
:Failure { msg: '' }
## Optional / Maybe Data Types
data :Optional, :Some { value: T } # note: T is a TypeVar
:None
data :Maybe, :Just { value: T }
:Nothing
...
Yes, yes, yes. The Enum
class from the enums library gets auto-required.
Use like:
Enum.new( :Color, :red, :green, :blue )
# -or-
enum :Color, :red, :green, :blue
# -or-
enum :Color, [:red, :green, :blue]
See the enums library documentation for more »
Safe Data Structures (Array, Hash, Struct) - Say goodbye to null / nil (and maybe) and the Billion-Dollar mistake. Say hello to zero and the Billon-Dollar fix.
The safedata
scripts are dedicated to the public domain.
Use it as you please with no restrictions whatsoever.
Send them along to the wwwmake forum. Thanks!