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
Post a Comment