Define and implement a generic monad behavior.
[hope.git] / src / hope_result.erl
1 -module(hope_result).
2
3 -behavior(hope_monad).
4
5 -export_type(
6 [ t/2
7 ]).
8
9 -export(
10 [ return/1
11 , map/2
12 , pipe/2
13 , lift_exn/1
14 , lift_exn/2
15 ]).
16
17
18 -type t(A, B) ::
19 {ok, A}
20 | {error, B}
21 .
22
23
24 -spec return(A) ->
25 {ok, A}.
26 return(X) ->
27 {ok, X}.
28
29 -spec map(t(A, Error), fun((A) -> (B))) ->
30 t(B, Error).
31 map({ok, X}, F) ->
32 {ok, F(X)};
33 map({error, _}=Error, _) ->
34 Error.
35
36 -spec pipe([F], X) ->
37 t(Ok, Error)
38 when X :: any()
39 , Ok :: any()
40 , Error :: any()
41 , F :: fun((X) -> t(Ok, Error))
42 .
43 pipe([], X) ->
44 {ok, X};
45 pipe([F|Fs], X) ->
46 case F(X)
47 of {error, _}=E -> E
48 ; {ok, Y} -> pipe(Fs, Y)
49 end.
50
51 -spec lift_exn(F) -> G
52 when F :: fun((A)-> B)
53 , G :: fun((A)-> t(B, {Class, Reason :: any()}))
54 , Class :: error
55 | exit
56 | throw
57 .
58 lift_exn(F) when is_function(F, 1) ->
59 fun(X) ->
60 try
61 {ok, F(X)}
62 catch Class:Reason ->
63 {error, {Class, Reason}}
64 end
65 end.
66
67 -spec lift_exn(F, Label) -> G
68 when F :: fun((A)-> B)
69 , G :: fun((A)-> t(B, {Label, {Class, Reason :: any()}}))
70 , Class :: error
71 | exit
72 | throw
73 .
74 lift_exn(F, Label) when is_function(F, 1) ->
75 fun(X) ->
76 try
77 {ok, F(X)}
78 catch Class:Reason ->
79 {error, {Label, {Class, Reason}}}
80 end
81 end.
This page took 0.066143 seconds and 4 git commands to generate.