Collapsing multiple case branches?

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

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 Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

"Thomas" == Thomas Davie
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

On Sat, Jan 3, 2009 at 12:04 PM, Thomas Davie
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

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
participants (4)
-
Alexander Dunlap
-
Christian Maeder
-
Colin Paul Adams
-
Thomas Davie