question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Static Land interop `Observable` definition is wrong

See original GitHub issue

Like a comment in the current definition says, the definition is wrong:

  // This ap strictly speaking incompatible with chain. If we derive ap from chain we get
  // different (not very useful) behavior. But spec requires that if method can be derived
  // it must have the same behavior as hand-written method. We intentionally violate the spec
  // in hope that it won't cause many troubles in practice. And in return we have more useful type.
  ap(obsFn, obsVal) {
    return combine([obsFn, obsVal], (fn, val) => fn(val))
  },

I can see the “good intention” behind the above definition, but a major advantage of Static Land is precisely the fact that for a single type you can simply have as many different algebra module instances as needed:

  • We can implement many modules for one type, therefore we can have more than one instance of the same Algebra for a single type. For example, we can implement two Monoids for numbers: Addition and Multiplication.

Observables support multiple different algebras. For example, basically every flatMapXXX operation induces a Monad with different semantics. With Static Land, each of those can be supported as different algebra modules (all of them fully correct) from which the user can then pick and choose the appropriate one depending on which semantics are needed.

So, why is the above definition wrong? Because it breaks the sequential semantics of the chain. Let’s say that you wish to perform a sequence of, say, database operations using the Observable definition. You should be able to do that with an applicative sequence function, but now you cannot, because the above definition executes the operations in parallel, rather than sequentially.

Of course, another major advantage of Static Land is that this issue can be worked around simply by providing the proper algebra modules outside of the library core.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
hallettjcommented, Oct 7, 2018

@polytypic I’m not sure I agree that ap should have sequential semantics. Part of the purpose of Apply is to have an option for parallel operations. I don’t know what would be the right authoritative source to cite so I will cite a few sources:

Monads describe dependent computations and Applicatives describe independent computations.

https://typelevel.org/cats/typeclasses/parallel.html

Or, if you prefer — [monads] can work in series, whereas applicatives work in parallel.

https://hackernoon.com/functors-and-applicatives-b9af535b1440

Applicative functors provide a way to take two computations and join them together using a function. The Traversable example highlights how two collections can be parallelized into pairs. Applicative functors and parallel processing go together like bread and butter.

That’s a quote from “Scala in Depth” by Josh Suereth, discussed here: https://stackoverflow.com/questions/12184373/how-do-applicative-functors-tie-in-with-parallelizing-algorithms-scala-and-sca

On the other hand I found this comment on Reddit that argues that an implementer should maybe consider making an Apply instance sequential for types that implement Monad:

If you have an Applicative, you shouldn’t assume anything about the order of effects. If you are defining an Applicative (instance), you are free to perform effects in whatever order you want because no client can assume an order.

However, if you are planning on writing a Monad instance for the type for which you are writing an Applicative instance, then you need to think carefully. The effects associated with Monads do have an order that a client can depend on (due to the possibility of data dependence), and making Applicative and Monad instances for the same type agree on effect ordering is customary.

This reasoning wraps back around at this point. If you have a particular Applicative for which you know there is a Monad (such as IO), custom lets you assume the effects will be evaluated left-to-right so as to be compatible with the Monad instance.

In summary, you should think of any Applicative you are given as potentially evaluating effects in parallel, but if you’re on the other side of the implementation and want effects to actually run in parallel, you should reconsider defining a Monad instance for the same type so that clients can reason about effects based on the concrete type.

https://www.reddit.com/r/haskell/comments/381o9y/does_applicative_have_an_inherent_notion_of_order/crrmnmr/

Replies to that comment point out some counterexamples.

There is also a discussion of “sequencing of effects” in Haskell on Wikibooks that sheds some light on the issue. The gist is that the result of ap in a case where inputs may represent multiple values (as is the case with Observable) is implementation-dependent.

https://en.wikibooks.org/wiki/Haskell/Applicative_functors#Sequencing_of_effects

My interpretation of what I have read is that there is no absolute rule about the relationship between ap and chain. I think that the implementation of ap should be determined by use cases that are likely to be most useful, and results that are likely to be least surprising.

0reactions
rpominovcommented, Oct 8, 2018

Hm, right, in the case of one-value observables sequential ap might make sense indeed.

Let’s discuss how exactly we could fix this. I think we shouldn’t change Kefir.staticLand.Observable, maybe just add a note in the documentation about its flaw. Instead we could add new modules, say Kefir.staticLand.ObservableMonad and Kefir.staticLand.ObservableApplicative. Not sure about the names, and what exactly we should do about the methods: should we just omit ap in ObservableMonad, omit chain in ObservableApplicative, and copy all the rest from Observable?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Observable As Property Helper - ReactiveUI
The ObservableAsPropertyHelper (OAPH) is a class that simplifies the interop between an IObservable and a property on your ViewModel.
Read more >
RxJS: How to Use Interop Observables - ncjamieson
It's a package that contains observable source creators and operators to manipulate them, but observables aren't just an RxJS abstraction.
Read more >
Observable | RxJS API Document - ReactiveX
Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables. public static....
Read more >
Kefir.js 3.8.5 (changelog)
Subscribes callback to errors on an observable. If called on a property, which has a current error, callback will be called immediately (synchronously)...
Read more >
How to solve the error "Object reference not set to an instance ...
Hi @PeterFleischer-3316, I fixed the bugs by adding a static class (ContactRef) to get the Contact property in all ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found