TorosFanny
TorosFanny

Reputation: 1732

In Elm, when value under a signal has a compound type such as a list, how to efficiently update one element

I'm rather new to Elm, and I'm deeply attracted by the way Elm dealing with GUI. But after some deep thought, I find it's hard to efficiently update just one element of a list or finger tree (Just like finger tree in Haskell, if it already exists in Elm's library) which is under a Signal and the size of it also varies against time.

Specifically, to express a dynamic finger tree, we have to write

Signal [ {-the finger tree's element type-} ]

But if we want to update just one element of the finger tree efficiently, we have to write

Signal [ Signal {-the core data type-} ]

But in Elm the Signal is not a Monad, then how to flatten the two layer Signals into one layer?

Comment 1: I don't know in detail how Elm behaves in this situation. Reprocessing the whole finger tree is just my guess.

Comment 2: For example, suppose we have a signal value, marked as s, of type Signal (fingerTree Int), and the following function, marked as f, whose input is s is, for example, lift (fmap (+1)) whose type is Signal (fingerTree Int) -> Signal (fingerTree Int). And if s has just one element changed, function f has to re-do the (+1) operation for every element of s. Obviously, it's a waste of time and I'm not sure if Elm is intelligent enough to detect the immutability.

Upvotes: 3

Views: 233

Answers (1)

AndrewC
AndrewC

Reputation: 32455

TL;DR: Implement your logic/data processing as pure functions and lift them to transform signals.

The trick is to write a function processList : [elementType] -> [elementType] that provides the logic you want (check if the third element is a wibbler and change it to a wobbler or whatever you wanted to do), and then use the lift function which has type

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

like lift processList mySignalThatProducesLists to edit the data produced by mySignalThatProducesLists using processList.

The main idea here is that you encode the logic and data processing as pure functions and then use them as Signal transformers using lift. It's like Elm automatically reapplies the function every time the data in the source signal is updated.

If you're used to programming in Haskell, you can think of Signal a as a newtype wrapper around Time -> a for some opaque Time type, and lift as fmap. You don't need to have a monad to edit data.

There are also lift2 andlift3functions for lifting functions with more than one argument, so again to use a Haskell analogy, you essentially have the capabilities of an Applicative functor there.

The reason they don't have a Monad is that that imposes implementation details that reduce efficiency. It may be that there's some equivalent of ArrowApply in there that I haven't spotted (that would give you an expressibility eqiuivelent of Monad), but I'm not sure there is.

Upvotes: 5

Related Questions