-
-
Notifications
You must be signed in to change notification settings - Fork 417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Functional approach to try-catch-finally #1108
Comments
Good afternoon, I believe you should post this in the Discussion section instead of the issues. Unless you believe something here doesn't behave as you think it should. |
You're using
The only monad that does public static class Resource
{
public static Fin<B> use<A, B>(Fin<A> resource, Func<A, Fin<B>> op)
where A : IDisposable
{
try
{
return resource.Bind(op);
}
catch (Exception e)
{
return Fin<B>.Fail(e);
}
finally
{
resource.Iter(r => r?.Dispose());
}
}
} Then you can do this: Resource.use(AllocatateResource(1),
resId => from unit in UseResource(resId)
from _ in DeleteResource(resId)
select _); With the from resId in use(AllocatateResource(1))
from unit in UseResource(resId)
select _); It tracks the resources and cleans them up automatically. I am actually working on bringing resource tracking to every monadic type (for version 5), but for now it's a case of wrapping up the sub-expression with your own function. For some monadic types there are some One other thing, seeing as it looks like you're doing IO side-effects, I'd recommend using |
@louthy thanks for you fast reply! I thought it would be beneficial to hide the exceptions inside those methods, thats why I changed the return type to Fin and work with the Error struct from there. Is this assumtion flawed? I tried the solution with the Resource.use function, but it also hides errors, that occur in the Dispose call, if I dont use exceptions. (The Dispose function cannot "return" anything, except an exception :D ) The example with the Effect monad confused me, because I cannot find any use Function for Eff or Aff, that does not take a function as second parameter. But from the use code I found, that solution would have the same Error propagation problem based on the Dispose call, as the Resource.use function. If I want to get rid of exceptions, I have to go with my presented solution for now I guess. |
No, but the way to think about the monadic types, like The trick for any part of your application is to use the monad with the smallest set of capabilities for the subdomain you're working on. When you need to expand those you pick a 'bigger' monad with more built-in capabilities.
It's our IO monad. It should be at the outer edges of your application. You can think of the smallest capability being entirely pure functions. That's the 'inner' layer. Then maybe
You can remove the |
This is a very interesting way to think about the monads. Are the monads and their capabilities listed somewhere for comparison, or is this the type of thing one should just learn over time? |
You could check the Features list on the ReadME. Also the reference documentation also includes a number of preambles that I’ve written for each section. Most of the names of the monadic types are fairly standard for many different FP languages, so googling “Either monad” would likely get you plenty of hits. |
Hello,
I find my way into functional programming and love to see, that I can get started without leaving C# behind. Thanks for the great work! But I cannot get my head around on how to implement a try-catch-finally behaviour in a FP style.
I have to following 3 functions to work with and every single one can throw an exception...
With try catch finally it would look like this (it is important, that the finally block can exit with an exception):
This is a real mess in my opinion so I changed those methods to the following:
Now, I can do this, which looks pretty good and is easier to understand.
But if UseResource returns an Error, there will be an early out and DeleteResource is not called anymore. If I have to use Map and Match Functions to handle this, it will get more complicated again. I tried to use the Prelude.use function and wrap the allocate and delete function in an IDisposable, but in that case the possible Error from DeleteResource cannot be accessed anymore. So my best working state is this:
The Fail part in the first match clause is my main issue, because I need the Error from the UseResource call and not the success state of the DeleteResource call. In addition I dont like the two calls to DeleteResource.
Is there any smarter/better way of calling the DeleteResource method if AllocatateResource was sucessful and keep the error of the UseResource call?
Thanks for any help :)
The text was updated successfully, but these errors were encountered: