haskell - Match Data constructor functions -


i'm trying match data constructors in generic way, task of type executed.

data task = tasktypea int | tasktypeb (float,float)  generictasks :: statelikemonad s generictasks =    want (tasktypea 5)     tasktypea #> \input ->         want (tasktypeb (1.2,4.3))        runtasktypea input     tasktypeb #> \(x,y) -> runtasktypeb x y  main = runtask generictasks 

in this, generictasks function goes through do-instructions, building list of stuff want handled sort of state monad, , list of ways it, via (#>) function. runtask function run generictasks, use resulting list of to-do , how-to-do, , computations.

however, i'm having quite trouble figuring out how extract "type" (tasktypea,b) (#>), such 1 can call later. if :t tasktypea, int -> task.

i.e., how write (#>)?

i'm not entirely confident it's possible i'm thinking here in such generic way. reference, i'm trying build similar shake library, (#>) similar (*>). shake uses string argument (*>), matching done entirely using string matching. i'd without requiring strings.

your intuition correct, it's not possible write (#>) have specified. time data constructor acts pattern when in pattern position, namely, appearing parameter function

f (tasktypea z) = ... 

as 1 of alternatives of case statement

case tt of     tasktypea z -> ... 

or in monadic or pattern binding

do tasktypea z <- tt    return z 

when used in value position (e.g. argument function), loses patterny nature , becomes regular function. means, unfortunately, cannot abstract on patterns easily.

there is, however, simple formalization of patterns:

type pattern d = d -> maybe 

it's little bit of work make them.

tasktypea :: pattern task int tasktypea (tasktypea z) = z tasktypea _ = nothing 

if need need use constructor "forwards" (i.e. a -> d), pair 2 (plus functions work it):

data constructor d = constructor (a -> d) (d -> maybe a)  apply :: constructor d -> -> d apply (constructor f _) = f  match :: constructor d -> d -> maybe match (constructor _ m) = m  tasktypea :: constructor task int tasktypea = constructor tasktypea $ \case tasktypea z -> z                                           _ -> nothing 

this known "prism", , (a general form of) implemented in lens.

there advantages using abstraction -- namely, can construct prisms may have more structure data types allowed (e.g. d can function type), , can write functions operate on constructors, composing simpler ones make more complex ones generically.

if using plain data types, though, pain have implement constructor objects each constructor did tasktypea above. if have lot of these work with, can use template haskell write boilerplate you. necessary template haskell routine already implemented in lens -- may worth learn how use lens library because of that. (but can bit daunting navigate)

(style note: second constructor above , 2 helper functions can written equivalently using little trick:

data constructor d = constructor { apply :: -> d, match :: d -> maybe } 

)

with abstraction in place, possible write (#>). simple example be

(#>) :: constructor d -> (a -> state d ()) -> state d () cons #> f =     d <-     case match cons d of         nothing -> return ()          -> f 

or perhaps more sophisticated, depending on precisely want.


Comments