[Haskell-cafe] A convenient way to deal with conditional function composition?

Chris Kuklewicz haskell at list.mightyreason.com
Tue Apr 10 09:33:41 EDT 2007


Maxime Henrion wrote:
> 	Hello all,
> 
> 
> I have found myself writing instances of Show for some types of
> mine, and I did so by defining the showsPrec function, for performance
> reasons.  I ended up with code that I find quite inelegant.  Here's
> an example:
> 
> data Move = Move {
>                  movePiece     :: PieceType,
>                  moveFile      :: Maybe File,
>                  moveTarget    :: Square,
>                  moveIsCapture :: Bool
>                  --movePromotion :: Maybe PieceType
>                }
>   deriving (Eq)
> 
> instance Show Move where
>   showsPrec _
>     Move {
>       movePiece     = p,
>       moveFile      = f,
>       moveTarget    = s,
>       moveIsCapture = c
>     } = (if p /= Pawn then shows p else id) .
>         (maybe id shows f) .
>         (if c then ('x':) else id) .
>         shows s
> 
> I considered writing a conditional composiion combinator to avoid all
> the 'if foo then f else id' code.  Something looking like this:
> 
> f .? True  g = f . g
> f .? False g = f
> 
> I'm not sure this is the best approach though, and I would be happy
> to hear about your suggestions for improving the style of this code,
> or any other comment that you think is appropriate.
> 
> Thanks,
> Maxime

Well, since ((.) :: ShowS -> ShowS -> ShowS) is a Monoid, you can use Writer to
create the result:

> import Control.Monad
> import Control.Monad.Writer
> 
> type Writes = Writer ShowS ()
> 
> data PieceType = Pawn | Other deriving (Eq,Show)
> type File = Int
> type Square = Int
> 
> data Move = Move {
>                  movePiece     :: PieceType,
>                  moveFile      :: Maybe File,
>                  moveTarget    :: Square,
>                  moveIsCapture :: Bool
>                  --movePromotion :: Maybe PieceType
>                }
>   deriving (Eq)
> 
> instance Show Move where showsPrec = showsPrec_Move
> 
> showsPrec_Move :: Int -> Move -> ShowS
> showsPrec_Move _ Move { movePiece     = p
>                       , moveFile      = f
>                       , moveTarget    = s
>                       , moveIsCapture = c } = execWriter $ do
>   when (p/=Pawn) (tell (shows p))
>   maybe (return ()) (tell . shows) f
>   when c (tell ('x':))
>   tell (shows s)
> 
> testMove = Move Other (Just 6) 10 True
> 

which gives

> *Main> testMove
> Other6x10
> *Main> testMove { movePiece=Pawn }
> 6x10
> *Main> testMove { movePiece=Pawn, moveIsCapture=False }
> 610



More information about the Haskell-Cafe mailing list