Extracting data from a signal

I have a signal like this: signal1 = Signal.constant {a=4, b=3, l = []}


How to extract data from a signal? I tried Signal.map (\x -> x) signal1

but it Signal.map

returns a different signal.

+2


source to share


2 answers


If while programming in Elm you have questions such as:

  • "how to extract a value from a signal?"
  • "how can I change this variable to a different value?"
  • "where do I put foldp

    and what arguments should I pass?"

you should read The Elm Architecture and try to implement your code along the way. Seriously, any novice Elm programmer should diligently go through this tutorial from start to finish, as it will eliminate most of the confusion.

However, I will give a simplified summary - remember, I am omitting a lot of details and complexities. If you've read the tutorial, you probably understand how a typical Elm program is structured. Most Elm programs have 3 main parts: model, update and preview.

The model contains initial values ​​for all your program data and their type definitions. The update takes an event and a model and returns the modified model based on the event. The View takes the model (whatever stage it is at the moment) and draws it on the screen, in other words, it returns Element

.

In a simple program, you can immediately display all of your signals without storing intermediate state, simply by applying Signal.map

to the render and signal. Below, the function show

plays the role of your primitive representation. You are not using any models or updates because you are immediately rendered whenever a mouse signal emits a new event.

import Graphics.Element exposing (Element, show)
import Mouse
import Signal exposing (Signal, map)

main : Signal Element
main = map show Mouse.isDown

      

But if you want to maintain state between events , you must use foldp

, either directly or through some higher level abstraction. By the state I mean your model changed by successive applications of your update function. At any moment, your model is in a certain state. Yours main

usually looks something like this:

main = map view (foldp update model signal)

      

main

the function is always of type Signal Element

- there are exceptions, but behind the scenes they still get converted to Signal Element

. Whatever you do with your data, code, and functions, at some point you have to combine it all into something like Signal Element

, which will become the body of your function main

.

Typically, a model is a record with many fields, any of which can also be records. Usually the update is of type Event -> Model -> Model

, where Model

is the type of your model, and Event

is what emits your final signal. Typically, the view is of type Model -> Element

. (Type names don't have to be Event

and Model

, I'm using them as placeholders in this example).

You cannot extract values ​​from a signal, this is intentionally not possible in Elm. Instead, you raise the function in context Signal

using Signal.map

. All manipulations with the values ​​emitted by the signal are performed in the context Signal

using functions that are hoisted into it. Suppose you have a Signal

type Signal Event

. Then it foldp update model signal

will have a type Signal Model

, because it foldp

has a type:



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

      

If your view function has a type Model -> Element

, it map view (foldp update model signal)

will have a type Signal Element

.

main

has a type Signal Element

, so it map view (foldp update model signal)

can be a body main

.

import Graphics.Element exposing (Element, show)
import Mouse
import Signal exposing (Signal, foldp, map)

type alias Model = Int
model : Model
model = 0

update : () -> Model -> Model
update event model = model + 1

view : Model -> Element
view model = show model

main : Signal Element
main = map view (foldp update model Mouse.clicks)

      

Above is a very simple program that accumulates mouse clicks. We have a dummy event and our model is an integer. How does the function work Signal.map

? It is of type:

map : (a -> b) -> Signal a -> Signal b

      

Requires a normal function that converts a value to another value and takes a signal of the first value to get a signal of the second value. Suppose you have many different signals, they emit values ​​corresponding to mouse clicks, key presses, timed events, HTML input fields, all kinds of stuff. You manipulate these signals in any way you want, but at some point you have merge

them into one final signal with a type Signal Something

(where something corresponds to a complex data type containing all the input data required by the program).

Since you must have a function main

, at some point you will need to convert your final signal to Signal Element

, so at some point you will need to map (hoist) a function of type Something -> Element

over Signal Something

to get Signal Element

. Why is this called lifting? Due to partial application, these 2 type definitions are Signal.map

equivalent:

map : (a -> b) -> Signal a -> Signal b
map : (a -> b) -> (Signal a -> Signal b)

      

You are bringing a normal day-to-day type function a -> b

into context Signal

so that it can work with value signals, not just values. Here's a more complex example that accounts for both seconds and mouse clicks:

import Graphics.Element exposing (Element, show)
import Mouse
import Signal exposing (Signal, foldp, map, merge)
import Time exposing (Time, fps, inSeconds)

type alias Model = { clicks : Int, time : Int }
model : Model
model = { clicks=0, time=0 }

type Event = Seconds Int | Mouse ()
update : Event -> Model -> Model
update event model = case event of
  Seconds time -> { model | time <- model.time + time }
  Mouse () -> { model | clicks <- model.clicks + 1 }

view : Model -> Element
view model = show model

timeSignal = Seconds << round << inSeconds <~ fps 1
mouseSignal = map Mouse Mouse.clicks

signal : Signal Event
signal = merge timeSignal mouseSignal

main : Signal Element
main = map view (foldp update model signal)

      

Now, hopefully, you have a basic understanding of how Elm programs are structured and how to handle events emitted by signals and change your data from event to event. Now you can extend the above program by adding more signals, making your model more complex and making your viewing more attractive.

+4


source


This is intentionally nearly impossible because you don't need to.

Why? Well, it might help to look at one possible signature for the main one in an Elm app:

main : Signal Element

      

Here we are declaring that the type of our program is an element signal; this means that our program is an element that changes over time. The runtime Elm will sort the "time shift" bit for us if we let it know which signals we care about (by referencing them) and how to connect them (using a map, foldp, etc.).



If you are trying to access an internal value in order to display it as part of your application, the correct way is to use this basic signature and allow Elm to unwrap the signal.

If you just want to see the value at runtime (e.g. in the console log), take a look:

http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Debug

+1


source







All Articles