but I'm struggling to come up with a real-life exa...
# arrow
b
but I'm struggling to come up with a real-life example for how to swap out instances of
<F>
in something like the following:
Copy code
interface S3Ops<F>: MonadDefer<F> {

    val s3: AmazonS3

    fun getS3Info(bucket: String, key: String): Kind<F, S3Object> {

        val waiterRequest = GetObjectMetadataRequest(bucket, key)

        return catch { s3.waiters().objectExists().run(WaiterParameters(waiterRequest)) }
                .flatMap {
                    val objectRequest = GetObjectRequest(bucket, key)
                    catch { s3.getObject(objectRequest) }
                }.flatMap {
                    if (it == null) {
                        raiseError(RuntimeException("No object retrieved from S3"))
                    } else {
                        just(it)
                    }
                }
    }
p
Copy code
object IOBla: S3Ops<F>, MonadDefer<F> by IO.monadDefer() {
  override val s3: AmazonS3 = s3()
}
Copy code
object RxBla: S3Ops<F>, MonadDefer<F> by Observable.monadDefer() {
 override val s3: AmazonS3 = s3()
}
you can apply part of an interface using delegation
and the other with overrides
b
Agree, changing effect semantics or interfacing makes sense. The context in consideration in the linked paper changes the entire behavior (expression evaluation vs. expression pretty-printing)
and that's where I'm struggling - maybe it's not possible to "pretty-print" functions specified as arguments to catch/flatMap above
p
ooooooh
full program reification?
look into Free Monad
b
I think my disconnect right now is assuming that I can apply arbitrary algebras to any type
e.g. it's easy to provide printers or evaluators for Exprs but not so much for S3Ops
Would it be fair to say that the algebras in Arrow are the algebras of effects, vs. the generalized algebras suggested in the paper?
yeah, that must be the case since the algebra is constrained - in the above example
F
has to be
MonadDefer
instead of the general
F
in the paper
Thanks for the discussion 🙂
p
Yes, in the case of Free Monad an algebra resembles something like an event bus, or a reducer if you prefer those terms
you define your program as a reification of execution
and your subscriber/reducer takes that algebra of messages and interprets it to a value
Ank is written like that
or at least it used to
b
Free Monads/free algebras are probably the next step on my journey to enlightenment, TBH
if you squint it’s a reducer except that reducer is applicative (1 message, 1 effect) and this is monadic (1 message, N effects)
b
I'll need to spend some time squinting at it. Thanks for the pointer!
p
👍🏼
b
Thanks for the pointer. I think I got it while I was falling asleep last night - I just need to create a base language that describes operations (rather than performs them) then create the interpreters that act on the operations I can achieve both "pretty-printing" and actual S3 operations.
🎉 1
p
yes
the design is as follows:
myOperationFunction(parameter: String): User
becomes
data class MyOperationData(val parameter: String): MyAlgebra<F, User>
and MyAlgebra is the composition of all operations, parametrized to
F
actually it may not even be necessary
just MyAlgebra<User> and that flattens for `F`in the interpeter
b
Yup. I'm not quite to that level of abstraction yet but I have enough in front of me to see that I can replace mocking with interpreters that (e.g.) parameterize over State<S,A> and record the list of operations to be executed instead of mocking, which is quite nice
🎉 1