Rendering values into items and intermediate items in Haskell

Viewed 48

While doing user interface programming I often encounter the need to render a list of values and add some related information between the rendered values. In the following code example I'm rendering numerical values into strings where they appear in parenthesis and render the distance of two values into a string that gets placed between the renders of the values. The code works but I'm wondering if an implementation of the mystery function is available as part of the Haskell standard library. I'm also interested in names used for this function in other libraries, as using human readable words makes googling easier.

mystery :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
mystery n d [] = []
mystery n d [x] = [n x]
mystery n d (x:xs) = (n x) : (d x (head xs)) : mystery n d xs

node x = "(" ++ show x ++ ")"
distance x y = "-" ++ (show $ abs $ x - y) ++ "-"
render xs = concat $ mystery node distance xs
-- render [25, 68, 54, 15] == "(25)-43-(68)-14-(54)-39-(15)"
1 Answers

Your mystery function is actually doing a couple things at once, and if you separate out the behaviors, it may be a little easier to see what's going on.

First, you're mapping n on all the elements. We can write that as fmap n xs. Next, you're constructing new elements d x y for all pairs of adjacent elements x and y. We can write that as zipWith d xs (tail xs).

The last step is taking these two constructions and making a new list with elements that alternate back and forth between them. Interestingly, this was a question asked 9 years ago, but still doesn't have a super satisfying answer. Probably the simplest answer is to define your own function:

alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs

Then, we can define mystery as a one-liner:

mystery n d x = alternate (fmap n x) (zipWith d x (tail x))

If you really want it to be a one-liner, the best I could come up with was using concat and transpose in a bit of a funky way:

mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))

Basically, we're making singleton lists out of the two components using pure, fusing them together with <>, then transposeing this "list of lists" to get the elements properly interspersed, and concating the result.

Related