Re: [elm-discuss] beginner documentation on Addresses and Mailboxes, documentation on idiomatic elm

1,213 views
Skip to first unread message

Evan Czaplicki

unread,
Jun 2, 2015, 10:03:26 PM6/2/15
to elm-d...@googlegroups.com
Can you say more about what's tough with mailboxes and addresses? What kind of challenges are you running into in code or conceptually?

This stuff is kind of new so the documentation is not fully fleshed out. Any insights you have could be helpful for doing better!

On Monday, June 1, 2015, krish <krish...@gmail.com> wrote:
Is there any beginner-friendly, haskell-ignorant, documentation for Addresses, Mailboxes and such? I am finding the Architecture tutorial to be rather heavy-going. 

Also there are tutorials and blog posts, such as elm-by-example and others. As a beginner I am a bit worried whether those tutorials and blog posts are expounding idiomatic elm.

Thanks.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Sent from Gmail Mobile

krish

unread,
Jun 3, 2015, 4:44:58 AM6/3/15
to elm-d...@googlegroups.com
Thank you Evan.

In the package documentation on signals there is no specific info on what an Address is except it being a part of Mailbox. Conceptually, i do sort of understand what this is. But I am not crystal clear about it, the forwarding mechanism and all. I guess StartApp is hiding the underlying mechanism of how all this works, how the Update function receives the actions etc.  Would an example of using Addresses directly, without StartApp, help ? I don't know. May be after a while all this will become clear.


On Wednesday, June 3, 2015 at 7:33:26 AM UTC+5:30, Evan wrote:
Can you say more about what's tough with mailboxes and addresses? What kind of challenges are you running into in code or conceptually?

This stuff is kind of new so the documentation is not fully fleshed out. Any insights you have could be helpful for doing better!

On Monday, June 1, 2015, krish <krish...@gmail.com> wrote:
Is there any beginner-friendly, haskell-ignorant, documentation for Addresses, Mailboxes and such? I am finding the Architecture tutorial to be rather heavy-going. 

Also there are tutorials and blog posts, such as elm-by-example and others. As a beginner I am a bit worried whether those tutorials and blog posts are expounding idiomatic elm.

Thanks.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Richard Feldman

unread,
Jun 3, 2015, 5:07:40 PM6/3/15
to elm-d...@googlegroups.com
Mailbox has been the most consistently confusing term I've seen newbies struggle with, for what it's worth. I get the metaphor, but unfortunately it seems to be more confusing than helpful to beginners.

Max Goldstein

unread,
Jun 3, 2015, 6:12:38 PM6/3/15
to elm-d...@googlegroups.com
I'll take a stab at the Mailbox docs. For one thing, port actions : Mailbox Action is just wrong (you wouldn't make it a port).

David Dawkins

unread,
Jun 24, 2015, 10:02:09 AM6/24/15
to elm-d...@googlegroups.com
Sorry to wake an old-ish thread, but I'm having the same issue. I could use material that explains what an Address is, how it relates to Signals, Messages, Channels, Mailboxes. 

Specifically I am trying to understand the simple [ + / - ] button example. Try to look at that example as if you didn't know what an address was, and then see what you can find out. I managed to get to the elm architecture document, and then found a clickable "Address", which took me to API docs, but it fizzles out there.

I do understand what a signal is, this is a (great) intuitive concept; a value that changes over time, or if you like, a stream of events (the edges where the value changes). A channel could be seen as a way of decoupling a signal from a consumer (why else would you need it?) - as if we were sending each event into (say) a TCPIP socket.  Address and mailbox defy my current intuition.

Many thanks all. Back to my day job (today, C# coroutines and continuations).


On Wednesday, 3 June 2015 03:03:26 UTC+1, Evan wrote:
Can you say more about what's tough with mailboxes and addresses? What kind of challenges are you running into in code or conceptually?

This stuff is kind of new so the documentation is not fully fleshed out. Any insights you have could be helpful for doing better!

On Monday, June 1, 2015, krish <krish...@gmail.com> wrote:
Is there any beginner-friendly, haskell-ignorant, documentation for Addresses, Mailboxes and such? I am finding the Architecture tutorial to be rather heavy-going. 

Also there are tutorials and blog posts, such as elm-by-example and others. As a beginner I am a bit worried whether those tutorials and blog posts are expounding idiomatic elm.

Thanks.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

BethAr

unread,
Jun 24, 2015, 1:29:25 PM6/24/15
to elm-d...@googlegroups.com
I don't find the concept of mailbox unintuitive per se, but it becomes murky when you confound it with signal - mailboxes don't handle signals, unless you can call a mailman such! I would think "station" would make a better analogy, a station could receive or transmit a signal.

Keeping with the mailbox analogy, though, I would suggest explaining that it holds the value it currently has, and that it makes that value accessible through its address. The way it gets that value is the problem, because you can't say that is by an ever growing stream of mailmen, whom somehow bring letters that build upon the contents of the letters previously dispensed. It is hard to make an analogy with e-mail as well, as we don't usually have the regularity that signals propose, unless you make an analogy with a RSS feed - which is not a bad idea altogether.

Regardless, mailboxes have intuitive features that could be taken advantage of, such as that the value they hold are useless until accessed by the consumer of the letters. To insist upon the fact that one must handle the address explicitly removes much magical reasoning, which is good in my opinion.



David Dawkins

unread,
Jun 24, 2015, 1:36:04 PM6/24/15
to elm-d...@googlegroups.com
Thanks, that gives me a little more of the puzzle. If I ever work it all out, I'm going to post a summary here, with each concept bulletpointed, and interrelated.

Matt Ho

unread,
Jun 24, 2015, 2:15:20 PM6/24/15
to elm-d...@googlegroups.com
I'll also echo the sentiment to Signals, messages, and Addresses being hard to understand.  Please take with a grain of salt that I'm new to elm and these are just the interpretations of a newbie :)

Let me give some specifics:

1. What is Signal.Address Action?

Seems like this should just be a type.  Every time I see this, I need to rethink what this is trying to say.  What's confusing is that I want to write this as:

Signal Action

I'm not sure what the address part is for.  I think what might make it less confusing (more readable) is if your examples, had a declaration like:

type Mailbox = Signal.Address Action
 
So then:

view : Signal.Address Action -> Model -> Html

Could be written as:

view : Mailbox -> Model -> Html

Which to my naive eye would read generate html from a mailbox and model.  Or even

view : Model -> Mailbox -> Html

which feels more natural still.  Mailbox -> Model makes me think that the Mailbox is someone modifying the model.

2. Why does Signal.Address Action get reduced to address when used as a variable?

Again, another one of these things that continually trips me up.  When I take a moment to understand, I get why address might be a good name, but I'll look at it at a later time and get tripped up again.  Maybe it's Signal.Address Action is a lot to digest as one block for a beginner (see issue #1).

3. How should one send messages into a signal.

I've seen a couple of examples and don't understand why these are different.  

Signal.forwardTo address (Modify id)
 
I think this is sending something to an address, but then I'm confused why sometimes I see it expressed as:

Signal.message address << UpdateField

As a sub-part to this issue.  The amount of symbolism reminds me of Scala.  What does << do in this statement?  Why couldn't I rewrite this as:

Signal.forwardTo address UpdateField

I'm sure the answer is obvious, but to a beginner, this is pretty confusing.  

4. Nouns and verbs

Lastly, I've noticed a lot of functions are named with nouns.  Sometimes they're easy to understand like view, other times not so much.  While not a huge issue, it just one additional thing that needs to be divined.  As a newbie it would help me tremendously if everything was more explicit about what it was doing.

For example:

view -> render
 
Signal.message -> Signal.deliver 

Despite the challenges, I can see the potential in elm.  Right now, it still feels challenging to grok.

Thanks!

M

Matt Ho

unread,
Jun 24, 2015, 2:22:57 PM6/24/15
to elm-d...@googlegroups.com
While I said this in a subpoint, I think it's worth while to call out explicitly.

5. Use of symbolism

As a newbie, symbolism is very difficult to deal with. Unlike normal functions, I can't easily google a symbol.  That combined with the current state of IDE support makes it very difficult to understand what is going on.  How do I look up:

:->
()
>>
<<

With things like foldp, I can always search 

Signal foldp example

Google doesn't seem to like symbol searches.

Thanks again!

M


BethAr

unread,
Jun 24, 2015, 4:53:34 PM6/24/15
to elm-d...@googlegroups.com
Hello, Matt Ho,

About your last two points:

In functional programming is usual to name functions as nouns, and sometimes best practice, because functions are the values you are dealing with. For instance, if I have a value `elephant`, and I make a function that makes it into a  `giraffe`, I will not call it  `convertToGiraffe ` as it is usual in imperative programming, I will probably call it  `giraffe`, because that is what generates and what I will be working with. However, if that function takes an argument and convert into a `giraffe`, I will probably call it `giraffeMaker`, again, as a noun. I'm certain other people are more lax on this, than I am though.

About the symbols, it is also common in function programming (at least in Haskell, which is my main programming language) to use infix operators for functions that are used frequently, and you are allowed to make your own. Haskell documentation provides its own search engine (two actually, Hoogle and Hayoo) that handles symbols just fine. Elm's creator seems to take an instance that too many symbols make the meaning of source code opaque, and I think he is right, but he provides the very basic operators that are crucial for functional programming. Reducing the amount of symbols also keeps one from having to maintain something like Hoogle, which is not trivial. With that said it is odd that the symbols for function composition (>>) are not in the syntax reference.

David Dawkins

unread,
Jun 24, 2015, 5:16:51 PM6/24/15
to elm-d...@googlegroups.com
I did some more digging. and ended up here:

http://elm-lang.org/guide/reactivity#signals  "Communicating with Mailboxes".

So - a Mailbox is fairly straightforward. It's a place where you can send values, using the Mailbox's Address. Multiple producers may exist, all targeting 
the same Mailbox.

The consumer uses the Mailbox's Signal to be notified of values being written to the Mailbox.

A Message appears to be a binding between a value and an Address, something you might create and store for while before finally
sending it. You might use Mailboxes and not need Messages.

We can think of Address as being an indirection on a Signal. We give producers an "Address a", and consumers will react to values
being sent using a "Signal a".

So - let's see if I can understand "button" now. We give the button function an Address for it to send click events to; we can listen to 
button presses by consuming the associated Signal. The Mailbox is "merely" a way to associate the Address and the Signal.

Why do we need Mailboxes? Why not create a Signal and pass that into the button function?  My best guess (and I may be remembering
something Evan wrote once, or conflating the concept of a Port) is that it's either:
a) a way of formalizing the boundary between the pure FP machinery and the outside world, or
b) a way of handling an implementation detail with UIs (which might be the same as (a))

Or both.

I'm going to see if my understanding checks out now, by playing with some examples.

Dave

David Dawkins

unread,
Jun 24, 2015, 5:38:26 PM6/24/15
to elm-d...@googlegroups.com
Here's another piece of the puzzle: there are two types of button!

I've been typing "button" into the Core libraries search page and finding "Graphics.Input" button.

However, the examples I've been looking at are using "Html.Input" button.  Finally, I can match the example with the docs.

God it feels good when the penny drops.

I can also see that we are using a single Mailbox for the HTML example; the view function we pass into StartApp.start
is passed an address that we should supply to any input elements like buttons.  StartApp.start must then be wiring a 
system mailbox's signal to the update function.

I promise to try not to post any more tonight.

:-)

Max Goldstein

unread,
Jun 24, 2015, 5:42:36 PM6/24/15
to elm-d...@googlegroups.com
David, your understanding seems right on point.

Matt, I think the big think you may be missing is that Signal is both the construct (a signal of floats, or Signal Float) and a module. As a module, its members (functions, values, and types) are denoted as Signal.thingy or for example Signal.message (the function) which produces a value of type Signal.Message (note the capital M). Neither of these are a signal of messages.

As for searching, you can search for >> on the package page. But that's not an obvious place to look.

I did indeed take a stab at writing better docs for this part of the library. I'm open to suggestions.

BethAr

unread,
Jun 24, 2015, 6:03:03 PM6/24/15
to elm-d...@googlegroups.com
Max, I think a simple policy of "if it is used in an example, it must feature in the syntax reference" would suffice.

Max Goldstein

unread,
Jun 24, 2015, 7:05:48 PM6/24/15
to elm-d...@googlegroups.com
Max, I think a simple policy of "if it is used in an example, it must feature in the syntax reference" would suffice.

Right, but technically it's not syntax. It's just a function, defined in Elm itself, in the Basics module which is imported by default. But Elm generally favors prudence over pedantry (at least by the standards of functional languages) so I see your point.

surfncode

unread,
Jun 27, 2015, 5:06:44 AM6/27/15
to elm-d...@googlegroups.com
Hello, sorry to intrude in this thread but I felt I needed to echo to what David and krish are saying.

I must say I feel equally confused concerning the Mailbox and Address concept. Before they were introduced, I was starting to feel confortable using elm but since then I have kind of paused (indefinitely) my learning of elm. From the discussions I read on this mailing list, I understand that they are an answer to some limitations of elm that Signal could not bypass alone. Although I'm still not very clear on what those are.

I'm not particulary clever (and not particulary dumb either) but it seems to me that those new concepts may make it difficult for elm to reach a critical mass of front-end devellopers who have no previous functionnal programming experience. Although I have taken an interest in haskell for the past few month, I cannot say I have real programming experience in it beside some quick experimentations with code that rarely exceeded 60 lines. I realized now, it's not enough to have the same easy grasp on Mailbox that most expericenced FP programmer on elm-discuss seem to have.

I have indeed read most of the docs about Mailbox and Address but it does not appear to be enough either. I guess the thing to do would be to dive in and start coding using them and only then, I would be able to have a better understanding of why they are usefull and how they work. It feels kind of backward to me. Maybe that's my personnality but I'm usually more confortable doing the things the other way around. When I can form a clear concept about something, I usually have an easier way using it (naturally). However forming concepts from experience works less well and I feel I usually end up with some kind of permanent "comprehension debt".

That being said, the introduction of Mailbox and Address seems to satisfy most of the other programmers so I would not presume to say they should be removed. I just wished they were not so essential for doing the basic stuff in elm and could be used as some kind of advanced feature of the language, once you mastered the Signal stuff.

surfncode

unread,
Jun 27, 2015, 6:12:28 AM6/27/15
to elm-d...@googlegroups.com
I just checked the doc (I hadn't for a while), I must say the start app package is great work ! It makes it really easy to get started without any boilerplate. I still have to check the new Task and Mailbox docs to see if there is any improvement compared to last time. I only checked shortly after the release of 0.15 so my previous post opinion colored by that.


Jason Merrill

unread,
Jun 27, 2015, 7:33:22 PM6/27/15
to elm-d...@googlegroups.com
On Saturday, June 27, 2015 at 2:06:44 AM UTC-7, surfncode wrote:
I must say I feel equally confused concerning the Mailbox and Address concept. Before they were introduced, I was starting to feel confortable using elm but since then I have kind of paused (indefinitely) my learning of elm. From the discussions I read on this mailing list, I understand that they are an answer to some limitations of elm that Signal could not bypass alone. Although I'm still not very clear on what those are.

I completely agree that as it stands, the Mailbox and Address concept is much harder to understand from the documentation than anything else in Elm. I'll give my conception of how they work, but I'll admit that I actually haven't built anything with them yet, partly because of my uneasiness with my own understanding.

I think there are at least two reasons that these concepts are hard to understand:

1. Their purpose is to encapsulate components so that they can function as a sub-part of a larger hierarchy. It's *always* hard to come up with short convincing examples that show how to encapsulate things into modular components, because simple examples with fixed requirements don't actually need modularity.

2. The need for Mailbox/Address arises partly from the fact that Elm's models are immutable, and many of us have a lot more familiarity with mutable data from previous programming experience.

Let's dive in to (2), the immutability constraint. Suppose you have a model hierarchy that looks like this:

           A
        /     \
       /       \
      B1       B2
     /  \     /  \
    C1  C2   C3  C4


A, B, and C represent different kinds of components. I should give them names, but its hard because of (1) so I'm not going to. Sorry. You can think of the C's as counters or buttons or textboxes or whatever--something that the user can interact with directly.

Then a user comes along and clicks on/interacts with C1's view, and because of that interaction, C1's model needs to be modified (say incremented if it's a counter), and we'll call the new version C1'. In a mutable world, our new hierarchy might look like this:

           A
        /     \
       /       \
      B1       B2
     /  \     /  \
    C1' C2   C3  C4


In other words, we could modify C1 in place. But in an immutable world, B1 with a different child isn't B1 anymore. It must be updated to B1', and for the same reason, A must be updated to A'. Replacing a child implies replacing its parents all the way up the tree:

           A'
        /     \
       /       \
      B1'      B2
     /  \     /  \
    C1' C2   C3  C4


Notice that the siblings of the modified component, and the siblings of its parents, may stay the same as they were before (or they may change--it ends up being the option of the parent).

Ok, so we see this action inside C1, and we know that all of its parents need to be replaced, so how should we achieve that? One way would be to have C1 have a reference to B1, and have B1 have a reference to A1, so that children could notify their parents all the way up the chain that they need to be replaced. Alternatively, maybe every node in the tree could have a reference to the root so that at any time, they could notify the root that a lineage of children needs to be replaced.

Neither of these options is very good. We don't want C1 to have a handle to all the capabilities of B1 or A, because C1 shouldn't care about most of the details of its parent. We want to allow C to function as a child of an open ended group of different kinds of parents, so it's important to limit the interface that it uses to communicate with them.

What we'll do instead is have B1 pass its Address to C1, and A will pass its Address to B. If you're my child component, I'll allow you to send a message to my address, but you can't just come to my house and use all of my things (we're strict parents, I guess). This restricted interface allows predictable reuse of components in different contexts.

There's also a type aspect that I think is harder to describe in the terms of the metaphor. As a child, you tell me what kind of messages you will send by exposing your own Action type. As a parent, if I respond to a different type of action than exactly what you send, then instead of exposing my primary address, I will make a special address just for you using Signal.forwardTo. This address knows how to map the messages sent by children into an appropriate type for the parent, and then deliver them to the parent's primary address.

If we want to stick with the metaphor, maybe I like to receive packages on wooden pallets, but my child likes to send them in shipping containers, so instead of giving the address of my warehouse to children directly, I will make a transfer station for moving packages from shipping containers to pallets, and then give my children the address of the transfer station. Metaphors are hard...

Now in Elm, we're living in the future, so we don't have to go check our Mailbox all the time--instead, whenever someone sends a message to our Address, we receive a Signal containing the message. Typically, the message from a child will contain information that will be used to replace that child with a different child (here the parent/child metaphor becomes uncomfortable...), and maybe it will suggest other ways that we as the parent need to be modified. But we don't actually replace our child just yet; instead, we wrap the message up in whatever way we choose, and then forward it to our parent.

At the top of the tree, the "main" routine will respond to receiving a message by calling "update" on the root of the model (A), and inside the root's update routine, "update" will in turn be called on whichever of its children need to be replaced, and so on down the lineage.

So to summarize, messages are forwarded all the way up the tree, then "update" functions are called all the way back down the tree, with information being summarized and put in context as appropriate at every step.

What this bureaucracy buys us over just having children take care of their own state directly is observability and comparability.

Observability: With mutable datastructures, it will often happen that in the beginning, a parent doesn't care about every little change that happens to its children. But then requirements change, and suddenly the parent takes an interest. At that point, you have to draw new arrows on the information passing diagram, which is error prone work that involves a lot of decision making. With the Elm architecture, all the arrows you should ever need are on the diagram from the start. When requirements change, components change the way they are processing information that their child was already sending, but no new paths of information flow need to be created.

Comparability: It's hard to write tests that verify that a certain sequence of actions takes a mutable data structure from one state to another. This is because there is a difference between the questions "is this the same component as it was before," and "does this component contain the same state that it did before," and that difference is subtle. Immutable components only have a single notion of equality, so if you want to test that a system ended up in the state you thought it would, you don't have to cook up different custom ways of introspecting that state for each problem. 

Elsewhere in the thread, someone asked why a mailbox needs both an address and a signal separately. Couldn't parents just pass a signal to their children, and then let the children put messages in the signal directly? I think this is a great question, and I don't really know the answer. I get the impression that almost no one else really *knows* the answer either.

One thing that I can think of is that maybe we only want to expose the ability to write to the signal to children, not the ability to read from it.

Just because I give you my address doesn't mean I want you to be able to read all my mail. But do note that when we enforce constraints like this, the issue isn't actually security, as it would be for physical mail, but rather comprehensibility. It's incredibly useful when you're approaching a new code base to have some explicit guarantees about the direction and topology of data flow, because the source code itself typically doesn't exactly paint that picture in bold. Constraints are similarly important for maintainability, because whenever you expose a capability that shouldn't actually be used, you can pretty much guarantee that in a few months someone (probably you...) will stumble into that part of the code in a fog and use the capability anyway to get out of a pinch. And then no one will understand the design anymore, because the code won't have been designed, it will have evolved.

I do get the impression that there is also some other important issue here, ...something, something loops in the signal graph...

Anyway, I should definitely conclude. I hope, but somewhat doubt, that someone else will find it as useful to read this as I did to write it.

Max Goldstein

unread,
Jun 27, 2015, 11:06:06 PM6/27/15
to elm-d...@googlegroups.com
Couldn't parents just pass a signal to their children, and then let the children put messages in the signal directly?

If all you have is a signal, you can't just put messages in it. One, it wouldn't make sense semantically for any part of the program to, say, claim they saw the mouse move. Signals that aren't associated with a mailbox have to come from somewhere. Two, putting an event on a signal is an impure action. (Even creating a mailbox is impure. Create two with the same initial value and the signals aren't the same.)

Elm has a three ways of handling that impurity. One, you can make a message. This is like an envelope that already has the address filled out and the letter inside, but it isn't sent yet. Creating a message is pure; sending it is not. That's why the functions in Graphics.Input take a message (or a function to produce one). The impure sending happens in DOM callbacks, sort of.

The second way is to pass around the address. This is very similar to using messages, except a little less abstract. The HTML library does a lot of this and arguably it should take a message instead. My SocketIO library uses this strategy but uses the addresses to create tasks.

Much like a message, a task is used to separate the specification of an impure action from actually doing it. Unlike messages, which can only send type-correct values to signals, a task can do literally anything. Messages are a way to restrict this. Anyway, you can create a task to send a value using send in the Signal library. To actually run this task, you have to send it out a port, which makes it very clear something impure is happening.

David Dawkins

unread,
Jun 29, 2015, 5:45:03 AM6/29/15
to elm-d...@googlegroups.com


On Sunday, 28 June 2015 04:06:06 UTC+1, Max Goldstein wrote:
Couldn't parents just pass a signal to their children, and then let the children put messages in the signal directly?

If all you have is a signal, you can't just put messages in it. One, it wouldn't make sense semantically for any part of the program to, say, claim they saw the mouse move. Signals that aren't associated with a mailbox have to come from somewhere. Two, putting an event on a signal is an impure action. (Even creating a mailbox is impure. Create two with the same initial value and the signals aren't the same.)


Right. The implication here is that creating a signal involves providing a source for the signal. You cannot create a signal that does not have a source. Given that, it follows that there is no way to send values into the signal (because there is no need - the source is baked-in at creation time). 

So, this is why Mailbox exists; it gives us the ability to create a Signal whose Address can indeed be handed around to various parts of the framework for them to post value updates. Mailbox is simply an association between an Address and a Signal. 


Matt Ho

unread,
Jun 29, 2015, 2:08:25 PM6/29/15
to elm-d...@googlegroups.com
These are some fantastic comments and go along way to clearing up the relationship between Signal, Mailbox, and Action.  

However, I would suggest the fact that the confusion happens so often and that these comments are required to understand Signal, Mailbox, and Action might be an indicator that the metaphor might need to be revisited before Elm becomes something that will attract a significant number of developers.

For me the heart of it lies with Signal and Mailbox.  These feel like two distinct metaphors being mixed.  When I think of Mailbox, I would imagine words like: message, envelope, deliver, send, postman, postbox, etc.  When I think of Signal, I think of words like event, processor, receiver, fork, boost, etc.  My trouble starts because Signal and Mailbox have no inherent relationship.

M

Jeff Smits

unread,
Jun 30, 2015, 7:04:54 PM6/30/15
to elm-discuss
Evan picked the term mailbox from concurrent systems theory (also used in, for example, Concurrent ML). Looks like this term may not be the most intuitive though.

Luis Arias

unread,
Jul 1, 2015, 1:37:18 PM7/1/15
to elm-d...@googlegroups.com
The word Mailbox is also a stumbling block for me as a beginner.  If was thinking maybe a word like Endpoint would create less tension than Mailbox.  To me it more aptly designates the capability of receiving a message via it's Address and one can imagine an endpoint providing a Signal of values having been sent through it.  Endpoint seems more coherent to me conceptually (if I understood correctly), again as a beginner.  I think I remember reading some discussion about Loopback earlier on, was it for this same concept too?  That seems like a great analogy too although I think I remember that it was also throwing people off.

Luis

Texas Toland

unread,
Jul 5, 2015, 3:27:11 AM7/5/15
to elm-d...@googlegroups.com
Mailbox.signal strikes me odd too.

I don't find the concept of mailbox unintuitive per se, but it becomes murky when you confound it with signal - mailboxes don't handle signals, unless you can call a mailman such!
 
I think an email analogy works better than the physical post. Would outbox/inbox make more sense to anyone else:
send messages to your outbox and receive them back in your inbox?

Richard Feldman

unread,
Jul 5, 2015, 8:00:36 PM7/5/15
to elm-d...@googlegroups.com
I don't think the Mailbox metaphor is worth trying to fix. The reasoning behind it made sense, but the results are in and empirically it's been overwhelmingly more confusing than helpful. I think the experiment is over and it's time to start from scratch and try a new way to communicate this idea.

One of the things that I've seen a lot of people struggle with is the term Address. The way it's used in practice seems at odds with the name. Consider:

view : Address Action -> Model -> Html

The phrase "what is an Address of Actions for?" is something I've heard on several occasions. It's a reasonable question, as it doesn't 

I think a better term would be Dispatcher. Compare:

view : Dispatcher Action -> Model -> Html

It's a Dispatcher of Actions, which makes sense because it lets you dispatch Actions to a Signal.

I think this would yield a lot more intuition, especially for JS users who have used Facebook's Flux architecture, which uses the term Dispatcher for the equivalent role in that pattern: https://facebook.github.io/react/img/blog/flux-diagram.png

Then the question becomes: what do you call a value that contains both a Dispatcher and a Signal?

type alias Something a = {
    signal
: Signal a,
    dispatcher
: Dispatcher a
 
}

Richard Feldman

unread,
Jul 5, 2015, 8:07:32 PM7/5/15
to elm-d...@googlegroups.com
Oops, clipped the end of that sentence. Should have been:

The phrase "what is an Address of Actions for?" is something I've heard on several occasions. It's a reasonable question, as it doesn't describe its own purpose so much as how it fits into the container type (Mailbox). The trouble is, you frequently end up using a Mailbox once, while using its Address all over the place. As such, it seems better to prioritize making Address self-descriptive rather than naming it based on how it relates to its (often throwaway) container.

Texas Toland

unread,
Jul 5, 2015, 11:39:15 PM7/5/15
to elm-d...@googlegroups.com
It's a Dispatcher of Actions, which makes sense because it lets you dispatch Actions to a Signal.

I'm on board with this. The only caveat is its complement would be Observable instead of Signal. Signal (from QT) or Pipe are the only similar names I'm familiar with for our Mailbox that describe observer IO. 

David Dawkins

unread,
Jul 6, 2015, 2:16:49 AM7/6/15
to elm-d...@googlegroups.com

A SignalDispatcher.

--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/J5dBfWJoLoQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.

Luis Arias

unread,
Jul 6, 2015, 6:07:44 AM7/6/15
to elm-d...@googlegroups.com
I like the rationale for Dispatcher very much. Great idea!

Luis

Max Goldstein

unread,
Jul 6, 2015, 11:00:18 AM7/6/15
to elm-d...@googlegroups.com
Personally I find the name "dispatcher" to be completely non-intuitive. The best proposal I've seen so far is inbox and outbox. That might fail if people think of the email inbox, where stuff sits rather than where they send stuff. However, I do like the idea of not holding the "signal" field sacrosanct and seeing if we can rename both to come up with something better.

Jeff Smits

unread,
Jul 6, 2015, 7:10:49 PM7/6/15
to elm-discuss

Perhaps it would be clearer to not name some abstract “Address” thing but instead just give a function?

type alias Dispatcher a = 
    { writeTo : a -> Message
    , received : Signal a 
    }

(names are random picks from suggestions, can be different)

Now you don’t need message : Address a -> a -> Message.

forwardTo : Address b -> (a -> b) -> Address a gets replaced by simple function composition, which is less magical:

type Action = Undo | Remove Int

port actions : Dispatcher Action

removeAddress : Int -> Message
removeAddress = 
    actions.writeTo << Remove

send : Address a -> a -> Task x () can be replaced by send : Message -> Task x ()

Does this simplified API give inspiration for better names?

On Mon, Jul 6, 2015 at 8:00 AM, Max Goldstein <maxgol...@gmail.com> wrote:

Personally I find the name "dispatcher" to be completely non-intuitive. The best proposal I've seen so far is inbox and outbox. That might fail if people think of the email inbox, where stuff sits rather than where they send stuff. However, I do like the idea of not holding the "signal" field sacrosanct and seeing if we can rename both to come up with something better.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Sebastian Graf

unread,
Jul 6, 2015, 7:21:54 PM7/6/15
to elm-d...@googlegroups.com

Building on the pipe idea:

type alias Pipe a =
    { out : EventSource a
    , in : EventSink a
    }

An event bus analogy:

type alias Bus a =
    { signal : Signal a
    , arbiter : Arbiter a -- this is hard
    }

Honestly I find something to the point (Pipe or EventRouter) better than a neat analogy (Bus). It’s not pretty, but it’s clear what it does.

Texas Toland

unread,
Jul 6, 2015, 7:31:10 PM7/6/15
to elm-d...@googlegroups.com
Building on the pipe idea:

Wow your Pipe is my favorite so far! I'm familiar with it from an old ActionScript project for routing between app modules.

Richard Feldman

unread,
Jul 6, 2015, 8:46:22 PM7/6/15
to elm-d...@googlegroups.com
One thing about the current API has going for it is that you can give something the ability to send to a signal without giving it the ability to read from that Signal.

To be fair, though, I'm honestly not sure how useful that is in practice. It hasn't really come up for me so far, so +1 for exploring this API!

Max Goldstein

unread,
Jul 6, 2015, 10:38:36 PM7/6/15
to elm-d...@googlegroups.com
Richard, I think the pipes/writeTo idea still allows you to pass around just the writeTo function. I think it's a nice property to have.

I'd like to explore names a little more but I really like the pipes idea as well. It means Message isn't hanging on to the API by one function. And I love how the really wacky forwardTo ("it's like map but switched, huh?") disappears entirely.

Richard Feldman

unread,
Jul 6, 2015, 10:57:04 PM7/6/15
to elm-d...@googlegroups.com
Ah, good point! That's interesting...so then I guess your view definition would look something like this?

view : (Action -> Message) -> Model -> Html
view sendAction model
= ...

Richard Feldman

unread,
Jul 6, 2015, 11:02:07 PM7/6/15
to elm-d...@googlegroups.com
Oh wow, if you use the term "dispatch" for the Action -> Message argument, that actually makes event handlers read very cleanly:

view : (Action -> Message) -> Model -> Html

view dispatch model
=
 
button [class "load-more"] [onClick dispatch LoadMoreResults]

Richard Feldman

unread,
Jul 6, 2015, 11:03:41 PM7/6/15
to elm-d...@googlegroups.com
Or rather, to give an example that would actually compile... ;)

view : (Action -> Message) -> Model -> Html
view dispatch model
=

  button
[onClick dispatch LoadMoreResults] [text "Load More Results"]

But yeah, that reads very nicely!

Luis Arias

unread,
Jul 7, 2015, 2:00:53 AM7/7/15
to elm-d...@googlegroups.com
Indeed!
--
"Think like a fundamentalist but code like a hacker" - @headinthebox

Maxime Dantec

unread,
Jul 7, 2015, 2:12:01 AM7/7/15
to elm-d...@googlegroups.com
That's really clean !

Matt Ho

unread,
Jul 7, 2015, 1:41:51 PM7/7/15
to elm-d...@googlegroups.com
+1 for dispatch.  Way easier to understand as a newbie

M

surfncode

unread,
Jul 8, 2015, 3:34:41 AM7/8/15
to elm-d...@googlegroups.com

+1 too for dispatch. The examples look great !

Sandeep Datta

unread,
Jul 25, 2015, 2:56:13 PM7/25/15
to Elm Discuss, eva...@gmail.com
Any news on this? The architecture tutorial is very hand-wavy as it stands now. Major chunks of code missing, explanations for important concepts like addresses and mailboxes are also missing etc

On Wednesday, 3 June 2015 07:33:26 UTC+5:30, Evan wrote:
Can you say more about what's tough with mailboxes and addresses? What kind of challenges are you running into in code or conceptually?

This stuff is kind of new so the documentation is not fully fleshed out. Any insights you have could be helpful for doing better!

On Monday, June 1, 2015, krish <krish...@gmail.com> wrote:
Is there any beginner-friendly, haskell-ignorant, documentation for Addresses, Mailboxes and such? I am finding the Architecture tutorial to be rather heavy-going. 

Also there are tutorials and blog posts, such as elm-by-example and others. As a beginner I am a bit worried whether those tutorials and blog posts are expounding idiomatic elm.

Thanks.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Sent from Gmail Mobile

Max Goldstein

unread,
Jul 25, 2015, 3:19:45 PM7/25/15
to Elm Discuss, eva...@gmail.com, datta....@gmail.com
I wrote it up in this proposal. Evan said he's doing some research on a related idea and isn't ready yet.

Sandeep Datta

unread,
Jul 25, 2015, 4:18:11 PM7/25/15
to Max Goldstein, eva...@gmail.com, Elm Discuss

Hey Max, thanks for the link. Can u help me understand the significance of mail boxes? Why do we need them at all? Can't you use a signal without a mailbox?

David Dawkins

unread,
Jul 25, 2015, 5:23:19 PM7/25/15
to Elm Discuss, maxgol...@gmail.com, eva...@gmail.com, datta....@gmail.com
Hi Sandeep,

Here's my understanding, copied from earlier in this thread:

Couldn't parents just pass a signal to their children, and then let the children put messages in the signal directly?

If all you have is a signal, you can't just put messages in it. One, it wouldn't make sense semantically for any part of the program to, say, claim they saw the mouse move. Signals that aren't associated with a mailbox have to come from somewhere. Two, putting an event on a signal is an impure action. (Even creating a mailbox is impure. Create two with the same initial value and the signals aren't the same.)


Right. The implication here is that creating a signal involves providing a source for the signal. You cannot create a signal that does not have a source. Given that, it follows that there is no way to send values into the signal (because there is no need - the source is baked-in at creation time). 

So, this is why Mailbox exists; it gives us the ability to create a Signal whose Address can indeed be handed around to various parts of the framework for them to post value updates. Mailbox is simply an association between an Address and a Signal. 

Sandeep Datta

unread,
Jul 26, 2015, 12:39:51 AM7/26/15
to David Dawkins, Max Goldstein, Evan Czaplicki, Elm Discuss

What if we just forego the option of creating new signals from scratch? The Elm run time should be the interface to the outside world and how it creates the signals should not be visible to the application. All you should be able to do in your applications is just take existing signals, transform and combine them using things like map and fold to create new signals. If you need to pass a new signal around just pass the composed/transformed entity (higher order function?) instead. Would you still need a mailbox for this?

Max Goldstein

unread,
Jul 26, 2015, 9:22:57 AM7/26/15
to Elm Discuss, david....@gmail.com, eva...@gmail.com, datta....@gmail.com
The need to explain this indicates a failure of documentation. This is a pretty basic concept, and the fact that it's not taking means Elm has work do do in how it communicates.

Mailboxes are meant to be used with Graphics.Input, which makes checkboxes, buttons, dropdowns, and the like. The other fundamental concern is that you can't have signals of signals. Any function that takes non-signal arguments and produces a signal is not compatible with Signal.map, so such functions should be avoided. (I think the only example in core is Time.fps, which in practice is not a problem.)

So because of this, let's say my library had an interface like

checkbox : Bool -> (Element, Signal Bool)

(We get away using an Element not a Signal Element because checked an unchecked boxes have the same size. Don't worry about that too much.) If I have a fixed number of checkboxes, this is fine. But if I have a Signal (List Bool) that I want to display as checkboxes, this won't work.

But let's say I did have a fixed number of checkboxes. I List.map this function over those, and now I have a list of pairs of signals. The pairs aren't a problem, but I'd have to do a List.indexedMap over the signals of booleans just so I could tell which checkbox was checked. Then I'd have to merge them all together. That's a mess.

To use a different example, what if I want to perform an action on hover. About 18 months ago, the API was

hoverable :  Element -> (Element, Signal Bool)

Let's say we're making a menu system and the element we want to make hoverable may not exist initially. Then we'd have to Signal.map this, and we're left with a signal of signals. But with mailboxes we have

hoverable : (Bool -> Message) -> Element -> Element

This function uses its first argument to turn the hover status, a boolean, into a message, and then perform the imperative action of sending the message when the hover occurs. Because there are no signals, we can Signal.map over this ourselves if we like. This means there might be an arbitrary number of elements all sending their hover info to the same mailbox, but just one exists at a time. There's an implicit Signal.merge here, and since the function can create any message is likes, that takes care of uniquely identifying the hover, which is what we used List.indexedMap for above.

The only problem is, what's a message? A message is a value and a signal that it can be sent to. Creating a message doesn't actually send the value to the signal. The runtime does that for you.

So, how do you create (a function that creates) a message? In the dispatcher proposal, the equivalent of a mailbox would be a record with an (a -> Message) value, ready to use. If the types didn't line up, you can use ordinary function composition to add the right transformation, a job very clumsily handled by forwardTo in today's library. Finally, to actually get the (a -> Message) function in today's library, you need to use Signal.message myMailbox.address. I think this is unnecessary, which is why my proposal is to eliminate the Address abstraction in favor of the Message abstraction that all libraries either use or could use, and be simpler for it.

For example, in elm-html

-- current
onKeyUp : Address a -> (Int -> a) -> Attribute
-- proposed
onKeyUp : (Int -> Message) -> Attribute

The neat trick here, the one that eliminates polymorphism, is that the message holds both the address and the value to send, which must be of the same type. If we know that is true of any message, then the runtime doesn't need to keep track of the type, and it doesn't need the type to actually send the message.

Evan Czaplicki

unread,
Jul 29, 2015, 7:52:06 PM7/29/15
to Max Goldstein, Elm Discuss, david....@gmail.com, datta....@gmail.com
Someone who has written a lot about this in this thread, write a blog post explaining things.

I wonder how much it'd help to just have a really nice tutorial we can point people to. Maybe go through the role of it in the CounterPair example. Also try to figure out what exactly folks are asking here and address that directly. What was the moment where they felt confusion? Find that and make it not happen.

Evan Czaplicki

unread,
Jul 29, 2015, 8:01:45 PM7/29/15
to Max Goldstein, Elm Discuss, david....@gmail.com, datta....@gmail.com
One other thing, priming is a powerful tool.

If you start a blog post with "let me explain a confusing thing" you are dooming yourself. Just explain the logic of it so when someone googles "elm address" they get something that walks them through understanding the current API and feeling like it's nice and they have a good handle on it.

I think the docs are better now, but I need to do a major release of core to get it out there. I'll start a thread about that I guess.

Max Goldstein

unread,
Jul 29, 2015, 11:16:30 PM7/29/15
to Elm Discuss, david....@gmail.com, datta....@gmail.com, eva...@gmail.com
I might give a blog post a try, but since -- in my opinion -- the unwrapped "dispatcher" abstraction is so much better, I might not be able to do it justice.

As for docs, I've made this PR which will hopefully fix the worst misinformation without adding anything that might make you hesitant to merge.

Max Goldstein

unread,
Jul 30, 2015, 12:42:05 PM7/30/15
to Elm Discuss, david....@gmail.com, datta....@gmail.com, eva...@gmail.com, maxgol...@gmail.com
Alright, I wrote the blog post. Hopefully things make more sense after reading it.

Evan Czaplicki

unread,
Jul 30, 2015, 4:49:25 PM7/30/15
to Max Goldstein, Elm Discuss, David Dawkins, Sandeep Datta
Awesome, thank you Max, I think it is very well done!

(And having "Elm 0.15.1" at the top is a really nice touch, great idea!)

Mike Clark

unread,
Jul 30, 2015, 5:50:44 PM7/30/15
to Elm Discuss, david....@gmail.com, datta....@gmail.com, eva...@gmail.com, maxgol...@gmail.com
This is great, Max! Thanks for taking the time to write this up.

Max Goldstein

unread,
Aug 3, 2015, 10:02:50 AM8/3/15
to Elm Discuss, david....@gmail.com, datta....@gmail.com, eva...@gmail.com, maxgol...@gmail.com
Thanks Evan and Mike! I just added another section, Handling Dynamic Data. I had mentioned that the old way couldn't do this, but I hadn't really addressed how to do it in the new way until now.

Brian Bugh

unread,
Aug 14, 2015, 10:18:12 AM8/14/15
to Elm Discuss, david....@gmail.com, datta....@gmail.com, eva...@gmail.com, maxgol...@gmail.com
Thanks Max, this was super helpful. 

Also, whoever brought up "Address" being akin to "Dispatcher" was hugely helpful. I finally get that part now, thank you.
Reply all
Reply to author
Forward
0 new messages