2

I am trying to extend my function toTuple so that it takes [(d1, Just x), (d2, Just y), (d3, Just z)] and produces [(d1, d2, y), (d2, d3, z)]

import qualified Data.Function.Step.Discrete.Open as SF import qualified Data.Map as Map newtype DayMap a = DayMap (SF.SF Day (Maybe a)) deriving stock (Show, Functor) toTuple :: Map.Map Day (Maybe a) -> [(Day, Maybe Integer)] toTuple a = produceList where produceList = Map.toList (getDM td3) getDM :: DayMap a -> Map.Map Day (Maybe a) getDM (DayMap sf@(SF.SF m hi)) = m td3 :: DayMap Integer td3 = DayMap.insert (Just $ fromGregorian 2010 01 01) (Just $ fromGregorian 2012 01 01) 22 DayMap.empty 

It currently produces this:

> toTuple (getDM td3) [(2010-01-01,Nothing),(2012-01-02,Just 22)] 

I.e. the value Just 22 is relevant between 2010-01-01 and 2012-01-02 and is empty before that.

So i want to end up with [(2010-01-01, 2012-01-02, (Just 22))] in this case.

I'm not clear on how to extend my toTuple function. Any tips would be appreciated.

5
  • 2
    What happens to the Just x here? Commented Jul 23, 2019 at 19:20
  • It ends up in the tuple between the date preceding it and the date it's originally associated with [(2010-01-01, 2012-01-02, (Just 22))] Commented Jul 23, 2019 at 19:29
  • 2
    Probably something like zipWith (\(x,_) (y,z) -> (x,y,z)) (tail data) data. Commented Jul 23, 2019 at 19:47
  • Thanks. I don't follow what's happening with the (tail data) data part though. Could you elaborate? Commented Jul 23, 2019 at 19:57
  • 1
    tail returns the list but without the first element, so that means we zip each item with the next one. So the first item (x,_) with the second (y,z); and the second (x,_) with the third (y,z); and so on. Commented Jul 23, 2019 at 19:59

2 Answers 2

3

You can process such list with:

toTuple :: [(a, b)] -> [(a, a, b)] toTuple [] = [] toTuple xs@(_:xt) = zipWith f xs xt where f (x, _) (y, z) = (x, y, z)

Here we thus map an empty list on an empty list. A non-empty list is processed by zipping the list (xs) with its tail (xt), with as "zipping function" f. f takes the first item of the "previous" tuple x, and the "next" tuple (y, z), and construct a 3-tuple (x, y, z).

Sign up to request clarification or add additional context in comments.

2 Comments

Do you have thoughts on how I might create a helper function that would allow me to supply target start and end Days and truncate the toTuple output accordingly? E.g. if toTuple output [(2010-01-01,2012-01-02,Just 22),(2012-01-02,2013-01-01,Nothing),(2013-01-01,2016-01-02,Just 9)] and I wanted Days between 2012-06-30 and 2015-01-01, it should return: [(2012-06-30,2013-01-01,Nothing),(2013-01-01,2015-01-01,Just 9)]
Always bringing excellent answers and a lot of interesting start points to think! awesome work here
0

The @Willem Van Onsem covers everything. I let another version with foldr pretty unconventional :

toTuple' :: [(a, b)] -> [(a, a, b)] toTuple' xs = foldr (\_ _ -> zipWith f xs (tail xs)) [] xs where f (x, _) (y, z) = (x, y, z) $> toTuple' [(1,2),(3,4),(5,6),(7,8)] $> [(1,3,4),(3,5,6),(5,7,8)] 

2 Comments

I don't think this brings anything to the table. That fold is precisely equivalent to pattern matching on the result of null xs, which is clearer.
@dfeuer I agree and I said that, the accepted answer covered all. But I wanted to put this way also. Thanks for comments and for you time

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.