Prettier functions for wrapping and wrapping
The post Semantic editor combinators gave an example of a pattern that comes up a lot for me in Haskell programming.
I want to apply functions inside of a newtype
without cumbersome unwrapping and wrapping of the representation insides.
While chatting with Daniel Peebles in #haskell today, the realization hit me that these “higher-order wrappers” can not only make other code pretty, but can themselves be expressed more beautifully and clearly, using two of the combinators given in that post.
The example I gave was type composition, taken from the TypeCompose library:
newtype (g :. f) a = O { unO :: g (f a) }
The convenient higher-order wrappers apply n-ary function within O
constructors:
inO h (O gfa) = O (h gfa)
inO2 h (O gfa) (O gfa') = O (h gfa gfa')
...
Then I get to implement Functor
and Applicative
instances in the style of semantic editor combinators.
instance (Functor g, Functor f) => Functor (g :. f) where
fmap = inO . fmap . fmap
instance (Applicative g, Applicative f) => Applicative (g :. f) where
pure = O . pure . pure
(<*>) = (inO2 . liftA2) (<*>)
The point-free definitions I gave before are pretty cryptic if you’re not used to the style:
inO = ( O .) . (. unO)
inO2 = (inO .) . (. unO)
inO3 = (inO2 .) . (. unO)
...
What dawned on me today is that I can instead say what I mean plainly: inO
applies unO
to the argument and O
to the result.
inO = result O . argument unO
Similarly, inO2
applies unO
to the (first) argument and inO
to the resulting function.
Similarly for inO3
:
inO2 = result inO . argument unO
inO3 = result inO2 . argument unO
...
The unwrapping and wrapping don’t interact, so, we can write equivalent definitions, swapping the compositions:
inO2 = argument unO . result inO
Equivalence follows from associativity of function composition.
Conal Elliott » Blog Archive » Sequences, segments, and signals:
[…] About « Prettier functions for wrapping and wrapping […]
5 December 2008, 12:14 amConal Elliott » Blog Archive » Another angle on functional future values:
[…] definitions of these helpers are very simple with the ideas from Prettier functions for wrapping and wrapping and a lovely notation from Matt Hellige’s Pointless […]
4 January 2009, 8:02 pmconal:
In December of 2008, Matt Hellige suggested a notational refinement that I’ve been using & enjoying in my day-to-day programming ever since. See his post Pointless Fun.
Above, I suggested redefining
inO
to “say what I mean plainly:inO
appliesunO
to the argument andO
to the result.”Matt’s idea is to package up this pattern of use of
result
andargument
and give it a name. And not just any name, but an infix operator that looks like an arrow and is right-associative, to mimic the notation of function types.Now
inO
,inO2
, etc have lovely, simple definitions:inO = unO ~> O inO2 = unO ~> inO inO3 = unO ~> inO2 -- ...
Written out,
which can be read as saying that the semantic editor combinator
inO3
passes three arguments throughunO
before invoking a given editor and then the editor’s result throughO
.This notational technique can be used in many other ways besides stripping and restoring
newtype
constructors. Matt’s examples include use ofid
when arguments and/or results do not need transforming.Afterthought: SECs built up with
9 March 2010, 10:16 am(~>)
(or explicitly withresult
andargument
) remind me vaguely of method combination in some object systems, like CLOS, but in a functional style — where after and before methods combine with inherited methods via function composition rather than sequential execution. Even this apparent difference diminishes if one considers a standard denotational semantics of sequential execution as function composition. For instance, a denotational semantics for method combination might be written elegantly in terms ofargument
,result
, and(~>)
.Conal Elliott » Blog Archive » Another angle on zippers:
[…] inO is from Control.Compose, and is defined using the ideas from Prettier functions for wrapping and wrapping and the notational improvement from Matt Hellige’s Pointless […]
29 July 2010, 6:38 pm