Collapsing multiple case branches?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Collapsing multiple case branches?

Colin Paul Adams
I have the following function:

northern_range:: Piece_type -> Int
northern_range piece =
    case piece of
      Lance -> 11
      Reverse_chariot -> 11
      Vertical_mover -> 11
      White_horse -> 11
      Rook -> 11
      Promoted_rook -> 11
      Promoted_gold_general -> 11
      Promoted_silver_general -> 11
      Free_king -> 11
      Promoted_phoenix -> 11
      Flying_stag -> 11
      Flying_ox -> 11
      Whale -> 11
      Dragon_king -> 11
      Soaring_eagle -> 11
      Bishop -> 0
      Kylin -> 0
      Lion -> 0
      Promoted_kylin -> 0
      Blind_tiger -> 0
      Promoted_ferocious_leopard -> 0
      Free_boar -> 0
      Horned_falcon -> 0
      _ -> 1

I'd prefer to write this as just three lines (one for each of the
three resulting values), something like this:

northern_range:: Piece_type -> Int
northern_range piece =
    case piece of
      Lance, Reverse_chariot, Vertical_mover, etc. -> 11
      Bishop, Kylin, etc. -> 0
      _ -> 1

Is there some syntax to do this sort of thing?
--
Colin Adams
Preston Lancashire
Reply | Threaded
Open this post in threaded view
|

Collapsing multiple case branches?

Thomas Davie
Hi Colin,

northernRange :: PieceType > Int -- note the camel case, that's  
traditional in Haskell circles
northernRange p
   | p `elem` [Lance, ReverseChariot, VerticalMover ....] = 11
   | p `elem` [Bishop, Kylin,....] = 0
   | otherwise = 1

These are called "pattern guards" ? you can put any boolean expression  
in them.

Of note, if you provide an Enum instance for PieceType you may really  
be able to do this:

northernRange p
   | p `elem` [Lance..SoaringEagle] = 11
   | p `elem` [Bishop..HornedFalcon] = 0
   | otherwise = 1

Finally, my guess is that you probably want a much more general type  
for PieceType that doesn't need extended every time you add a Piece to  
your game (and similarly doesn't need every function in your program  
extended at the same time).  Perhaps something like this:

data Piece = Piece { name :: String, northernRange :: Int }

With elements like:

lance = Piece "Lance" 11

or like:

reverseChariot = Piece {name = "Reverse chariot", northernRange = 11}


Bob

On 3 Jan 2009, at 20:56, Colin Paul Adams wrote:

> I have the following function:
>
> northern_range:: Piece_type -> Int
> northern_range piece =
>    case piece of
>      Lance -> 11
>      Reverse_chariot -> 11
>      Vertical_mover -> 11
>      White_horse -> 11
>      Rook -> 11
>      Promoted_rook -> 11
>      Promoted_gold_general -> 11
>      Promoted_silver_general -> 11
>      Free_king -> 11
>      Promoted_phoenix -> 11
>      Flying_stag -> 11
>      Flying_ox -> 11
>      Whale -> 11
>      Dragon_king -> 11
>      Soaring_eagle -> 11
>      Bishop -> 0
>      Kylin -> 0
>      Lion -> 0
>      Promoted_kylin -> 0
>      Blind_tiger -> 0
>      Promoted_ferocious_leopard -> 0
>      Free_boar -> 0
>      Horned_falcon -> 0
>      _ -> 1
>
> I'd prefer to write this as just three lines (one for each of the
> three resulting values), something like this:
>
> northern_range:: Piece_type -> Int
> northern_range piece =
>    case piece of
>      Lance, Reverse_chariot, Vertical_mover, etc. -> 11
>      Bishop, Kylin, etc. -> 0
>      _ -> 1
>
> Is there some syntax to do this sort of thing?
> --
> Colin Adams
> Preston Lancashire
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/beginners

Reply | Threaded
Open this post in threaded view
|

Collapsing multiple case branches?

Colin Paul Adams
>>>>> "Thomas" == Thomas Davie <[hidden email]> writes:

    Thomas> Hi Colin, northernRange :: PieceType > Int -- note the
    Thomas> camel case, that's traditional in Haskell circles

I know, but I find it vile.

    Thomas> northernRange p | p `elem` [Lance, ReverseChariot,
    Thomas> VerticalMover ....] = 11 | p `elem` [Bishop, Kylin,....] =
    Thomas> 0 | otherwise = 1

    Thomas> These are called "pattern guards" ? you can put any
    Thomas> boolean expression in them.

Ah, thanks, that will do nicely.

    Thomas> Of note, if you provide an Enum instance for PieceType you
    Thomas> may really be able to do this:

    Thomas> northernRange p | p `elem` [Lance..SoaringEagle] = 11 | p
    Thomas> `elem` [Bishop..HornedFalcon] = 0 | otherwise = 1

I thought of that, but there are additional functions to do where the
required ordering would be different.

    Thomas> Finally, my guess is that you probably want a much more
    Thomas> general type for PieceType that doesn't need extended
    Thomas> every time you add a Piece to your game (and similarly
    Thomas> doesn't need every function in your program extended at
    Thomas> the same time).  Perhaps something like this:

    Thomas> data Piece = Piece { name :: String, northernRange ::
    Thomas> Int }

A reasonable guess, but as the pieces types are fixed (it's an ancient
game) I preferred to write it this way.

BTW is this (as it looks to me) a classic space-time trade-off?
--
Colin Adams
Preston Lancashire
Reply | Threaded
Open this post in threaded view
|

Collapsing multiple case branches?

Alexander Dunlap
In reply to this post by Thomas Davie
On Sat, Jan 3, 2009 at 12:04 PM, Thomas Davie <[hidden email]> wrote:
> Hi Colin,
...snip...
> These are called "pattern guards" ? you can put any boolean expression in
> them.
...snip...

Technically, those are just called "guards." "Pattern guards" are when
you also bind a pattern; it's a GHC extension. They look like this,
for example:

foo x
  | Just y <- bar x = y + 1 -- this is the pattern guard. If bar x can
be matched with Just y, then y is bound and that guard path is taken.
Otherwise, evaluation falls through to the next guard option.
  | otherwise = 0

Alex
Reply | Threaded
Open this post in threaded view
|

Re: Collapsing multiple case branches?

Christian Maeder-2
In reply to this post by Colin Paul Adams
Colin Paul Adams wrote:
> I have the following function:
> northern_range:: Piece_type -> Int
> northern_range piece
     | elem piece [Lance, Reverse_chariot, Vertical_mover, etc.] = 11
     | elem piece [Bishop, Kylin, etc.] = 0
     | otherwise = 1

if you have an Eq instance for Piece_type.

Cheers Christian