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