Commit | Line | Data |
---|---|---|
d45d190d SK |
1 | [![Build Status](https://travis-ci.org/ibnfirnas/hope.svg?branch=master)](https://travis-ci.org/ibnfirnas/hope) |
2 | ||
07bb8aec SK |
3 | Hope |
4 | ==== | |
a11ea326 SK |
5 | |
6 | A quest for a "standard" library with uniform, composable abstractions. | |
d2ab44d2 | 7 | |
07bb8aec SK |
8 | Originally motivated by a desire for an error monad and generic option type |
9 | operations, and stood for _Higher Order Programming in Erlang_. Soon after, I | |
10 | wished all standard containers used consistent conventions and protocols (such | |
11 | as consistent accessor names, argument positioning rules and expression of | |
12 | semantics with option and result types). | |
d2ab44d2 | 13 | |
07bb8aec SK |
14 | Here lies an experiment to see what something like that could look like. As all |
15 | proper experiments should, this one is used daily in production projects (hence | |
16 | the high-ish version number, 'cause semver). | |
d2ab44d2 | 17 | |
07bb8aec SK |
18 | |
19 | Conventions | |
20 | ----------- | |
21 | ||
22 | I entertain any forward-thinking library design ideas, but more than anything | |
23 | else, these are influenced by Jane Street's Core of the OCaml world. | |
24 | ||
25 | - A module per data type implementation | |
26 | - Name of the module is the name of the type | |
27 | - Inside the module, the type it implements is always named t(..), such as: | |
28 | `hope_foo:t()`, _not_ `hope_foo:foo()` | |
29 | - t(..) is always the first argument | |
30 | - Names of private records _may_ be short, such as: `#foo{}` or `#t{}` (Though | |
31 | I'm second-guessing this idea, since seeing `{t, ..}` in stack traces is less | |
32 | than helpful. I'm considering requiring fully-qualified names for all record | |
33 | definitions and maybe short-handing what would've been `#t{..}` as | |
34 | `-define(T, ?MODULE). -record(?T, {..}).`, which may be a bit ugly. Still | |
35 | thinking...) | |
36 | - Names of public records _must_ be fully qualified, such as: `#hope_module_record{}` | |
37 | - Names of all modules _must_ be fully qualified, such as: `hope_module` (this | |
38 | should go without saying, but just to be sure...) | |
c50166fd SK |
39 | - Keep the number of (anonymous) arguments "reasonably" low: |
40 | + up to 3 is normal | |
41 | + 4 is suspicious but may be reasonable | |
42 | + 5 is _very_ suspicious and probably unnecessary | |
43 | + more than 5 is unacceptable, so consider reducing by: | |
44 | 1. revising abstractions, or, if not practical | |
45 | 2. creating a public record specifically for the purpose of passing | |
46 | many arguents, which simulates labeled arguments. For an example see | |
47 | https://github.com/ibnfirnas/oauth1_core where I used that technique | |
48 | extensively (especially in oauth1_server.erl) | |
07bb8aec SK |
49 | |
50 | ||
51 | Abstractions | |
52 | ------------ | |
53 | ||
54 | ### Monads | |
55 | ||
56 | A class of burritos, used for sequencing operations on a particular data type. | |
d2ab44d2 SK |
57 | Defined in `hope_gen_monad`, implemented as: |
58 | ||
59 | - `hope_result`: for composition of common functions returning | |
60 | `{ok, Val} | {error, Reason}`. An alternative to exceptions, which makes the | |
61 | error conditions apparent in the spec/signature. Analogous to Haskell's | |
62 | `Data.Either a b`, Jane Street Core's (OCaml) `('a, 'b) Result.t`, Rust's | |
63 | `Result<T, E>` | |
64 | - `hope_option`: for expressing and composing the intention that the value may | |
65 | or may not be available. An alternative to the common `undefined` (which is | |
66 | equivalent to the dreaded `null`). Analogous to ML's (SML, OCaml, etc) | |
67 | `'a Option.t`, Rust's `Option<T>` and Haskell's `Data.Maybe a` [1]. | |
68 | ||
69 | ||
07bb8aec | 70 | ### Containers |
d2ab44d2 | 71 | |
07bb8aec SK |
72 | A class of abstract data types to which we have exclusive access and can put |
73 | things in and take them out. See issue #9 | |
74 | ||
75 | - Operations on all abstract types of containers _should_ share a common lexicon | |
76 | - Concrete implementations of an abstract data type _must_ be swapable | |
77 | ||
78 | #### Dictionary | |
d2ab44d2 SK |
79 | |
80 | Defined in `hope_gen_dictionary`, implemented as: | |
81 | ||
82 | - `hope_kv_list`. Equivalent to orddict/proplist. Operations implemented with | |
83 | BIFs from `lists` module, where possible | |
84 | ||
07bb8aec SK |
85 | TBD: |
86 | - `hope_hash_tbl`. API around stdlib's `dict` | |
87 | - `hope_gb_dict`. API around stdlib's `gb_trees` | |
88 | ||
89 | #### Set | |
90 | ||
91 | TBD: | |
92 | - `hope_hash_set`. API around stdlib's `sets` | |
93 | - `hope_gb_set`. API around stdlib's `gb_sets` | |
94 | ||
95 | #### Queue | |
96 | ||
97 | TBD | |
98 | ||
99 | Should include both FIFO (queue) and LIFO (stack), so that user can swap if a | |
100 | different order is desired. | |
101 | ||
102 | Should we attempt to include priority queues or make them a separate abstract | |
103 | type? | |
104 | ||
105 | #### Sequence | |
106 | ||
107 | TBD | |
108 | ||
109 | Not yet defined and only partially implemented as: | |
110 | ||
111 | - `hope_list` | |
112 | ||
113 | ||
114 | ### Resources | |
115 | ||
116 | A class of abstract systems to which we share access with an unknown number of | |
117 | users and can make requests to perform operations which may not get done for | |
118 | any number of reasons. | |
119 | ||
120 | #### Storage | |
121 | ||
122 | TBD | |
123 | ||
124 | See issue #11 | |
125 | ||
d2ab44d2 SK |
126 | |
127 | [1]: http://en.wikipedia.org/wiki/Option_type |