/ apps / beamai_core / src / data / beamai_result.erl
beamai_result.erl
  1  %%%-------------------------------------------------------------------
  2  %%% @doc 错误处理的 Result 单子
  3  %%%
  4  %%% 提供用于链式组合可能失败的计算的单子操作。
  5  %%% 所有函数都使用 {ok, Value} | {error, Reason} 元组格式。
  6  %%%
  7  %%% @end
  8  %%%-------------------------------------------------------------------
  9  -module(beamai_result).
 10  
 11  -export([ok/1, error/1, is_ok/1, is_error/1]).
 12  -export([map/2, flat_map/2, bind/2]).
 13  -export([pipe/2, pipe_while/2]).
 14  -export([unwrap/1, unwrap_or/2, unwrap_error/1]).
 15  -export([from_boolean/2, from_maybe/2]).
 16  -export([collect/1, partition/1]).
 17  -export([tap/2, tap_error/2]).
 18  
 19  -type result(T) :: {ok, T} | {error, term()}.
 20  -type result(T, E) :: {ok, T} | {error, E}.
 21  
 22  -export_type([result/1, result/2]).
 23  
 24  %%====================================================================
 25  %% 构造函数
 26  %%====================================================================
 27  
 28  -spec ok(T) -> {ok, T}.
 29  ok(Value) -> {ok, Value}.
 30  
 31  -spec error(E) -> {error, E}.
 32  error(Reason) -> {error, Reason}.
 33  
 34  %%====================================================================
 35  %% 谓词函数
 36  %%====================================================================
 37  
 38  -spec is_ok(result(term())) -> boolean().
 39  is_ok({ok, _}) -> true;
 40  is_ok(_) -> false.
 41  
 42  -spec is_error(result(term())) -> boolean().
 43  is_error({error, _}) -> true;
 44  is_error(_) -> false.
 45  
 46  %%====================================================================
 47  %% 转换函数
 48  %%====================================================================
 49  
 50  %% @doc 如果是 ok 则应用函数,否则透传错误
 51  -spec map(result(A), fun((A) -> B)) -> result(B).
 52  map({ok, Value}, Fun) -> {ok, Fun(Value)};
 53  map({error, _} = E, _Fun) -> E.
 54  
 55  %% @doc 应用返回 result 的函数,并展平结果
 56  -spec flat_map(result(A), fun((A) -> result(B))) -> result(B).
 57  flat_map({ok, Value}, Fun) -> Fun(Value);
 58  flat_map({error, _} = E, _Fun) -> E.
 59  
 60  %% @doc flat_map 的别名(Haskell 命名风格)
 61  -spec bind(result(A), fun((A) -> result(B))) -> result(B).
 62  bind(Result, Fun) -> flat_map(Result, Fun).
 63  
 64  %%====================================================================
 65  %% 管道操作
 66  %%====================================================================
 67  
 68  %% @doc 将值通过函数列表传递,遇到第一个错误时停止
 69  -spec pipe(A, [fun((A) -> result(B)) | fun((A) -> B)]) -> result(B).
 70  pipe(Value, []) ->
 71      {ok, Value};
 72  pipe(Value, [Fun | Rest]) ->
 73      case apply_fun(Fun, Value) of
 74          {ok, NewValue} -> pipe(NewValue, Rest);
 75          {error, _} = E -> E
 76      end.
 77  
 78  %% @doc 当谓词返回 true 时继续传递
 79  -spec pipe_while(A, [{fun((A) -> boolean()), fun((A) -> result(A))}]) -> result(A).
 80  pipe_while(Value, []) ->
 81      {ok, Value};
 82  pipe_while(Value, [{Pred, Fun} | Rest]) ->
 83      case Pred(Value) of
 84          true ->
 85              case apply_fun(Fun, Value) of
 86                  {ok, NewValue} -> pipe_while(NewValue, Rest);
 87                  {error, _} = E -> E
 88              end;
 89          false ->
 90              {ok, Value}
 91      end.
 92  
 93  %%====================================================================
 94  %% 解包操作
 95  %%====================================================================
 96  
 97  %% @doc 获取值,如果是错误则抛出异常
 98  -spec unwrap(result(T)) -> T.
 99  unwrap({ok, Value}) -> Value;
100  unwrap({error, Reason}) -> erlang:error({unwrap_error, Reason}).
101  
102  %% @doc 获取值,如果是错误则返回默认值
103  -spec unwrap_or(result(T), T) -> T.
104  unwrap_or({ok, Value}, _Default) -> Value;
105  unwrap_or({error, _}, Default) -> Default.
106  
107  %% @doc 获取错误原因
108  -spec unwrap_error(result(term(), E)) -> E.
109  unwrap_error({error, Reason}) -> Reason;
110  unwrap_error({ok, _}) -> erlang:error(not_an_error).
111  
112  %%====================================================================
113  %% 类型转换
114  %%====================================================================
115  
116  %% @doc 将布尔值转换为 result
117  -spec from_boolean(boolean(), E) -> result(ok, E).
118  from_boolean(true, _Error) -> {ok, ok};
119  from_boolean(false, Error) -> {error, Error}.
120  
121  %% @doc 将可能为 undefined 的值转换为 result
122  -spec from_maybe(T | undefined, E) -> result(T, E).
123  from_maybe(undefined, Error) -> {error, Error};
124  from_maybe(Value, _Error) -> {ok, Value}.
125  
126  %%====================================================================
127  %% 集合操作
128  %%====================================================================
129  
130  %% @doc 将 result 列表收集为列表的 result
131  -spec collect([result(T)]) -> result([T]).
132  collect(Results) ->
133      collect(Results, []).
134  
135  collect([], Acc) ->
136      {ok, lists:reverse(Acc)};
137  collect([{ok, V} | Rest], Acc) ->
138      collect(Rest, [V | Acc]);
139  collect([{error, _} = E | _], _Acc) ->
140      E.
141  
142  %% @doc 将结果列表分区为成功和错误两部分
143  -spec partition([result(T, E)]) -> {[T], [E]}.
144  partition(Results) ->
145      partition(Results, [], []).
146  
147  partition([], Oks, Errors) ->
148      {lists:reverse(Oks), lists:reverse(Errors)};
149  partition([{ok, V} | Rest], Oks, Errors) ->
150      partition(Rest, [V | Oks], Errors);
151  partition([{error, E} | Rest], Oks, Errors) ->
152      partition(Rest, Oks, [E | Errors]).
153  
154  %%====================================================================
155  %% 副作用操作
156  %%====================================================================
157  
158  %% @doc 对 ok 值执行副作用函数,返回原始结果
159  -spec tap(result(T), fun((T) -> term())) -> result(T).
160  tap({ok, Value} = R, Fun) ->
161      Fun(Value),
162      R;
163  tap({error, _} = E, _Fun) ->
164      E.
165  
166  %% @doc 对错误执行副作用函数,返回原始结果
167  -spec tap_error(result(T, E), fun((E) -> term())) -> result(T, E).
168  tap_error({error, Reason} = E, Fun) ->
169      Fun(Reason),
170      E;
171  tap_error({ok, _} = R, _Fun) ->
172      R.
173  
174  %%====================================================================
175  %% 内部函数
176  %%====================================================================
177  
178  apply_fun(Fun, Value) ->
179      case Fun(Value) of
180          {ok, _} = R -> R;
181          {error, _} = E -> E;
182          Other -> {ok, Other}
183      end.