[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