I am currently working on a stream Result type `Er...
# arrow
k
I am currently working on a stream Result type
Error<E> | Loading | Success<T>
. I tried to implement
applicative
for the type. What I would like to achieve is the that the
error
would have a higher precedence than
Loading
, but the
ap()
implementation with
Copy code
flatmap{ .map{ ff() } }
I can not obtain the state of the second state unless the first is success. an example that I would like to achive:
Copy code
Result.applicative().tupled(Loading, Error) 
// current result: Loading
Instead of the loading I am looking for the
Error
to be returned. is there a good way to execute it? 🤔 is that a good idea t all? 😄
r
the default impl of ap based on flatMap can be overriden to not be based on flatMap
k
🤦
now I realised how silly my question was. Thanks for lead!
Copy code
fun <B> ap(ff: ResultOf<(T) -> B>): Result<B> {
        val next = ff.fix().flatMap {this.map(it)}
        return when (val current = this.fix()) {
            is Loading -> when(next) {
                Loading -> current
                is Error -> next
                is Success -> current
            }
            is Error -> current
            is Success -> next
        }
    }
j
If you do that, be careful with using it (that actually violates some monad/applicative law afaik) This should not be a problem in your case but can sometimes lead to weird behavior.
k
thanks for the warrning @Jannis! can you help me with the laws I break? I would love to look deeper into this. I am not sure yet, if this is worth to break the flow.
j
This is about the applicative-monad-consistency law which basically states: If an Applicative functor is also a Monad, ap should behave no different than if it's implemented with flatMap. This is to reason about code as now with a different constraint you get different behaviour despite Monad just being a stronger version of applicative. This is not a problem if you are very careful with it's use (for example I break that law for generators in propCheck (at least the rewrite of it I am working on atm) because the applicative behaviour is preferable). Twitter impurepics has a nice image showing this: https://impurepics.com/posts/2019-03-18-monad-applicative-consistency-law.html
👍 1
Honestly following this law is up to you, if you want to break it, break it, but be prepared for odd behaviour when using applicative methods from a monad constraint
The solution in haskell would be to introduce a newtype and define applicative over that type. However due to the lack of newtypes, or comparable, in kotlin I'd probably define a seperate applicative instance and use that when you explicitly want this behaviour