Yep, I posted this on r/haskell and someone pointed this out, which is cool. The provided type for Peg didn't derive Enum or Bounded, but it's a good trick to know.
After a while spent programming in Haskell you would probably develop your own mini-library of functions that make your life easier. Another one I often find useful is
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) f g = \x y -> f (g x y)
which e.g. allows you to define the absolute distance function dist :: (Num a) => a -> a -> a
dist = abs .: (-)
A fun challenge is figuring out why the definition of (.:) is equivalent to (.:) = fmap . fmap
!> (.:) = fmap . fmap
> !
Of course it's not really equivalent, since the most general type of the LHS is as you have said, whereas that of the RHS involves functor constraints; but inlining the definition of `fmap` for arrows gives the amusing definition:
(.:) = (.) . (.)
I tend to figure this sort of thing out by successive eta conversion: \f g x y -> f (g x y)
\f g x y -> (f . g x) y
\f g x -> f . g x
\f g x -> ((f .) . g) x
\f g -> (f .) . g
\f g -> ((f .) .) g
\f -> ((f .) .)
\f -> (.) (f .)
\f -> (.) ((.) f)
\f -> ((.) . (.)) f
(.) . (.)
Is there a better way? (.:) f g = (f .) . g
This can interestingly be generalized(in a way) to get (.::) :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> d
(.::) f g = ((f .) .) . g
and so on.Since fmap = (.), substitution would get your point free form.
(...) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
since (...) = (.) . (.)
.