Some people prefer to think of foldp as some sort of time machine. To "create a past-dependent signal" or "step time forward" or "apply over a list of events". To me foldp is just simply memory. Every time you need to go from one thing to another thing, you need to change the thing is which getting remembered.

Let's first look at how to define an initial state in javascript and elm.

var foo = true;


and in elm:

foo = True


Ok and now you want to change foo to false, in javascript just assign it again

var foo = true;
foo = false;


and done, easy. But what about elm? Since it's a functional language which doesn't know assignments, you can not do this

foo = True
foo = False


In javascript putting two things below each other is a sequence. In elm these are just function declarations and you don't know when they can occur (without knowing the context). And a function can do only 1 thing, it can not both return True and False at the same time.

Let's take a look at foldp function signature first

foldp : (a -> state -> state) -> state -> Signal a -> Signal state


or rather this might make it more understandable

foldp : updateFunction -> defaultValue -> triggerSignal -> outputSignal


Let's start with the outputSignal first. This is the value you can use as the result of your memory. In other words if you needed foo somewhere (which changed from true to false) you can use it's outputSignal to get that changing value.

Then the defaultValue, this is the initialization value for when a change has not occured yet. In our case True, easy.

Then the triggerSignal. This one is used to determine when to change the value to another one. It's actually rare two write sequences like

var foo = true;
foo = false;


Why would you want to first change it to true and then to false right away? Most of the time you only want to it change on the occurrence of an event. Like a user mouse click. How to do mouse click events and the likes are outside the scope of this post. However let's imagine the user had two buttons one with true and one with false. In that case it would be useful to send this value along with your triggerSignal so it can be used for foldp.

And lastely the updateFunction with it's signature

a -> state -> state


It's a function that takes the value of your triggerSignal as first argument. foldp magically supplies the old value as second argument. In the case the foldp was never triggered before this would be the defaultValue. The function is supposed to return the new value which you want. By using a pure function it becomes more obvious that we are not just setting and getting a variable. Rather we describe how to get from one immutable state to another one.

Often you don't care what the previous value was and you just want to set a new one, you can do this:

(\a _ -> a)


or you want to toggle between true and false. Then the value is ONLY dependent on the previous one and not override it to a specific value.

update _ s = case s of
True -> False
False -> True


More complex function determine the new state both on the previous state and the new value. It's conceptually the same as a Finite State Machine.

# Memory scope

Startapp uses foldp to not just change the state of a boolean (like in the examples above), but often a big record with a lot of fields in it (the model). This application model also frequently serves as memory for used modules.

When you have a part of your app, like a widget, you can tie it in with the state (memory) of your overall application. The Counter module can be regarded as a small widget which gets reused in CounterPair. It's tied in at various places, in the update function, the model and so on.

However this is not always necessary or wanted. Sometimes you don't need to communicate with the rest of your application. Maybe you have a couple of widgets that can function on their own. They can have memory, do http requests or do native ports on their own. If the requirement of sharing memory between widgets is not there, you shouldn't just tie stuff together.

Let's look at an example of to create a more localized use of memory without having to create an entire module for it. We start off with a little piece of jQuery that uses a button click to change it's size.

<style type="text/css">
button {
font-size: 12px;
}
</style>

<button>Size me</button>

<script type="text/javascript">
$('button').on('click', function() { if ($('button').css('font-size') === '12px') {
$('button').css('font-size', '20px'); } else if ($('button').css('font-size') === '20px') {
\$('button').css('font-size', '12px');
}
});
</script>
html

The code is not refactored well, but will be closest to the elm version of it.

elm
import Html exposing (button, text)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick)

box = Signal.mailbox "128px" -- mailbox value is not getting used

view size = button [ onClick box.address size
, style [("font-size", size)]
]
[text ("Size me")]

update size _ = case size of
"12px" -> "20px"
"20px" -> "12px"

memory = Signal.foldp update "12px" box.signal

main = Signal.map view memory


This elm code indeed does use foldp to memorize the size of your button. But it's still very similar to startapp and does not really feel "local". In fact there is only one memory here so there is no separation between "application memory" and "button memory". Eventually you should end up with at least two foldp functions to seperate those memories. First let's move a bunch of stuff in function scope of the view.

view = let box = Signal.mailbox "128px"

subView size = button [ onClick box.address size
, style [("font-size", size)]
]
[text ("Size me")]

update size _ = case size of
"12px" -> "20px"
"20px" -> "12px"

memory = Signal.foldp update "12px" box.signal

in Signal.map subView memory

main = view


It now becomes more obvious that our original view can serve as a subView. No magic here .. all which was done was move functions and rename view to subView. main = view is of course redundant but it's put there to make it explicit that you can now introduce more signaling on your main function (just like in startapp).

In case you want to repeat this pattern of localized memory more often, let's introduce as final step a function that takes care of the boilerplate code so you only have to write the code that is specific to your app.

memReplace default update view = let box = Signal.mailbox default
state = Signal.foldp (\x _ -> update x) default box.signal

view = let default = "12px"

update size = case size of
"12px" -> "20px"
"20px" -> "12px"


Notice that the memReplace does not care about the previous state of your memory. That's why it is named memReplace for just replacing memory. The last piece of code is exactly the same as the code before that, only everything is moved around. If you find this difficult to understand try it yourself, it will be a valuable skill in working with elm in general. Also if you want different kind of local memory functions, with different features (like doing something with the previous state), try to construct them yourself. It's not that hard and once you understand this stuff you understand a very important part of the language.