Open lawrence-koh opened 2 years ago
Hi, and thanks for the interesting question! :slightly_smiling_face:
I don't have a solution at hand, but I'll think about it and get back to you.
Could you explain in a bit more detail what you'd like to archive (or maybe show a minimal example in Haskell)?
Do you want func
to not be called at all if the logging, which is done before it, fails, and get a logging-failed result? Or should func
be called nonetheless, and the logging-failed information shall be transported somewhere in addition to the result<string, string>
from func
?
I was thinking of something like the below:
//func : [String] -> Result String String
fplus::result< std::string, std::string > func( const std::vector< std::string >& param )
{
log("Performing func..."); -> this will throw if the logging fails
//actual code for func
}
If the log function fails and throws, I would like the logging failed information to be transported in addition to the result<string, string>. I suppose one way would be just to change the return type of result
to something else?
I would like the logging failed information to be transported in addition to the result<string, string>.
Ok, so if I understand correctly, no matter if the logging fails or not, you want your actual function to be executed nonetheless. Because otherwise, it would just be simple monadic composition, which could be achieved using things like fplus::and_then_result
(((a -> Result c b), (Result a b)) -> Result c b
) or fplus::compose_result
(((a -> Result b c), (b -> Result d c)) -> (a -> Result d c)
).
But in your case, we can have the following possible results:
func
succeededfunc
failedfunc
succeeded (would not exist in monadic composition)func
failed (would not exist in monadic composition)Thus, just thinking about the types for now, we need a return type for your final (composed) function able to represent all those states.
For now, we have:
log : a -> Result Monostate String
a
would probably be [String]
in your case, but trying to simplify be generalizing here.Monostate
is just a unit type, like std::monostate
, which would be returned if the logging succeededString
would be the error message explaining why the log failed, for example, the what()
part of the exception that would be thrown.func : a -> Result String String
So the result of the new log_and_func
function could contain (per case):
String
(from func
success)String
(from func
fail)(String, String)
(from log
fail and from func
success)(String, String)
(from log
fail and from func
fail)Thus we could have log_and_func : a -> (Maybe String, Result String String)
. Example result pairs:
(Nothing, "func_result")
(Nothing, "func_error")
("log_error", "func_result")
("log_error", "func_error")
Is the above going in the right direction, or do you intend something else?
yes what you outlined makes sense!
Hi @Dobiasd,
I worked through your Udemy functional programming course and found functional programming and
fplus
to be highly interesting. Am currently attempting to refactor some code and am just wondering if there is a way to model IO monads usingfplus
?I have a function that is currently as such:
However, I would like to add some logging at the start of the function. This would change the return type since logging is an
IO
action which may fail, but not too sure how it can be done usingfplus
.Be great if I could get your advice :)