Wiggling Sums



Published on October 17, 2012 under the tag An interesting Traversable problem I stumbled acrossPublished on October 17, 2012 under the tag haskell

The problem

The context of this problem is related to optimization problems: given some value, we want to produce a bunch of related values.

An example of where such an operation can be found is shrink :: Arbitrary a => a -> [a] , found in the QuickCheck library.

Alex and I encountered an fun problem while working on something similar at Tsuru. This blogpost is not really aimed at people who have just begun reading about Haskell as it contains little text and requires some intuition about sums and products (in the more general sense).

{-# LANGUAGE FlexibleInstances #-} import Control.Applicative import Data.Traversable

We can capture our idea of related values in a typeclass:

class Wiggle a where wiggle :: a -> [a] [a]

And define a simple instance for Int or Double :

instance Wiggle Int where = [x - 1 , x, x + 1 ] wiggle x[x, x, x

instance Wiggle Double where = let eps = 0.03 in [x - eps, x, x + eps] wiggle xeps[xeps, x, xeps]

The interesting notion is to define instances for more general (combined) types. Given a tuple, we can wiggle it in two ways: either wiggle one of its components, or wiggle them both. Let’s express both notions using two simple newtypes :

newtype Product a = Product { unProduct :: a} a} deriving ( Show )

instance ( Wiggle a, Wiggle b) => Wiggle ( Product (a, b)) where a,b)(a, b)) Product (x, y)) = wiggle ((x, y)) [ Product (x', y') | x' <- wiggle x, y' <- wiggle y] (x', y')x'wiggle x, y'wiggle y]

newtype Sum a = Sum { unSum :: a} a} deriving ( Show )

instance ( Wiggle a, Wiggle b) => Wiggle ( Sum (a, b)) where a,b)(a, b)) Sum (x, y)) = wiggle ((x, y)) [ Sum (x', y) | x' <- wiggle x] ++ (x', y)x'wiggle x] [ Sum (x, y') | y' <- wiggle y] (x, y')y'wiggle y]

The same applies to structures such as lists. We can wiggle all elements of a list, or just a single one (if the list is non-empty). Both instances are reasonably straightforward to write.

The interesting question is if and how we can do it for a more general family of structures than lists? Foldable ? Traversable ?

A Wiggle instance for traversable products is not that hard:

instance ( Traversable t, Wiggle a) => Wiggle ( Product (t a)) where t,a)(t a)) Product xs) = map Product $ traverse wiggle xs wiggle (xs)wiggle xs

But how about the instance:

instance ( Traversable t, Wiggle a) => Wiggle ( Sum (t a)) where t,a)(t a)) = wiggleSum wigglewiggleSum

The solution

Is it possible? Can you come up with a nicer solution than we have?

Spoiler warning: Click here to reveal the solution.