Hi! Lately, I’ve been wondering how helpful Curryi...
# arrow
c
Hi! Lately, I’ve been wondering how helpful Currying, Compose and Pipe are in the Kotlin FP world. is something that i should be using regularly as kotlin fp programmer? or is something more useful for programming languages like Haskell?
r
Hi Alejandro, My opinion is that in general those operators in the JVM have a higher cost, because composition usually implies allocations and wrapping around the lambdas. They are not popular in Kotlin and with time the same happened to Scala, people do not bother with them for what I can see and are mostly used for teaching but rarely seen in real world projects.
🔝 4
s
is something that i should be using regularly as kotlin fp programmer?
TL;DR no 😄
p
Pipe is used very frequently in Kotlin, it’s just called
let
🔝 1
and specially
let?.
that gives you additional behavior
🔝 1
c
I was watching this talk and it shows an example in F# (which supports currying by default). I wanted to do the same with kotlin and i realized that it isn’t the most appropriate programming language for this kind of thing, as Raul has mentioned. And that’s why I wanted to better ask to experts haha

https://youtu.be/rCKPgu4DvcE?t=2310

p
i used currying quite frequently in Scala... the syntax was just so much more approachable than in kotlin imho
k
@carbaj0 The views expressed on using currying/function composition in Kotlin/Arrow by Raul and Simon were a real shock to me coming from other FP languages (I'm a big fan of Scott Wlaschin too BTW for his efforts to bring FP ideas to the masses). I've been porting another FP library to Kotlin, so I've had to think about how to port the concepts into the Kotlin/Arrow world as the originally library uses Currying etc heavily. My 2c is that I think that it's a lot harder in a statically typed language like Kotlin (disclaimer: all my other FP work has been in dynamically typed languages). I've often had to step in and help the compiler, whereas if I just create variables the compiler could figure types out on it's own. Arrow comprehensions were a learning curve given I'm used to Kleisli composition and pointfree programming. Having to think up variable names again was a shock 😆 . Sometimes I get frustrated by the type system, but it is what it is. Kotlin/JVM bring other benefits so I gracefully give my FP purity away and make the code work. Having a couple of intermediate variables isn't really that big a deal to have readable code. Being a seasoned Java developer in an earlier life being able to come back to the JVM with Kotlin/Arrow is an absolute joy.
m
c
thanks for your answers, now I feel a little more confident when I look at the code of my projects haha
k
@Marko Novakovic I read through that entire thread, and the focus seems to be on the fact that you can pipe/compose functions of non Sum (disjunction) types (eg: String, Int, etc) using
let
etc. Where the value of a pipe operator (and what Wlaschin highlights in his talks) is the ability to "switch tracks", or use a Sum/Monad type (like Arrow's
Either
) without having to worry about the complexity of gluing the functions together. Composing functions together that return a Monad with a "pipe" function/operator requires Kleisli composition (https://blog.ssanj.net/posts/2017-06-07-composing-monadic-functions-with-kleisli-arrows.html). F# seems to use its pipe operator for both types of function composition. Of course, Arrow has Monad comprehensions for that so you can take the ideas of a simple
pipeK
and do the piping yourself.
Copy code
F#

request 
|> validate() 
|> persist() 
|> notify() 
|> getResponse();

Kotlin/Arrow

either {
  val valid = validate(request).bind()
  val persisted = persist(valid).bind()
  val notified = notify(persisted).bind()
  val response = getResponse(notified).bind()

  response
}
However (as per my previous comment) it requires the creation of "intermediate" variables, and is therefore not pointfree which a lot of FP code strives to be. I understand that the Kotlin/Arrow designers have made very well thought out decisions as to why they've done what they've done (due to the JVM platform, Kotlin being a statically typed language, performance concerns, etc). It does mean however that we're not going to get the same level of "FP niceness" in Kotlin/Arrow that you get in other languages.
r
@kierans777 https://gist.github.com/raulraja/c31ef316e6e83c548966e3bdb66259c0 Here is an example of how you can achieve Pipe in this style by declaring your own functions that properly infers functions with receivers in suspend. When multiple receivers come out it’s possible to provide a version of
let + bind
but Kotlin unviversal way of invokation is not a pipe but
callable references
which are currently quit limiting, specially polymorphic function shapes like Kleisli. You can oberserve in that code that receivers allow you to remove the complexity. In general if you use the EffectScope coming to arrow you don’t ever need to return Either<E, A>, just
A
where
EffectScope<E>
is a receiver. that already gives you the power to shift out a value of
E
. I’m saying this because
bind
can also be eliminated if you don’t return Either in the first place.
m
@kierans777 I agree. am also doing some F# and I love
|>
so much. we don’t have same feature in Kotlin but I wanted to bring attention that it’s not all that bad and that Kotlin has similar feature(s)
👍 1