New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flattening Signals? #440

Closed
micmarsh opened this Issue Jan 5, 2014 · 30 comments

Comments

Projects
None yet
@micmarsh

micmarsh commented Jan 5, 2014

Is there any way to write a function of the type Signal (Signal a) -> Signal a, to "flatten" a signal of Signals into a single Signal?

I want to use WebSocket.connect on a signal that provides the current location.host from javascript, since that varies depending on where the app is currently running. I can use lift (\url -> connect url someInputStrings) urlHost, which gives a Signal (Signal String). If there's another way to accomplish this, I'd be open to that too!

@pthariensflame

This comment has been minimized.

pthariensflame commented Jan 5, 2014

There isn't a function of the type you want, because Signal isn't a monad.

@micmarsh

This comment has been minimized.

micmarsh commented Jan 5, 2014

That's true, a monad is (simply) defined as something with a flatmap/mapcat type function, right? That would be just what I need here.

@maxsnew

This comment has been minimized.

Contributor

maxsnew commented Jan 5, 2014

Basically, yes. This question gets asked a lot, and this explanation is pretty good: #413 (comment)

@pthariensflame

This comment has been minimized.

pthariensflame commented Jan 5, 2014

A monad m is (informally) something with both a flatMap-like function (of type m a -> (a -> m b) -> m b) and a singleton-like function (of type a -> m a). Signal has the latter, but not the former; it's a less powerful kind of thing than a monad, called an applicative functor (which means that it does have a function of type m (a -> b) -> m a -> m b).

Evan's thesis details the motivation for not making Signal a monad, and does a far better job of explaining it than I ever could.

@joneshf

This comment has been minimized.

joneshf commented Jan 5, 2014

I don't think you need it to be a Monad, you should be able to get by with it being a Foldable and Applicative, I believe.

EDIT: sorry, it needs to be Foldable and Alternative, then you can write something like asum. http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-Foldable.html#v:asum, since you've already got foldp and (~), you just need a unit/empty/zero and you can do it.

@pthariensflame

This comment has been minimized.

pthariensflame commented Jan 5, 2014

@joneshf Signal isn't Foldable, because then it would also be a Monad (see this library for a demonstration of just how far that can go).

@fosskers

This comment has been minimized.

Contributor

fosskers commented Jan 5, 2014

Signals will never be a Monad and here is why

@johnpmayer

This comment has been minimized.

Contributor

johnpmayer commented Jan 5, 2014

It sounds to me that the web socket connect is not general enough. This is
a compelling use case.
On Jan 5, 2014 5:27 PM, "Michael Marsh" notifications@github.com wrote:

Is there any way to write a function of the type Signal (Signal a) ->
Signal a, to "flatten" a signal of Signals into a single Signal?

I want to use WebSocket.connect on a signal that provides the current
location.host from javascript, since that varies depending on where the app
is currently running. I can use lift (\url -> connect url
someInputStrings) urlHost, which gives a Signal (Signal String). If
there's another way to accomplish this, I'd be open to that too!


Reply to this email directly or view it on GitHubhttps://github.com//issues/440
.

@mgold

This comment has been minimized.

Contributor

mgold commented Jan 5, 2014

Yes, if possible the web socket connect should take a Signal String as its first argument. In general, functions that have both signal and non-signal arguments cannot be lifted and compose poorly.

Also, is it time to get an FAQ?

@joneshf

This comment has been minimized.

joneshf commented Jan 5, 2014

@pthariensflame oh, right foldp is not foldr

@micmarsh

This comment has been minimized.

micmarsh commented Jan 6, 2014

Thanks for all the info everyone! Monads are something I feel like I've recently just gotten the hang of, having starting to work in Scala and Elm more often, I'll definitely check out Evan's thesis and other reading material at some point.

Returning to the immediate problem, though, I agree with @mgold that WebSocket.connect should probably take a Signal for the URL, even if it doesn't make as much sense implementation-wise given how WebSocket objects work on the JS level. After I get the game I'm working on into a good place, I'd be willing to look into doing that, unless someone else feels more qualified.

@Raynos

This comment has been minimized.

Raynos commented Jan 6, 2014

There is an issues of implementing a WebSocket interface that does some kind of reconnect without using monads.

I think these types of things should be explored and seen if they can be implemented in pure Elm instead of putting all the magic in the javascript layer.

@fosskers

This comment has been minimized.

Contributor

fosskers commented Jan 6, 2014

If only we had typeclasses.

@Raynos

This comment has been minimized.

Raynos commented Jan 6, 2014

@fosskers how would typeclasses help with this problem ?

@fosskers

This comment has been minimized.

Contributor

fosskers commented Jan 6, 2014

Pardon me, it might not help with your problem here, but I imagine it allow more native Elm implementations and less JavaScript magic.

@Raynos

This comment has been minimized.

Raynos commented Jan 6, 2014

@fosskers any reference on what types of magic it makes dissappear ?

@maxsnew

This comment has been minimized.

Contributor

maxsnew commented Jan 6, 2014

@Raynos comparable, number and appendable

@fosskers

This comment has been minimized.

Contributor

fosskers commented Jan 7, 2014

Those are my main gripes. Also with typeclasses we get Functors and Applicatives and the whole lot. Signal use is classically Applicative already, so why not make it official?

@deadfoxygrandpa

This comment has been minimized.

Contributor

deadfoxygrandpa commented Jan 7, 2014

I don't think anything is suddenly possible with the addition of typeclasses that wasn't possible before, though? They can make things more concise, but I think for Functors (for example) you need higher-kinded types. Max has this library: http://library.elm-lang.org/catalog/maxsnew-Generic/0.2.1/ that has implemented monoids (although they aren't called that in the library) without typeclasses; the lack of them isn't what's preventing Functors from being added in the same way.

@fosskers

This comment has been minimized.

Contributor

fosskers commented Jan 7, 2014

I saw what max has done there and I'm quite interested.

@evancz

This comment has been minimized.

Member

evancz commented Mar 22, 2014

Okay, so the initial issue is resolved. The issues of "can WebSocket be more general?" or "what's the deal with type classes in Elm?" or whatever else should be broken up into separate issues.

For type classes, I suspect the answer has shown up on the list. The short answer is that type classes as they appear in Haskell may not be the best way to do type classes. Read this and this and look into ML's first-class modules to get some other perspectives.

@evancz evancz closed this Mar 22, 2014

@Raynos

This comment has been minimized.

Raynos commented Mar 22, 2014

@evancz for the "can WebSocket be more general?" you might want to think about a way to play around with implementing better websocket libraries that expose interfaces over ports. One of the questions that comes to mind is can you publish a js + elm port interface to elm-get ?

We should encourage people to explore these issues by just doing it and exposing a clean port interface

@evancz

This comment has been minimized.

Member

evancz commented Mar 22, 2014

I like the idea of uploading "port handlers" with elm-get, but I have not given it more thought than "it seems plausible".

@maxsnew has been experimenting with this already I believe. I think lots of things could be set up to work nicely with "port handlers" once you can send ADTs out ports.

data IO a = Read (String -> IO a) | Write String (IO a)
data Http a = Get String (String -> Http a) | ...   -- something like this
-- more
@mgold

This comment has been minimized.

Contributor

mgold commented Mar 22, 2014

This is getting off-topic, feel free to fork back to the mailing list. But...

My concern with WebSocket.connect : String -> Signal String -> Signal String is that the outgoing signal cannot derive from the incoming signal. Otherwise you'd have a signal loop. I think ports are a better solution - the incoming port sits on the top of the graph and the outgoing on the bottom. If an outgoing event causes an incoming one, Elm is non the wiser.

Your port handlers remind me (perhaps spuriously) of how Haskell did IO before monads came along. I'd refer you to the original IO monad paper if I could remember the name of it, but here is a SO post. The problem with "dialogues", as I believe they were called, was that they were hard to synchronize, and that you'd have to keep expanding the ADT as more IO methods came along. I'm sure @maxsnew knows more about this than I do. My two cents are to build JS libraries that work seamlessly with ports to keep the language small and avoid effect-related headaches in the pure language. For WebSockets, I've heard good things about socket.io.

@maxsnew

This comment has been minimized.

Contributor

maxsnew commented Mar 22, 2014

@mgold If you're interested you should check out the way https://github.com/maxsnew/IO is implemented. It uses ports to basically get something like the dialogues you're talking about, but it exposes a monadic interface to the user. That way you isolate all of the problems with deadlock/inconsistency (and I definitely encountered them) to be in library code instead of the user interface. The main problem is extensibility.

@evancz

This comment has been minimized.

Member

evancz commented Mar 22, 2014

@maxsnew, that looks really cool! I'm curious how you got the kind of problems that would have come up with the dialogue approach (described well in chapter 7 of this) when working on your approach?

Also, I've been thinking about monad transformers and the effect system in Idris. I don't see a way around having a monad transformer if you want to combine IO and Http that are mutually dependent on each other. Is this the kind of extensibility you mean?

@maxsnew

This comment has been minimized.

Contributor

maxsnew commented Mar 22, 2014

So the concept is similar to the Dialogue mentioned there but instead of using lazy lists you get 2 communicating actors, one on the Elm side interpreting the IO AST and one on the JS side that listens for requests from the port, does the IO necessary and sends messages back. This eliminates some issues that arose in that original Haskell implementation (since we have communicating processes we can't do something like try to read the next message before it arrives) but you need to be careful about which messages arrive when and how to respond to them.

As for extensibility, the issue right now is that in order to have new IO actions, you need to add them to the core IO datatype. There are approaches to making this open instead of closed, but I haven't looked into them. The only approach I can really see for sure working would be to expose eval to library writers, so they could then write JS response functions in their elm code (though good luck getting that through a security audit).

@lexwraith

This comment has been minimized.

lexwraith commented Apr 26, 2016

@pthariensflame - your link to Evan's Thesis leads to some bizarre page loaded with popups - could we get the new link and remove the old one? It currently points to:

http://www.testblogpleaseignore.com/wp-content/uploads/2012/04/thesis.pdf

@pthariensflame

This comment has been minimized.

pthariensflame commented Apr 27, 2016

@lexwraith I don't want to edit it in the interest of preserving history, but the current link is http://elm-lang.org/papers/concurrent-frp.pdf.

@lexwraith

This comment has been minimized.

lexwraith commented Apr 27, 2016

@pthariensflame Great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment