Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Haskell traversable with a simple example

I am trying to traverse all members of a data structure in haskell using Data.Traversable, which is documented at the following urls:

http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-Traversable.html http://www.haskell.org/haskellwiki/Foldable_and_Traversable

So far I have come up with the following code which is as far as I know missing a proper implementation of the Tr.Traversable instancing.

import qualified Data.Traversable as Tr
import qualified Data.Foldable as Fl
import Control.Monad
import Control.Applicative

data Test = Test { desc  :: String
                 , value :: Int
} 

data Data t = Data { foo :: t 
                   , bar :: t       
} 

exampleData = Data { foo = Test "Foo" 1 
                   , bar = Test "Bar" 2
}

instance Show Test where
  show f = (desc f) ++ ": " ++ (show $ value f)

instance (Show a) => Show (Data a) where
  show f = show (foo f)

instance Functor Data where
  fmap = Tr.fmapDefault

instance Fl.Foldable Data where
  foldMap = Tr.foldMapDefault

instance Tr.Traversable Data where
    traverse f = Data f  -- Try to show a Test entry inside the Data structure

--  
--  traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
--

main = do
  putStrLn $ show exampleData
  Tr.traverse (putStrLn show) exampleData

I am trying to print all the items in exampleData, member by member and using show. Am I on the right track and how should the traversable instancing be implemented?

like image 394
toeplitz Avatar asked Jan 24 '14 20:01

toeplitz


People also ask

What is an example of a traversable list?

A simple example of its usage is using a list as the traversable structure, and IO as the applicative: λ> import Data.Traversable λ> let qs = ["name", "quest", "favorite color"] λ> traverse ( hing -> putStrLn ("What is your " ++ thing ++ "?") *> getLine) qs What is your name?

What is the difference between applicative and traversable?

The Traversable instance is almost the same, except the constructors are called in applicative style. This means that we can have (side-)effects while rebuilding the tree. Applicative is almost the same as monads, except that effects cannot depend on previous results.

Should I use the traversable typeclass for my algorithms?

With the Traversable typeclass, you could probably write your algorithms more independent and versatile. But my experience says, that Traversable is usually only used to simply glue algorithms to existing data structures. It is quite nice not to need to write similar functions for different datatypes qualified, too.

How does the traverse function work?

So traverse takes some structure, and applies f to transform every element in the structure into some applicative, it then sequences up the effects of those applicatives from left to right, returning a structure with the same shape containing the results. You can also compare it to Foldable, which defines the related function traverse_.


2 Answers

The typical Traversable implementation here would be

traverse f (Data foo bar) = Data <$> f foo <*> f bar
like image 26
Louis Wasserman Avatar answered Sep 28 '22 09:09

Louis Wasserman


I would just use the language extensions to derive it for me:

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFoldable #-}
import qualified Data.Traversable as Tr
import qualified Data.Foldable as Fl
import Control.Monad
import Control.Applicative

data Test = Test { desc  :: String
                 , value :: Int }

data Data t = Data { foo :: t
                   , bar :: t } deriving (Functor, Tr.Traversable, Fl.Foldable)

exampleData = Data { foo = Test "Foo" 1
                   , bar = Test "Bar" 2
}

instance Show Test where
  show f = (desc f) ++ ": " ++ (show $ value f)

instance (Show a) => Show (Data a) where
  show f = show (foo f)

main = do
  putStrLn $ show exampleData
  Tr.traverse (putStrLn . show) exampleData

> runhaskell test_traversable.hs
Foo: 1
Foo: 1
Bar: 2
()

If you want to know how the compiler automatically implements it, you could compile it with the -ddump-deriv flag (cleaned up a bit):

instance Functor Data where
  fmap f (Data foo' bar') = Data (f foo') (f bar')

instance Tr.Traversable Data where
  tr.traverse f (Data foo' bar') = Data <$> (f foo') <*> (f bar')

instance Fl.Foldable Data where
  Fl.foldr f z (Data foo' bar') = f foo' (f bar' z)
like image 111
bheklilr Avatar answered Sep 28 '22 09:09

bheklilr