Simple explanation of fold?

Here's my attempt:

A Signal is basically a sequence of values (usually triggered by external events like user input).

In fact, the core abstraction of Elm is that your app's state is updated in response to Signals and then that new state is re-rendered.

So let's say we have a Signal numbers of type numbers : Signal Int. For instance, let's say we have 10 buttons on the screen, each button has a number 1-10 on it, and our numbers signal emits an integer each time a user clicks a button.

Signal.map is a function that lets you transform a signal:

incrementedNumbers : Signal Int
incrementedNumbers = Signal.map (\n -> n + 1) numbers

view : Int -> Html
view num = div [] [ text ("Latest click + 1: " ++ (toString num)) ]

main : Signal Html
main =
  Signal.map view incrementedNumbers

Our app will now render the value of the button the user clicked but incremented by 1.

But what if we wanted to instead render the sum of all numbers the user has clicked so far? We would need a way to transform a signal that maintains a variable that we can add something to and then return it. Just like how [1, 2, 3].reduce((n, sum) => n + 1, 0) uses sum to accumulate the sum of numbers as it iterates across the list.

This is what Signal.foldp is for. It's just like that reduce sum snippet above except it's for Signals. It returns a Signal of the latest accumulated value.

currentSum : Signal Int
currentSum = Signal.foldp (\(currNum, sum)-> currNum + 1) 0 numbers

view : Int -> Html
view num = div [] [ text ("Sum so far: " ++ (toString num)) ]

main : Signal Html
main =
  Signal.map view currentSum

foldp is basically how an Elm app works, except it's folding your update function across a Signal of Actions. Your update function takes an action and your previous state and then returns an updated state.

type Action = Increment | Decrement  

type alias Model =
  { num: Int }

initialModel : Model
initialModel = { num = 0 }

update : Action -> Model -> Model
update action model =
  case action of
    Increment -> { model | num = model.num + 1 }
    Decrement -> { model | num = model.num - 1 }

latestAction : Signal Action

latestModel : Signal Model
latestModel = Signal.foldp update initialModel latestAction

viewModel : Model -> Html

main : Signal Html
main = Signal.map viewModel latestModel

That's pretty the core Elm abstraction

/r/elm Thread Parent