Could anyone answer this SO question <https://stac...
# arrow
s
done ๐Ÿ˜„
v
@stojan oh thank you so. Let me give some time to read and understand your answer
s
no worries, let me know if you have doubts
v
I can understand your tupled example clearly, but I couldn't catch how NonEmptyList combine function gets called implicitly when any of the value failed ?
or what if change my lamda function from {a,b -> a+b} to {a,b -> a-b}
s
your function is only applied if both values are
Valid
Semigroup.combine
is applied if both are
Invalid
which works by adding two lists
Copy code
interface NonEmptyListSemigroup<A> : Semigroup<NonEmptyList<A>> {
  override fun NonEmptyList<A>.combine(b: NonEmptyList<A>): NonEmptyList<A> = this + b
}
or what if change my lamda function from {a,b -> a+b} to {a,b -> a-b}
then you get a different result (in case both are valid)
v
so in my code map is equivalent to tuple in your example
is it ?
s
yup, my happy path function is "hardcoded"
and actually, arrow also has
tupled
returning
TupleN
in case of success (as a specialization of map)
v
Copy code
fun <A, B, Z> map(
  a: Kind<F, A>,
  b: Kind<F, B>,
  lbd: (Tuple2<A, B>) -> Z
): Kind<F, Z> =
  a.product(b).map(lbd)
Copy code
fun <A, B> Kind<F, A>.product(fb: Kind<F, B>): Kind<F, Tuple2<A, B>> =
  fb.ap(this.map { a: A -> { b: B -> Tuple2(a, b) } })
fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B>
s
here is a similar example for combining 2 values of type `Option`https://github.com/LordRaydenMK/fpscala.kt/blob/master/src/main/kotlin/chapter4/exercise4.3.kt#L6
well, the arrow codebase is abstracted over typeclasses, which can make the code harder to read (especially because typeclasses are emulated in Kotlin)
v
๐Ÿ˜€ I just try to find the line that calls semigroup combine method
anyhow thank you so much for your time
ill accept your SO answer
s
You are welcome, I hope it helped ๐Ÿ™‚
๐Ÿ‘ 1
v
Copy code
fun <E, A, B> ValidatedOf<E, A>.ap(SE: Semigroup<E>, f: Validated<E, (A) -> B>): Validated<E, B> =
  fix().fold(
    { e -> f.fold({ Invalid(SE.run { it.combine(e) }) }, { Invalid(e) }) },
    { a -> f.fold(::Invalid) { Valid(it(a)) } }
  )
I think this applicative type class method doing the trick. ValidatedOf Datatype extends applicative typeclass method ap() which takes semigroup and combines invalid results as you said, but the fold function inside it looks weird.
๐Ÿ‘ 1
s
Fold is how you interpret the type into a single value, providing functions for the Valid and Invalid case.
v
Yep but here it takes two function for invalid (e ->) and two function for valid ( a->) case ๐Ÿค”
s
you have two values of type
Validated
, (the implicit one, because the function is an extension function, and
f
). And you need to unwrap both of them. So again, like in my example you need to handle 4 cases.
v
Ah understood ๐Ÿ‘