Define explicit map_ok as implementation of map
[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 [ return/1
13 , map/2 % map/2 is alias for map_ok/2
14 , map_ok/2
15 , map_error/2
16 , tag_error/2
17 , pipe/2
18 , lift_exn/1
19 , lift_exn/2
20 , lift_map_exn/3
21 ]).
22
23-type exn_class() ::
24 error
25 | exit
26 | throw
27 .
28
29-type exn_value(A) ::
30 {exn_class(), A}.
31
32-type t(A, B) ::
33 {ok, A}
34 | {error, B}
35 .
36
37
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).
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) ->
51 {ok, F(X)};
52map_ok({error, _}=Error, _) ->
53 Error.
54
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
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 .
76pipe([], X) ->
77 {ok, X};
78pipe([F|Fs], X) ->
79 case F(X)
80 of {error, _}=E -> E
81 ; {ok, Y} -> pipe(Fs, Y)
82 end.
83
84-spec lift_exn(F) -> G
85 when F :: fun((A) -> B)
86 , G :: fun((A) -> t(B, exn_value(any())))
87 .
88lift_exn(F) when is_function(F, 1) ->
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).
100
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))
106 .
107lift_map_exn(F, MapOk, MapError) when is_function(F, 1) ->
108 fun(X) ->
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
118 of {ok , _}=Ok -> map_ok (Ok , MapOk)
119 ; {error, _}=Error -> map_error(Error, MapError)
120 end
121 end.
This page took 0.024111 seconds and 4 git commands to generate.