Two more noob questions :slightly_smiling_face: : ...
# arrow
n
Two more noob questions ๐Ÿ™‚ : 1. Why is there a need for separate
recover()
and
catch()
functions? Why isn't everything
fold()
? 2. When is the type parameter
B
and parameter
transform
of
fold()
is useful? Wouldn't it be enough to have
Copy code
// Just an example, this function is not present is Arrow
inline fun <Error, A> fold(
  @BuilderInference block: Raise<Error>.() -> A,
  recover: (error: Error) -> A,
  catch: (throwable: Throwable) -> A = { throw it }
)
and handle the transformation after the
fold()
call? The above is very similar to the actual
recover()
function:
Copy code
public inline fun <Error, A> recover(
  @BuilderInference block: Raise<Error>.() -> A,
  @BuilderInference recover: (error: Error) -> A,
  @BuilderInference catch: (throwable: Throwable) -> A,
): A = fold(block, catch, recover, ::identity)
These questions popped up because I don't like the naming of the
recover()
and
catch()
functions. I almost always use
recover()
but it is a bit strange that it also has a parameter named
recover
. So although the core function is
fold()
, I never use it because
recover()
with the
transform = ::identity
argument seems to be appropriate always... Thanks.
+1: is the name
fold
a well-known FP terminology? (So why not
run()
or
execute()
or
perform()
or ...?)
s
Hey @Norbi, Okay, question 1 & 2 seem to go hand-in-hand ๐Ÿ˜… โ€ข
fold
is useful when you need to align types after user code, so when building custom DSLs. I've only really needed it in one place, ior. So
recover
is probably sufficient in 99,99% of the cases. It's also the natural operation for
Raise
. Where you
raise
and
recover
โ€ข
recover
with 3 parameters, is basically just an alias for
fold
with
::identity
.
fold
is indeed a common name in FP for this kind-of operation, but seems foreign to use all-over code so
recover
seems to make more sense. Where you normally only need
recover
or
catch
in regular code, and even that only occasionally. Where typically most code exists out of
flatMap
most of the time, but in this case it's just regular code and
flatMap
is not needed.
recover
with a
recover
parameter is perhaps a bit unfortunate, but I am not sure what a better name would be. At least at this point it's consistent with all other functions and parameter names. In the end like you said everything is just
fold
but with different combinations of arguments. The reason for
transform
is just that you can align the value returned from
block
,
recover
and
catch
to a different type such as shown in
Ior
.
Actually,
ior
can be rewritten with
recover
๐Ÿ˜… So the
transform
parameter could be dropped but I would be in favor of
recover
rather than
fold
and that still brings the question of parameter name ๐Ÿค”
n
Thanks for the quick answer, now I have some more insight to the design decisions. I'd better get used to the name of
recover()
, it seems that I was the only one not completely satisfied with it ๐Ÿค” ๐Ÿ™‚
s
Why are you not liking
recover
? From your answer it sounds like you're not fan of the parameter name
recover
resulting in:
Copy code
fun Raise<String>.example(): Int = 1

recover(
  block = { example() },
  recover = { str -> str.length }
)
n
Yes, the main reason is that the parameter name is the same as the function name ๐Ÿ™‚ Really insignificant "issue", so don't waste your time with it ๐Ÿ™‚ Thanks again for the detailed answers!
Besides,
Copy code
effect {
    ...
}.recover {
    ...
}.bind()
can also be used which has a nice syntax imho ๐Ÿ™‚
"which has a nice syntax imho" - the problem is that I always forget to call
bind()
๐Ÿ˜•
s
There is this project that leverages Detekt, but I still need to PR an update for the new DSL. https://github.com/woltapp/arrow-detekt-rules