haskell - Enforced pattern order -


i'm writing magic gathering (mtg) game engine in haskell.

for unfamiliar mtg, it's card game cards can have 5 colors: white (w), blue (u), black (b), red (r), , green (g).

{-# language viewpatterns #-} import data.set  data color = w | u | b | r | g     deriving (show, eq, ord)  data card = card (set color) -- simplified card type colors  viewcolors :: card -> [color] viewcolors (card colors) = tolist colors 

what pattern match on colors so:

foo :: card -> string foo (viewcolors -> [w, b]) = "card white , black" foo _ = "whatever" 

so far, good. there 1 problem here: can type order of colors incorrectly in view pattern so:

bar :: card -> string bar (viewcolors -> [b, w]) = "this never hit" bar _ = "whatever" 

of course, have written viewcolors in way directly resolves problem. or use guards, i'd rather not. here couple ways so

viewcolors :: card -> (bool, bool, bool, bool, bool) viewcolors (card colors) = let m = (`member` colors)     in (m w, m u, m b, m r, m g) 

this solution overly verbose while pattern matching, if use type isomorphic bool shorter (and/or meaningful) identifiers. matching green card like

baz :: card -> string baz (viewcolors -> (false, false, false, false, true)) = "it's green" 

data colorview = w | wu | wub | ... combos here  viewcolors :: card -> colorview viewcolors (card colors) = extract correct colorview colors 

this solution has combinatorial explosion. seems extremely bad implement, nice use, if have colorviewtolist :: colorview -> [color] allow programmatic extraction after pattern match.


i have no idea if following can approximated in haskell, following ideal:

fuz :: card -> string fuz (viewcolors -> (w :* ())) = "it's white" fuz (viewcolors -> (w :* u :* ())) = "it's white , blue" fuz (viewcolors -> (w :* b :* ())) = "it's white , black" 

i'm willing use advanced language extensions allow kind of code: datakinds, polykinds, typefamilies, multiparamtypeclasses, gadts, name it.

is possible? have other suggested approaches?

i record solution, easy typeclasses

{-# language viewpatterns, scopedtypevariables #-}  import qualified data.set set  data color = w' | u' | b' | r' | g' deriving (show, eq, ord) data card = card (set.set color)   newtype w = w newtype u = u newtype b = b newtype r = r newtype g = g  class tocolors x   tocolors :: x -> [color]   reify :: x  instance tocolors ()   tocolors _ = []   reify = ()  instance tocolors => tocolors (w a)   tocolors (w a) = w':tocolors   reify = w reify  --other instances  members :: set.set color -> [color] -> bool members s = foldl (\b e -> b && (set.member e s)) true  viewcolors :: forall a. tocolors => card -> maybe viewcolors (card s) = let = reify :: in    if members s (tocolors a) (just a) else nothing  foo :: card -> string foo (viewcolors -> (w (b ()))) = "card white , black" foo _ = "whatever" 

this reworked other syntaxes. like, define colors types don't take parameters, , use infix heterogeneous list constructor. either way not care order.

edit: if want match exact sets easy also--just replace members function so

viewcolors :: forall a. tocolors => card -> maybe viewcolors (card s) = let = reify :: in    if s == (set.fromlist . tocolors $ a) (just a) else nothing 

Comments

Popular posts from this blog

c# - How Configure Devart dotConnect for SQLite Code First? -

java - Copying object fields -

c++ - Clear the memory after returning a vector in a function -