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