haskell - Rebindable syntax for arrow with constraint -
consider free arrow task remember how constructed. , want put constraint (e.x. show) on arguments of arrow:
data freearrow b leafarrow :: (show a, show b) => freearrow b seqarrow :: (show a, show b, show c) => freearrow b -> freearrow b c -> freearrow c pararrow :: (show a1, show b1, show a2, show b2) => freearrow a1 b1 -> freearrow a2 b2 -> freearrow (a1, a2) (b1, b2) deriving instance show (freearrow b)
to define arrow instance freearrow need define restricted versions of category , arrow:
class category cat id :: show => cat a (.) :: (show a, show b, show c) => cat b c -> cat b -> cat c class category => arrow arr :: (show b, show c) => (b -> c) -> b c first :: (show b, show c, show d) => b c -> (b,d) (c,d) second :: (show b, show c, show d) => b c -> (d,b) (d,c) (***) :: (show b, show c, show b', show c') => b c -> b' c' -> (&&&) :: (show b, show c, show c') => b c -> b c' -> b (c,c')
there instances:
instance category freearrow id = leafarrow (.) = flip seqarrow instance arrow freearrow arr _ = leafarrow first f = pararrow f id second f = pararrow id f (***) = pararrow
the approach operates hand-written arrows:
myarrow :: freearrow double double myarrow = (a &&& a) >>> arr (uncurry (+)) :: freearrow double double = leafarrow main :: io () main = print myarrow
will print:
seqarrow (seqarrow leafarrow (pararrow leafarrow leafarrow)) leafarrow
but arrow syntax (ghc 7.8.3):
myarrow :: freearrow double double myarrow = proc v -> -< v :: freearrow double double = leafarrow main :: io () main = print myarrow
i got errors like:
/home/ncrashed/dev/haskell/arrowproblem.hs:54:11: no instance (show c) arising use of ‘arr’ possible fix: add (show c) context of type expected context: (b -> c) -> freearrow b c in expression: arr when checking ‘arr’ (needed syntactic construct) has required type: forall b1 c1. (b1 -> c1) -> freearrow b1 c1 arising proc expression @ /home/ncrashed/dev/haskell/arrowproblem.hs:1:1 in expression: proc v -> -< v /home/ncrashed/dev/haskell/arrowproblem.hs:54:11: no instance (show c) arising use of ‘>>>’ possible fix: add (show c) context of type expected context: freearrow b -> freearrow b c -> freearrow c in expression: (>>>) when checking ‘(>>>)’ (needed syntactic construct) has required type: forall a1 b1 c1. freearrow a1 b1 -> freearrow b1 c1 -> freearrow a1 c1 arising proc expression @ /home/ncrashed/dev/haskell/arrowproblem.hs:1:1 in expression: proc v -> -< v /home/ncrashed/dev/haskell/arrowproblem.hs:54:11: no instance (show d) arising use of ‘first’ possible fix: add (show d) context of type expected context: freearrow b c -> freearrow (b, d) (c, d) in expression: first when checking ‘first’ (needed syntactic construct) has required type: forall b1 c1 d1. freearrow b1 c1 -> freearrow (b1, d1) (c1, d1) arising proc expression @ /home/ncrashed/dev/haskell/arrowproblem.hs:1:1
is there way fix this? bug?
perhaps should fall arrowp preprocessor...
p.s. there full sample of code
what problem is
when use haskell's arrow notation, not naively desugar proc v -> x -< y
literal text arr (\v -> y) >>> x
(using whatever arr
, >>>
in-scope) rather uses true values expecting, desugaring effectively:
control.arrow.arr (\v -> y) control.arrow.>>> x
the problem precisely when ran problem -- let's pretend it's house closed doorway -- chose build own house right next door door open (defining own arrow
, category
instances), , you're trying drive remote-control car hopelessly stuck in other house, , you're confused because doorways similar, why isn't there rc car upstairs in this house commands seamlessly rerouted to? answer is, you'll need build own rc car , controller (haskell source-to-source converter) complete approach.
clearly easier way chuck of work , instead doorknob other house.
how fix code
let me summarize how walls , doors haskell type classes work. you're programming @ advanced enough level may review, apologize if brief. show
type class, example, construct show
dictionary-of-functions (show
, showsprec
, showlist
) type constructor, , functions can use other functions coming other constraints on class's type-parameters.
the compiler stores show
dictionary takes type constructor pair: first, list of constraints on type parameters, second, actual dictionary you've implemented, potentially using functions earlier constraints. when compiler resolves show (mytype parama paramb)
therefore looks mytype
in show
dictionary, finds instance, verifies parama
, paramb
satisfy whatever constraints have satisfy (getting auxiliary dictionaries-of-functions classes), , forms dictionary of show
functions. that's review; if not, go , study tutorial on how haskell type classes work.
this means don't need show
in constructors you're writing. they're constructors! don't glue values in way can latter pattern-match apart -- don't need functions show
or showsprec
those. without them can still write:
data freearrow b leafarrow :: freearrow b seqarrow :: freearrow t -> freearrow t b -> freearrow b pararrow :: freearrow a1 b1 -> freearrow a2 b2 -> freearrow (a1, a2) (b1, b2) deriving instance show (freearrow b) instance category freearrow id = leafarrow; (.) = flip seqarrow instance arrow freearrow arr = const leafarrow first = flip pararrow id second = pararrow id (***) = pararrow
in fact can use show
on arbitrary arrow,
*main> show (leafarrow :: freearrow () (io string)) "leafarrow"
whereas code above not create value because leafarrow
constructor demanded show
instance io string
, can't provide it. , intended code works easily:
*main> :set -xarrows *main> print $ proc v -> (leafarrow :: freearrow double double) -< v seqarrow leafarrow (seqarrow leafarrow leafarrow)
we can of because "how constructed" information not use show x
typeclass define show x
instance of instances.
how think trying do
the reason can "fix" stuff above you're not introspecting deep parameters involved -- think want out of show
type class. in fact need define wholly different type class sort of type information available haskell runtime (unless i'm totally mistaken):
class typeof t -- integer here 10 type-constructor application, otherwise -- precedence of enclosing type-construction-operator. typeprec :: int -> t -> string -> string typeprec _ t = (typeof t ++) typeof :: t -> string typeof t = typeprec 0 t "" -- starts @ 0 if have no other info. instance typeof int typeof _ = "int" instance (typeof x) => typeof [x] typeof list = "[" ++ typeof (head list) ++ "]" instance (typeof x, typeof y) => typeof (x, y) typeof x = "(" ++ typeof (fst x) ++ ", " ++ typeof (snd x) ++ ")" -- helper functions precedence parsing: arg f x = typeprec 10 (f x) pif m n expr | m <= n = ('(' :) . expr . (')' :) | otherwise = expr <**> b = . (' ' :) . b infixr 1 <**> instance (typeof x) => typeof (io x) typeprec n x = pif 10 n $ ("io" ++) <**> arg io x io = undefined :: io x -> x instance (typeof x, typeof y) => typeof (either x y) typeprec n x = pif 10 n $ ("either" ++) <**> arg left x <**> arg right x left = undefined :: either x y -> x right = undefined :: either x y -> y
first, there may way write c-based extension haskell instead provides typeof :: x -> string
x haskell; hypothetically adding string parameter arrows. let's skip possibility.
the biggest problem above (.)
control.category
, explicitly forbids access internal type b
when composing cat b
cat b c
. overcoming going difficult. can't thread phantom-type data through cat
unless can protect cat
changing types.
a secondary problem you're trying annotate existing arrow metadata rather defining own arrow probe structure. along lines might crazy pathway:
prelude control.arrow control.monad.free control.monad.identity> :set prompt "ghci> " ghci> type myarrow = kleisli identity ghci> let x = arr (3*) :: kleisli (free (arrowmonad myarrow)) int int ghci> :t x x :: kleisli (free (arrowmonad myarrow)) int int
basically we're looking here use typeof
somehow "walk" tree here embodied free
monad.
there obvious restrictions preventing saying "this arrow if both input , output implement typeof
" (namely, arr
not have needed typeof
constraint), types can't hidden string in constructor; can't hidden in phantom type because says cat b c -> cat b -> cat c
, 2 obvious ways store intermediary types). there not, far can see, obvious restriction having class which, @ end of constructing our values, built of things simultaneously implement arrow
, typeof
.
Comments
Post a Comment