Dobiasd / FunctionalPlus

Functional Programming Library for C++. Write concise and readable C++ code.
http://www.editgym.com/fplus-api-search/
Boost Software License 1.0
2.07k stars 168 forks source link

IO Monad #265

Open lawrence-koh opened 2 years ago

lawrence-koh commented 2 years ago

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 using fplus?

I have a function that is currently as such:

//func : [String] -> Result String String
fplus::result< std::string, std::string > func( const std::vector< std::string >& param )

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 using fplus.

Be great if I could get your advice :)

Dobiasd commented 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.

Dobiasd commented 2 years ago

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?

lawrence-koh commented 2 years ago

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?

Dobiasd commented 2 years ago

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:

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:

So the result of the new log_and_func function could contain (per case):

Thus we could have log_and_func : a -> (Maybe String, Result String String). Example result pairs:

Is the above going in the right direction, or do you intend something else?

lawrence-koh commented 2 years ago

yes what you outlined makes sense!