Define explicit map_ok as implementation of map
[hope.git] / src / hope_result.erl
CommitLineData
6731749b
SK
1-module(hope_result).
2
b69220d7 3-behavior(hope_gen_monad).
2a40de4f 4
3b156801
SK
5-export_type(
6 [ t/2
64617423
SK
7 , exn_class/0
8 , exn_value/1
3b156801 9 ]).
6731749b 10
3b156801 11-export(
4af0774b 12 [ return/1
fd4da0e0
SK
13 , map/2 % map/2 is alias for map_ok/2
14 , map_ok/2
a80ca0b2
SK
15 , map_error/2
16 , tag_error/2
4af0774b 17 , pipe/2
8fc25ea1 18 , lift_exn/1
b79afea0 19 , lift_exn/2
64617423 20 , lift_map_exn/3
3b156801 21 ]).
6731749b 22
64617423
SK
23-type exn_class() ::
24 error
25 | exit
26 | throw
27 .
28
29-type exn_value(A) ::
30 {exn_class(), A}.
6731749b 31
3b156801
SK
32-type t(A, B) ::
33 {ok, A}
34 | {error, B}
35 .
6731749b
SK
36
37
4af0774b
SK
38-spec return(A) ->
39 {ok, A}.
40return(X) ->
41 {ok, X}.
42
43-spec map(t(A, Error), fun((A) -> (B))) ->
44 t(B, Error).
fd4da0e0
SK
45map({_, _}=T, F) ->
46 map_ok(T, F).
47
48-spec map_ok(t(A, Error), fun((A) -> (B))) ->
49 t(B, Error).
50map_ok({ok, X}, F) ->
4af0774b 51 {ok, F(X)};
fd4da0e0 52map_ok({error, _}=Error, _) ->
4af0774b
SK
53 Error.
54
a80ca0b2
SK
55-spec map_error(t(A, B), fun((B) -> (C))) ->
56 t(A, C).
57map_error({ok, _}=Ok, _) ->
58 Ok;
59map_error({error, Reason}, F) ->
60 {error, F(Reason)}.
61
62-spec tag_error(t(A, Reason), Tag) ->
63 t(A, {Tag, Reason}).
64tag_error({ok, _}=Ok, _) ->
65 Ok;
66tag_error({error, Reason}, Tag) ->
67 {error, {Tag, Reason}}.
68
ed9905af
SK
69-spec pipe([F], X) ->
70 t(Ok, Error)
71 when X :: any()
72 , Ok :: any()
73 , Error :: any()
74 , F :: fun((X) -> t(Ok, Error))
75 .
3efbdbc9
SK
76pipe([], X) ->
77 {ok, X};
6731749b
SK
78pipe([F|Fs], X) ->
79 case F(X)
80 of {error, _}=E -> E
81 ; {ok, Y} -> pipe(Fs, Y)
82 end.
8fc25ea1
SK
83
84-spec lift_exn(F) -> G
64617423
SK
85 when F :: fun((A) -> B)
86 , G :: fun((A) -> t(B, exn_value(any())))
8fc25ea1
SK
87 .
88lift_exn(F) when is_function(F, 1) ->
64617423
SK
89 ID = fun hope_fun:id/1,
90 lift_map_exn(F, ID, ID).
91
92-spec lift_exn(F, ErrorTag) -> G
93 when F :: fun((A) -> B)
94 , G :: fun((A) -> t(B, {ErrorTag, exn_value(any())}))
95 .
96lift_exn(F, ErrorTag) when is_function(F, 1) ->
97 ID = fun hope_fun:id/1,
98 Tag = fun (Reason) -> {ErrorTag, Reason} end,
99 lift_map_exn(F, ID, Tag).
b79afea0 100
64617423
SK
101-spec lift_map_exn(F, MapOk, MapError) -> G
102 when F :: fun((A) -> B)
103 , MapOk :: fun((B) -> C)
104 , MapError :: fun((exn_value(any())) -> Error)
105 , G :: fun((A) -> t(C, Error))
b79afea0 106 .
64617423 107lift_map_exn(F, MapOk, MapError) when is_function(F, 1) ->
b79afea0 108 fun(X) ->
64617423
SK
109 Result =
110 try
111 {ok, F(X)}
112 catch Class:Reason ->
113 {error, {Class, Reason}}
114 end,
115 % Applying maps separately as to not unintentionally catch an exception
116 % raised in a map.
117 case Result
fd4da0e0 118 of {ok , _}=Ok -> map_ok (Ok , MapOk)
64617423 119 ; {error, _}=Error -> map_error(Error, MapError)
b79afea0
SK
120 end
121 end.
This page took 0.036141 seconds and 4 git commands to generate.