Semantics of temporal data

Hello all, I wrote a Temporal datatype data Temporal a = Temporal { td :: a, -- "temporal default" tc :: [Change a] -- "temporal changes" } deriving (Eq, Show) data Change a = Chg { ct :: Time, -- "change time" cv :: a -- "change value" } deriving (Eq,Show) I got into semantic trouble when trying to write "join" for Temporal (Temporal a). If I have a Temporal Temporal, then each change's value is a Temporal. The question is: what significance does the temporal default have? In my implementation, when I look at this Chg t0 (Temporal default0 changes0) Chg t1 (Temporal default1 changes1) --<-- you are here Chg t2 (Temporal default2 changes2) I accept the changes1 which are >= t1 and less than t2. So far so good. But I also take the default1 and prepend it to the resuling list of changes with a change time of t1 (unless the first of the changes1 occurs also at t1). But by comparing results with a handwritten <*>, QuickCheck revealed that this is not in line with <*> = ap x >>= f = join $ fmap f x It appears to me that the defaults of the inner Temporal lose most of their meaning. The effective default is the change value of the last accepted change from the previous (t0) iteration. This would make some sense. If I have a summer schedule which lists the location of a single train over time, and it sais it is usually "nowhere", but at July 1st is shall be in Manchester. If I ask this schedule, where the train will be before July 1st it'll say "nowhere". Now if I prepend the summer schedule with a spring schedule, then there will be a last location of that train in the spring schedule (say Brighton), i.e. before the summer schedule becomes effective. Hence at the beginning of the summer, the train won't be "nowhere" but in Brighton. Does this make some sense? Please feel free to comment. BTW: I am really impressed that haskell pointed out this semantic issue to me. This could have gone unnoticed for months in other languages.

On 30/03/2015 at 22:23:17 +0200, martin wrote:
Hello all,
I wrote a Temporal datatype
data Temporal a = Temporal { td :: a, -- "temporal default" tc :: [Change a] -- "temporal changes" } deriving (Eq, Show)
data Change a = Chg { ct :: Time, -- "change time" cv :: a -- "change value" } deriving (Eq,Show)
I got into semantic trouble when trying to write "join" for Temporal (Temporal a).
It appears to me that the defaults of the inner Temporal lose most of their meaning. The effective default is the change value of the last accepted change from the previous (t0) iteration.
Does this make some sense? Please feel free to comment.
Yes, as the default value is essentially a change at the lower bound of time, 0 or -∞ or whenever it is, so if we join Temporal x [Change t1 (Temporal y _)] the change to y in the inner Temporal would happen at earliest possible time, so assuming t1 is later than this y ought to be ignored, I think.

Am 03/31/2015 um 02:41 AM schrieb M Farkas-Dyck:
On 30/03/2015 at 22:23:17 +0200, martin wrote:
It appears to me that the defaults of the inner Temporal lose most of their meaning. The effective default is the change value of the last accepted change from the previous (t0) iteration.
Does this make some sense? Please feel free to comment.
Yes, as the default value is essentially a change at the lower bound of time, 0 or -∞ or whenever it is, so if we join
Temporal x [Change t1 (Temporal y _)]
the change to y in the inner Temporal would happen at earliest possible time, so assuming t1 is later than this y ought to be ignored, I think.
That neatly sums it up (and will make my code more concise). Thanks.

Your Temporal type looks semantically very similar to FRP’s Behaviour. Following http://conal.net/papers/push-pull-frp/ http://conal.net/papers/push-pull-frp/ : We could specify the time domain as `Maybe Time`, where - `Nothing` is “before everything - distant past”, needed for “temporal default”, - `Just t` are finite values of time newtype Behaviour a = Behaviour (Maybe Time -> a) It’s quite straightforward to verify that your Temporal and this Behaviour are isomorphic, assuming that `Change`s are sorted by time, and there aren’t consecutive duplicates. I find this “higher-order” formulation easier to reason about, as it’s `(->) Maybe Time`, for which we have lot’s of machinery already defined (e.g. Monad). So you could verify direct join implementation on `Temporal` by: join_prop :: Temporal (Temporal Int) -> Property join_prop temp = join temporal == fromBehaviour (join (toBehaviour temporal)) One might need to use weaker equality here though.
On 31 Mar 2015, at 08:14, martin
wrote: Am 03/31/2015 um 02:41 AM schrieb M Farkas-Dyck:
On 30/03/2015 at 22:23:17 +0200, martin wrote:
It appears to me that the defaults of the inner Temporal lose most of their meaning. The effective default is the change value of the last accepted change from the previous (t0) iteration.
Does this make some sense? Please feel free to comment.
Yes, as the default value is essentially a change at the lower bound of time, 0 or -∞ or whenever it is, so if we join
Temporal x [Change t1 (Temporal y _)]
the change to y in the inner Temporal would happen at earliest possible time, so assuming t1 is later than this y ought to be ignored, I think.
That neatly sums it up (and will make my code more concise). Thanks.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org mailto:Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Am 03/31/2015 um 10:27 AM schrieb Oleg Grenrus:
Your Temporal type looks semantically very similar to FRP’s Behaviour.
Following http://conal.net/papers/push-pull-frp/ :
We could specify the time domain as `Maybe Time`, where - `Nothing` is “before everything - distant past”, needed for “temporal default”, - `Just t` are finite values of time
newtype Behaviour a = Behaviour (Maybe Time -> a)
It’s quite straightforward to verify that your Temporal and this Behaviour are isomorphic, assuming that `Change`s are sorted by time, and there aren’t consecutive duplicates.
I find this “higher-order” formulation easier to reason about, as it’s `(->) Maybe Time`, for which we have lot’s of machinery already defined (e.g. Monad).
I am certainly not happy with my definitions type Time = Integer data Change a = Chg { ct :: Time, -- "change time" cv :: a -- "change value" } deriving (Eq,Show) data Temporal a = Temporal { td :: a, -- "temporal default" tc :: [Change a] -- "temporal changes" } deriving (Eq, Show) because writing join turned out to be such a nightmare. I like your approach of wrapping a function instead of data, but the problem is, I can no longer retrieve the times (I cannot print a "resulting schedule"). But that could easily be fixed by also returning the time of the next Change: newtype Behaviour a = Behaviour (Maybe Time -> (a, Time) However that gets me in trouble with the last change, where there is no next change. Returning Nothing in that case won't help either, because then Nothing would have two meanings (distant past and distant future). So I need a different notion of Time, which includes these two special cases. I will give that a try. Still I don't understand why my original definition gave me so much trouble. I mean it all looks quite innocent. I tried to find flaws from 10000 feet above and the only thing I could find is that the type a is mentioned in both Change and Temoral and Change alone does not make much sense. Maybe you find some more flaws.
participants (3)
-
M Farkas-Dyck
-
martin
-
Oleg Grenrus