Test on newer releases
[hope.git] / src / hope_result.erl
... / ...
CommitLineData
1-module(hope_result).
2
3-behavior(hope_gen_monad).
4
5-export_type(
6 [ t/2
7 , exn_class/0
8 , exn_value/1
9 ]).
10
11-export(
12 % Generic monad interface
13 [ return/1
14 , map/2 % map/2 is alias for map_ok/2
15 , pipe/2
16
17 % Specific to hope_result:t()
18 , map_ok/2
19 , map_error/2
20 , tag_error/2
21 , lift_exn/1
22 , lift_exn/2
23 , lift_map_exn/3
24 ]).
25
26-type exn_class() ::
27 error
28 | exit
29 | throw
30 .
31
32-type exn_value(A) ::
33 {exn_class(), A}.
34
35-type t(A, B) ::
36 {ok, A}
37 | {error, B}
38 .
39
40
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).
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) ->
54 {ok, F(X)};
55map_ok({error, _}=Error, _) ->
56 Error.
57
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
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 .
79pipe([], X) ->
80 {ok, X};
81pipe([F|Fs], X) ->
82 case F(X)
83 of {error, _}=E -> E
84 ; {ok, Y} -> pipe(Fs, Y)
85 end.
86
87-spec lift_exn(F) -> G
88 when F :: fun((A) -> B)
89 , G :: fun((A) -> t(B, exn_value(any())))
90 .
91lift_exn(F) when is_function(F, 1) ->
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).
103
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))
109 .
110lift_map_exn(F, MapOk, MapError) when is_function(F, 1) ->
111 fun(X) ->
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
121 of {ok , _}=Ok -> map_ok (Ok , MapOk)
122 ; {error, _}=Error -> map_error(Error, MapError)
123 end
124 end.
This page took 0.020213 seconds and 4 git commands to generate.