X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=src%2Fhope_result.erl;h=0f9fb05b4dbaf405d5d81cb8359f47527c2c8248;hb=fd4da0e0037ecf1f8b77b08d439fef0301e8a871;hp=dec6e799d1a97b7be5cb260224c8fbbec2b99df6;hpb=a80ca0b203dc3398a0117d2e1fc6ae5d77250783;p=hope.git diff --git a/src/hope_result.erl b/src/hope_result.erl index dec6e79..0f9fb05 100644 --- a/src/hope_result.erl +++ b/src/hope_result.erl @@ -4,18 +4,30 @@ -export_type( [ t/2 + , exn_class/0 + , exn_value/1 ]). -export( [ return/1 - , map/2 + , map/2 % map/2 is alias for map_ok/2 + , map_ok/2 , map_error/2 , tag_error/2 , pipe/2 , lift_exn/1 , lift_exn/2 + , lift_map_exn/3 ]). +-type exn_class() :: + error + | exit + | throw + . + +-type exn_value(A) :: + {exn_class(), A}. -type t(A, B) :: {ok, A} @@ -30,9 +42,14 @@ return(X) -> -spec map(t(A, Error), fun((A) -> (B))) -> t(B, Error). -map({ok, X}, F) -> +map({_, _}=T, F) -> + map_ok(T, F). + +-spec map_ok(t(A, Error), fun((A) -> (B))) -> + t(B, Error). +map_ok({ok, X}, F) -> {ok, F(X)}; -map({error, _}=Error, _) -> +map_ok({error, _}=Error, _) -> Error. -spec map_error(t(A, B), fun((B) -> (C))) -> @@ -65,33 +82,40 @@ pipe([F|Fs], X) -> end. -spec lift_exn(F) -> G - when F :: fun((A)-> B) - , G :: fun((A)-> t(B, {Class, Reason :: any()})) - , Class :: error - | exit - | throw + when F :: fun((A) -> B) + , G :: fun((A) -> t(B, exn_value(any()))) . lift_exn(F) when is_function(F, 1) -> - fun(X) -> - try - {ok, F(X)} - catch Class:Reason -> - {error, {Class, Reason}} - end - end. + ID = fun hope_fun:id/1, + lift_map_exn(F, ID, ID). + +-spec lift_exn(F, ErrorTag) -> G + when F :: fun((A) -> B) + , G :: fun((A) -> t(B, {ErrorTag, exn_value(any())})) + . +lift_exn(F, ErrorTag) when is_function(F, 1) -> + ID = fun hope_fun:id/1, + Tag = fun (Reason) -> {ErrorTag, Reason} end, + lift_map_exn(F, ID, Tag). --spec lift_exn(F, Label) -> G - when F :: fun((A)-> B) - , G :: fun((A)-> t(B, {Label, {Class, Reason :: any()}})) - , Class :: error - | exit - | throw +-spec lift_map_exn(F, MapOk, MapError) -> G + when F :: fun((A) -> B) + , MapOk :: fun((B) -> C) + , MapError :: fun((exn_value(any())) -> Error) + , G :: fun((A) -> t(C, Error)) . -lift_exn(F, Label) when is_function(F, 1) -> +lift_map_exn(F, MapOk, MapError) when is_function(F, 1) -> fun(X) -> - try - {ok, F(X)} - catch Class:Reason -> - tag_error({error, {Class, Reason}}, Label) + Result = + try + {ok, F(X)} + catch Class:Reason -> + {error, {Class, Reason}} + end, + % Applying maps separately as to not unintentionally catch an exception + % raised in a map. + case Result + of {ok , _}=Ok -> map_ok (Ok , MapOk) + ; {error, _}=Error -> map_error(Error, MapError) end end.