2

Is it possible to create a Signal from a List? Essentially what I want is something with the signature List a -> Signal a. I know that a Signal represents a time-varying value and so something like this doesn't actually make any sense (i.e. I can't think of a reason to use it in production code).

I could see applications of it for testing though. For example, imagine some function which depended on the past values of a Signal (via foldp for instance) and you wanted to make assertions about the state of the system given the signal had received values x, y, and z.

Note that there wouldn't have to be anything special about the Signal denoting that it only would ever receive a fixed number of values. I'm thinking of it more like: in production you have a Signal of mouse clicks, and you want to test that from a given starting position, after a given set of clicks, the system should be in some other known state. I know you could simulate this by calling the function a fixed number of times and feeding the results back in with new values, I'm just wondering if it is possible.

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
robertjlooby
  • 7,160
  • 2
  • 33
  • 45

2 Answers2

3

I guess it's possible. You use a time-based signal, and map the values from the list over it:

import Time
import Graphics.Element exposing (show)

list = [1..10]


signalFromList : List a -> Signal a
signalFromList list =
  let
    (Just h) =
      List.head list

    time =
      Time.every Time.second

    maybeFlatMap =
      flip Maybe.andThen

    lists =
      Signal.foldp (always <| maybeFlatMap List.tail) (Just list) time
  in
    Signal.filterMap (maybeFlatMap List.head) h lists

main = Signal.map show <| signalFromList list

However!

It shouldn't be hard to do testing without signals. If you have a foldp somewhere, in a test you can use List.foldl over a list [x,y,z] instead. That should give you the ability to look at the state of your program after inputs x, y, z.

Apanatshka
  • 5,958
  • 27
  • 38
2

I don't think there is any way it can be done synchronously in pure elm (Apanatshka's answer illustrates well how to set up a sequence of events across time and why it's a bad idea). If we look at how most Signals are defined, we'll see they all head down into a native package at some point.

The question then becomes: can we do this natively?

f : List a -> Signal a

I often think of (Signal a) as 'an a that changes over time'. Here we provide a List of as, and want the function to make it change over time for us.

Before we go any further, I recommend a quick look at Native/Signal.js: https://github.com/elm-lang/core/blob/master/src/Native/Signal.js

Let's say we get down to native land with our List of as. We want something a bit like Signal.constant, but with some extra behaviour that 'sends' each a afterwards. When can we do the sending, though? I am guessing we can't do it during the signal construction function, as we're still building the signal graph. This leaves us a couple of other options:

  • something heinous with setTimeout, scheduling the sending of each 'a' at an appropriate point in the future
  • engineering a hook into the elm runtime so that we can run an arbitrary callback at the point when the signal graph is fully constructed

To me at least, the former sounds error prone, and I hope the latter doesn't exist (and never does)!

For testing, your suggestion of using a List fold to mimic the behaviour of foldp would be the way I would go.

grumpyjames
  • 366
  • 1
  • 5
  • heh, yeah both of those options sound pretty horrible. Not that my `signalFromList` is much better, because you're stuck with this time signal ticking away for no reason after you've emptied the list. – Apanatshka Jul 27 '15 at 21:44