3 ms·
It's a tradeoff. I may not get monads with Kotlin, but I also never have to understand (or explain) code like: override def covariantInstance[C]: Applicative
by ebiester 9y ago
It's a tradeoff. I may not get monads with Kotlin, but I also never have to understand (or explain) code like:
override def covariantInstance[C]: Applicative[C =>: ?] =
new Applicative[C =>: ?] with SndCovariant[C] {
def point[A](a: => A): C =>: A = arr(_ => a)
def ap[A, B](fa: => (C =>: A))(f: => (C =>: (A => B))): (C =>: B) = <<<(arr((y: (A => B, A)) => y._1(y._2)), combine(f, fa))
}
More importantly, as I bring people on to the team, I don't have to try and explain it to them. Scala was an interesting language, and I'm glad I spent some time digging into it, but its compromises around the JVM and java source compatibility and supporting every programming paradigm it could find makes it an unproductive language in my experience.
- lmm 9y agoSo what would the equivalent Kotlin look like? class applicativeCovariantInstanceStringString<C>: Applicative<EqualsGreaterThanColon<C, String, String>> { fun point(a: () => String): EqualsGreaterThanColon<C, String> = arr(_ => a()) fun ap(fa: () => EqualsGreaterThanColon<C, String>))(f: () => EqualsGreaterThanColon<C, String => String>): EqualsGreaterThanColon<C, String> = LessThanLessThanLessThan(arr((y: Pair<String => String, String>) => y.first(y.second)), combine(f, fa)) } class applicativeCovariantInstanceStringInt<C>: Applicative<EqualsGreaterThanColon<C, String, Int>> { fun point(a: () => String): EqualsGreaterThanColon<C, String> = arr(_ => a()) fun ap(fa: () => EqualsGreaterThanColon<C, String>))(f: () => EqualsGreaterThanColon<C, String => Int>): EqualsGreaterThanColon<C, Int> = LessThanLessThanLessThan(arr((y: Pair<String => Int, String>) => y.first(y.second)), combine(f, fa)) } class applicativeCovariantInstanceStringFloat<C>: Applicative<EqualsGreaterThanColon<C, String, Float>> { fun point(a: () => String): EqualsGreaterThanColon<C, String> = arr(_ => a()) fun ap(fa: () => EqualsGreaterThanColon<C, String>))(f: () => EqualsGreaterThanColon<C, String => Float>): EqualsGreaterThanColon<C, Float> = LessThanLessThanLessThan(arr((y: Pair<String => Float, String>) => y.first(y.second)), combine(f, fa)) } class applicativeCovariantInstanceIntString<C>: Applicative<EqualsGreaterThanColon<C, Int, String>> { fun point(a: () => Int): EqualsGreaterThanColon<C, Int> = arr(_ => a()) fun ap(fa: () => EqualsGreaterThanColon<C, Int>))(f: () => EqualsGreaterThanColon<C, Int => String>): EqualsGreaterThanColon<C, String> = LessThanLessThanLessThan(arr((y: Pair<Int => String, Int>) => y.first(y.second)), combine(f, fa)) } // and so on for all other pairs of types I mean, I'm not going to defend whatever library you got that from, because I don't think EqualsGreaterThanColon or LessThanLessThanLessThan are very good names (whether you write them with letters or with symbols), but I don't think restricting the language actually makes it any better.
- rbehrends 9y agoNot the OP, but I would rethink my abstractions and modeling. Just as it's not always helpful to pull out ring theory and unique factorization domains to simply explain the fundamental theorem of arithmetic. Part of designing a good abstraction is the interface communicating usage and intent, which should be tailored to the problem domain and the audience.
- lmm 9y agoYeah, it's hard to compare abstractions made for different audiences. Working in Scala I use applicatives all the time, so if you show me something and tell me it's an applicative then that's a lot more useful than giving me the details of the operations it has. But obviously to someone who isn't used to them talking about applicatives seems like it's just adding another layer of indirection.
- ebiester 9y agoI picked it from scalaz, and didn't have to go far to find an example.