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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
# Algebrick
Typed structs on steroids based on algebraic types and pattern matching seamlessly integrating with standard Ruby features.
- Documentation: <http://blog.pitr.ch/algebrick>
- Source: <https://github.com/pitr-ch/algebrick>
- Blog: <http://blog.pitr.ch/blog/categories/algebrick/>
## Quick example
{include:file:doc/quick_example.out.rb}
## Algebraic types
Algebraic types are:
- products with a given number of fields,
- or a kind of composite type, i.e. a type formed by combining other types.
In Haskell algebraic type looks like this:
data Tree = Empty
| Leaf Int
| Node Tree Tree
depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)
depth (Node Empty (Leaf 5)) -- => 2
This snippet defines type `Tree` which has 3 possible values:
- `Empty`
- `Leaf` with and extra value of type `Int`
- `Node` with two values of type `Tree`
and function `depth` to calculate depth of a tree which is called on the last line and evaluates to `2`.
Same `Tree` type and `depth` method can be also defined with this gem as it was shown in {file:README_FULL.md#quick-example Quick Example}.
### Algebrick implementation
Algebrick distinguishes 4 kinds of algebraic types:
1. **Atom** - type that has only one value, e.g. `Empty`.
2. **Product** - type that has a set number of fields with given type, e.g. `Leaf(Integer)`
3. **Variant** - type that is one of the set variants, e.g. `Tree(Empty | Leaf(Integer) | Node(Tree, Tree)`, meaning that values `Empty`, `Leaf[1]`, `Node[Empty, Empry]` have all type `Tree`.
4. **ProductVariant** - will be created when a recursive type like `List(Empty | List(Integer, List))` is defined. `List` has two variants: `Empty` and itself. Simultaneously it has fields as a product type.
Atom type is implemented with {Algebrick::Atom} and the rest is implemented with {Algebrick::ProductVariant} which behaves differently based on what is set: fields, variants, or both.
More information can be found at <https://en.wikipedia.org/wiki/Algebraic_data_type>.
## Documentation
### Type definition
{include:file:doc/type_def.out.rb}
### Value creation
{include:file:doc/values.out.rb}
### Behaviour extending
{include:file:doc/extending_behavior.out.rb}
### Pattern matching
Pattern matching is implemented with helper objects defined in `ALgebrick::Matchers`.
They use standard `#===` method to match against values.
{include:file:doc/pattern_matching.out.rb}
### Parametrized types
{include:file:doc/parametrized.out.rb}
## What is it good for?
### Defining data structures
<!-- {include:file:doc/data.out.rb} -->
- Simple data structures like trees
- Whenever you find yourself to pass around too many fragile Hash-Array structures
_Examples are coming shortly._
### Serialization
Algebraic types also play nice with JSON serialization and de-serialization making it ideal for defining message-based cross-process communication.
{include:file:doc/json.out.rb}
### Message matching in Actor pattern
Just a small snippet how it can be used in Actor model world.
{include:file:doc/actor.rb}
<!--
### Null Object Pattern
see {http://en.wikipedia.org/wiki/Null_Object_pattern#Ruby}.
{include:file:doc/null.out.rb}
This has advantage over a classical approach that the methods are defined
on one place, no need to track methods in two separate classes `User` and `NullUser`.
-->
|