TypeCompose 0.7.0 → 0.9.14
raw patch · 16 files changed
Files
- CHANGES +0/−74
- COPYING +25/−0
- Makefile +0/−1
- README +0/−17
- TODO +0/−0
- TypeCompose.cabal +30/−23
- src/Control/Compose.hs +233/−99
- src/Control/Instances.hs +5/−13
- src/Data/Bijection.hs +13/−8
- src/Data/CxMonoid.hs +6/−2
- src/Data/Lambda.hs +4/−4
- src/Data/Pair.hs +8/−8
- src/Data/Partial.hs +3/−2
- src/Data/Title.hs +3/−2
- src/Data/Zip.hs +8/−6
- wikipage.tw +0/−55
− CHANGES
@@ -1,74 +0,0 @@-% TypeCompose changes--== Version 0.5.1 ==--* Tweaked to work with ghc before and after 6.9--== Version 0.5 ==--* Backed out DistribM. Now that I've read "Composing Monads", I know- there's more to it. At least four different ways, all with conflicting- Monad instances.--== Version 0.4 ==--* pairEdit, pairEditM in Data.Pair-* build-type simple-* doc tweek DistribM & joinMM-* DistribM export & comment tweak-* DistribM and (m :. n) Monad-* Functor/Functor & Applicative/Applicative tweak-* inId2. Functor & Applicative instances for Id-* removed r->m dep in RefMonad-* doc tweak--== Version 0.3 ==--* Simplified Applicative instance for g :. f-* Renamed type constructors "O" and "App" to "(:.)" and "(:$)". Also- include old names for compatibility.-* Replaced the 6.6-compatible OPTIONS pragmas with LANGUAGE-* Pair & Copair for Const-* Changed functional dependency for RefMonad--## Version 0.2 ##--+ More comments-+ Added [Data.Partial](src/Data/Partial.hs): partial values.-+ [Data.Bijection](src/Data/Bijection.hs): bijective arrows. Used in- [Control.Compose] for composing representation transformations.-+ Using `LANGUAGE` instead of `OPTIONS` pragmas-+ [Data.Pair](src/Data/Pair.hs) & [Data.Fun](src/Data/Fun.hs). Classes of- pair-like and function-like types.-+ [Data.RefMonad](src/Data/RefMonad.hs)-+ Renamed StaticArrow/Static to OO/OO-+ Now in{O,Flip,Prod,Arrw,Const}{,2,3} (i.e., `inO2` etc)-+ `Sink` type alias and `Monoid` instance.-+ `Monoid_f` and `O` instance.-+ `Arrw` type class with `Functor` & `Cofunctor` instances.-+ [Data.Title](src/Data/Title.hs): a titling class for type constructors.- Doesn't really belong here.-+ Eliminated dependency on "mtl" package by removing a standard- applicative instance for `ReaderT`.-+ [Data.CxMonoid](src/Data/CxMonoid.hs): context-dependent monoid-+ Type constructors `:*:`, `::*::`, & `:~>:`-+ `FunA` and `FunAble`, for convenient `Arrow` definitions. See also `FunD` &- `FunDble` in [DeepArrow].--## Version 0.1 ##--+ Renamed "Compose/Comp/unComp" to "O/O/unO".-+ Renamed "onComp" to "inO"-+ Renamed "mapSrc" to "mapCur", and renamed type parameter "src" to "cur",- to avoid confusion with "Source" in Phooey's use of DataDriven.-+ Swapped argument order to dd in DataDriven.-+ Renamed "Updater" to "Action"-+ Changed the Monoid (IO a) instance in Control.Instances to use "liftA2- mappend" instead of "(*>)".-+ Added unFlip, inFlip, inFlip2---[TypeCompose]: http://haskell.org/haskellwiki/TypeCompose-[DeepArrow]: http://haskell.org/haskellwiki/DeepArrow--[Control.Compose]: src/Control.Compose.hs
+ COPYING view
@@ -0,0 +1,25 @@+Copyright (c) 2009-2012 Conal Elliott+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. The names of the authors may not be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
− Makefile
@@ -1,1 +0,0 @@-include ../cho-home-cabal-make.inc
− README
@@ -1,17 +0,0 @@-% TypeCompose--TypeCompose provides some classes & instances for forms of type-composition, as well as some modules that haven't found another home. The-[wiki page] contains a description and links to documentation.--Please share any comments & suggestions on the [talk page] there.--You can configure, build, and install all in the usual way with Cabal-commands.-- runhaskell Setup.lhs configure- runhaskell Setup.lhs build- runhaskell Setup.lhs install--[wiki page]: http://haskell.org/haskellwiki/TypeCompose-[talk page]: http://haskell.org/haskellwiki/Talk:TypeCompose
− TODO
TypeCompose.cabal view
@@ -1,37 +1,44 @@ Name: TypeCompose-Version: 0.7.0+Version: 0.9.14 Synopsis: Type composition classes & instances Category: Composition, Control+Cabal-Version: >= 1.6 Description: TypeCompose provides some classes & instances for forms of type composition, as well as some modules who haven't yet found a home. . Please see the project wiki page: <http://haskell.org/haskellwiki/TypeCompose> .- © 2007-2010 by Conal Elliott; BSD3 license.-Author: Conal Elliott + Copyright 2007-2012 by Conal Elliott; BSD3 license.+Author: Conal Elliott Maintainer: conal@conal.net-Homepage: http://haskell.org/haskellwiki/TypeCompose-Package-Url: http://code.haskell.org/~conal/code/TypeCompose-Copyright: (c) 2007-2010 by Conal Elliott+Homepage: https://github.com/conal/TypeCompose+Copyright: (c) 2007-2013 by Conal Elliott License: BSD3+License-File: COPYING Stability: provisional build-type: Simple-Hs-Source-Dirs: src-Extensions: -Build-Depends: base<5-Exposed-Modules: - Data.Bijection- Data.CxMonoid- Data.RefMonad- Data.Pair- Data.Zip- Data.Lambda- Data.Title- Data.Partial- Control.Instances- Control.Compose-Extra-Source-Files:-ghc-options: -Wall --- TODO: eliminate Pair or Zip+source-repository head+ type: git+ location: git://github.com/conal/TypeCompose.git++Library+ Hs-Source-Dirs: src+ Build-Depends: base<5, base-orphans >= 0.5+ Exposed-Modules:+ Data.Bijection+ Data.CxMonoid+ Data.RefMonad+ Data.Pair+ Data.Zip+ Data.Lambda+ Data.Title+ Data.Partial+ Control.Instances+ Control.Compose+ ghc-options: -Wall++ -- TODO: eliminate Pair or Zip++-- ghc-prof-options: -prof -auto-all
src/Control/Compose.hs view
@@ -3,15 +3,19 @@ , TypeOperators, GeneralizedNewtypeDeriving, StandaloneDeriving , CPP #-}+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702+{-# Language DeriveGeneric #-}+#endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 710+{-# Language KindSignatures, PolyKinds #-}+#endif -- For ghc 6.6 compatibility -- {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-}- ---------------------------------------------------------------------- -- | -- Module : Control.Compose--- Copyright : (c) Conal Elliott 2007+-- Copyright : (c) Conal Elliott 2007-2013 -- License : BSD3 -- -- Maintainer : conal@conal.net@@ -29,14 +33,15 @@ -- * Value transformers Unop, Binop -- * Specialized semantic editor combinators- , result, argument, (~>)+ , result, argument, (~>), (~>*), (<~), (*<~) -- * Contravariant functors- , Cofunctor(..), bicomap+ , ContraFunctor(..), bicomap -- * Unary\/unary composition- , (:.)(..), O, biO, convO, coconvO, inO, inO2, inO3+ , (:.)(..), O, unO, biO, convO, coconvO, inO, inO2, inO3 , oPure, oFmap, oLiftA2, oLiftA3- , fmapFF, fmapCC, cofmapFC, cofmapCF- -- , DistribM(..), joinMM+ , fmapFF, fmapCC, contraFmapFC, contraFmapCF+ , DistribM(..), joinDistribM, bindDistribM, returnDistribM+ , joinMMT, joinComposeT -- * Type composition -- ** Unary\/binary , OO(..)@@ -51,12 +56,12 @@ -- * Type application , (:$)(..), App, biApp, inApp, inApp2 -- * Identity- , Id(..), biId, inId, inId2+ , Id(..),unId, biId, inId, inId2 -- * Constructor pairing -- ** Unary- , (:*:)(..), biProd, convProd, (***#), ($*), inProd, inProd2, inProd3+ , (:*:)(..),(*:*), biProd, convProd, (***#), ($*), inProd, inProd2, inProd3 -- * Binary- , (::*::)(..), inProdd, inProdd2+ , (::*::)(..), (*::*), inProdd, inProdd2 -- * Arrow between /two/ constructor applications , Arrw(..), (:->:) , biFun, convFun, inArrw, inArrw2, inArrw3@@ -65,6 +70,14 @@ , biEndo, inEndo ) where ++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702+import GHC.Generics ( Generic )+#endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706+import GHC.Generics ( Generic1 )+#endif+ #if __GLASGOW_HASKELL__ >= 609 import Control.Category import Prelude hiding ((.), id)@@ -75,10 +88,12 @@ hiding (pure) #endif +import Data.Orphans () import Data.Monoid+import qualified Data.Semigroup as Sem import Data.Foldable-import Data.Traversable import Control.Applicative+import Control.Monad (join,liftM) -- import Test.QuickCheck -- for Endo @@ -97,9 +112,9 @@ Value transformers ----------------------------------------------------------} --- |Unary functions+-- | Unary functions type Unop a = a -> a--- |Binary functions+-- | Binary functions type Binop a = a -> a -> a @@ -110,40 +125,55 @@ --------------------------------------------------------------------} -- | Add pre-processing-argument :: (a' -> a) -> ((a -> b) -> (a' -> b))+-- argument :: (a' -> a) -> ((a -> b) -> (a' -> b))+argument :: Category cat => (a' `cat` a) -> ((a `cat` b) -> (a' `cat` b)) argument = flip (.) -- | Add post-processing-result :: (b -> b') -> ((a -> b) -> (a -> b'))+result :: Category cat => (b `cat` b') -> ((a `cat` b) -> (a `cat` b')) result = (.) -infixr 1 ~>+infixr 1 ~>, ~>*+infixl 1 <~, *<~+ -- | Add pre- and post processing-(~>) :: (a' -> a) -> (b -> b') -> ((a -> b) -> (a' -> b'))+(~>) :: Category cat =>+ (a' `cat` a) -> (b `cat` b') -> ((a `cat` b) -> (a' `cat` b')) -- (f ~> h) g = h . g . f f ~> h = result h . argument f --- More generally,--- --- (~>) :: Category (-->) => (a' --> a) -> (b --> b') -> ((a --> b) -> (a' --> b'))+(<~) :: Category cat =>+ (b `cat` b') -> (a' `cat` a) -> ((a `cat` b) -> (a' `cat` b'))+(<~) = flip (~>) -- If I add argument back to DeepArrow, we can get a different generalization: -- --- (~>) :: DeepArrow (-->) => (a' --> a) -> (b --> b') -> ((a -> b) --> (a' -> b'))+-- (~>) :: DeepArrow cat => (a' `cat` a) -> (b `cat` b') -> ((a -> b) `cat` (a' -> b')) +-- | Like '(~>)' but specialized to functors and functions.+(~>*) :: (Functor p, Functor q) => + (a' -> a) -> (b -> b') -> (p a -> q b) -> (p a' -> q b')+f ~>* g = fmap f ~> fmap g +(*<~) :: (Functor p, Functor q) => + (b -> b') -> (a' -> a) -> (p a -> q b) -> (p a' -> q b')+(*<~) = flip (~>*)++-- (~>*) and (*<~) could be generalized to other categories (beside functions)+-- if we use a more general Functor, as in the "categories" package.+ {---------------------------------------------------------- Contravariant functors ----------------------------------------------------------} -- | Contravariant functors. often useful for /acceptors/ (consumers, -- sinks) of values.-class Cofunctor acc where- cofmap :: (a -> b) -> (acc b -> acc a)+class ContraFunctor h where+ contraFmap :: (a -> b) -> (h b -> h a) -- | Bijections on contravariant functors-bicomap :: Cofunctor f => (a :<->: b) -> (f a :<->: f b)-bicomap (Bi ab ba) = Bi (cofmap ba) (cofmap ab)+bicomap :: ContraFunctor f => (a :<->: b) -> (f a :<->: f b)+bicomap (Bi ab ba) = Bi (contraFmap ba) (contraFmap ab) {----------------------------------------------------------@@ -172,13 +202,13 @@ > { mempty_f = O mempty_f; mappend_f = inO2 mappend_f } Similarly, there are two useful 'Functor' instances and two useful-'Cofunctor' instances.+'ContraFunctor' instances. -> instance ( Functor g, Functor f) => Functor (g :. f) where fmap = fmapFF-> instance (Cofunctor g, Cofunctor f) => Functor (g :. f) where fmap = fmapCC+> instance ( Functor g, Functor f) => Functor (g :. f) where fmap = fmapFF+> instance (ContraFunctor g, ContraFunctor f) => Functor (g :. f) where fmap = fmapCC > -> instance (Functor g, Cofunctor f) => Cofunctor (g :. f) where cofmap = cofmapFC-> instance (Cofunctor g, Functor f) => Cofunctor (g :. f) where cofmap = cofmapCF+> instance ( Functor g, ContraFunctor f) => ContraFunctor (g :. f) where contraFmap = contraFmapFC+> instance (ContraFunctor g, Functor f) => ContraFunctor (g :. f) where contraFmap = contraFmapCF However, it's such a bother to define the Functor instances per composition type, I've left the fmapFF case in. If you want the fmapCC@@ -187,8 +217,26 @@ constraints, rather than just matching instance heads. -}-newtype (g :. f) a = O { unO :: g (f a) }+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 710+newtype ((g :: k2 -> *) :. (f :: k1 -> k2)) (a :: k1)+#else+newtype (g :. f) a+#endif+ = O (g (f a)) deriving ( Eq, Show, Ord+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702+ , Generic+#endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706+ , Generic1+#endif+ ) +-- newtype (g :. f) a = O { unO :: g (f a) } deriving Show++-- | Unwrap a '(:.)'.+unO :: (g :. f) a -> g (f a)+unO (O gfa) = gfa+ -- | Compatibility synonym type O = (:.) @@ -196,15 +244,36 @@ instance (Functor g, Functor f) => Functor (g :. f) where fmap = fmapFF +-- or+-- +-- deriving instance (Functor g, Functor f) => Functor (g :. f)+ -- These next two instances are based on suggestions from Creighton Hogg: instance (Foldable g, Foldable f, Functor g) => Foldable (g :. f) where- foldMap f = fold . fmap (foldMap f) . unO+ -- foldMap f = fold . fmap (foldMap f) . unO+ foldMap f = foldMap (foldMap f) . unO+ -- fold (O gfa) = fold (fold <$> gfa)+ -- fold = fold . fmap fold . unO+ fold = foldMap fold . unO+ -- I could let fold default instance (Traversable g, Traversable f) => Traversable (g :. f) where- sequenceA = fmap O . sequenceA . fmap sequenceA . unO-+ -- sequenceA = fmap O . sequenceA . fmap sequenceA . unO+ -- sequenceA = fmap O . traverse sequenceA . unO+ -- sequenceA = (unO ~> fmap O) (traverse sequenceA)+ -- traverse f = fmap O . traverse (traverse f) . unO+ traverse = (unO ~> fmap O) . traverse . traverse +-- traverse f+-- sequenceA . fmap f+-- sequenceA . (inO.fmap.fmap) f+-- sequenceA . inO (fmap (fmap f))+-- sequenceA . O . fmap (fmap f) . unO+-- fmap O . traverse sequenceA . unO . O . fmap (fmap f) . unO +-- fmap O . traverse sequenceA . fmap (fmap f) . unO +-- fmap O . traverse (sequenceA . fmap f) . unO +-- fmap O . traverse (traverse f) . unO -- instance (Functor g, Functor f) => Functor (g :. f) where -- fmap = inO.fmap.fmap@@ -217,8 +286,8 @@ convO :: Functor g => (b :<->: g c) -> (c :<->: f a) -> (b :<->: (g :. f) a) convO biG biF = biG >>> bimap biF >>> Bi O unO --- | Compose a bijection, Cofunctor style-coconvO :: Cofunctor g => (b :<->: g c) -> (c :<->: f a) -> (b :<->: (g :. f) a)+-- | Compose a bijection, ContraFunctor style+coconvO :: ContraFunctor g => (b :<->: g c) -> (c :<->: f a) -> (b :<->: (g :. f) a) coconvO biG biF = biG >>> bicomap biF >>> Bi O unO @@ -263,25 +332,26 @@ oLiftA3 = inO3 . liftA3 - -- | Used for the @Functor :. Functor@ instance of 'Functor' fmapFF :: ( Functor g, Functor f) => (a -> b) -> (g :. f) a -> (g :. f) b fmapFF = inO.fmap.fmap --- | Used for the @Cofunctor :. Cofunctor@ instance of 'Functor'-fmapCC :: (Cofunctor g, Cofunctor f) => (a -> b) -> (g :. f) a -> (g :. f) b-fmapCC = inO.cofmap.cofmap+-- | Used for the @ContraFunctor :. ContraFunctor@ instance of 'Functor'+fmapCC :: (ContraFunctor g, ContraFunctor f) => (a -> b) -> (g :. f) a -> (g :. f) b+fmapCC = inO.contraFmap.contraFmap --- | Used for the @Functor :. Cofunctor@ instance of 'Functor'-cofmapFC :: (Functor g, Cofunctor f) => (b -> a) -> (g :. f) a -> (g :. f) b-cofmapFC = inO.fmap.cofmap+-- | Used for the @Functor :. ContraFunctor@ instance of 'Functor'+contraFmapFC :: (Functor g, ContraFunctor f) => (b -> a) -> (g :. f) a -> (g :. f) b+contraFmapFC = inO.fmap.contraFmap --- cofmapFC h (O gf) = O (fmap (cofmap h) gf)+-- contraFmapFC h (O gf) = O (fmap (contraFmap h) gf) --- | Used for the @Cofunctor :. Functor@ instance of 'Functor'-cofmapCF :: (Cofunctor g, Functor f) => (b -> a) -> (g :. f) a -> (g :. f) b-cofmapCF h (O gf) = O (cofmap (fmap h) gf)+-- | Used for the @ContraFunctor :. Functor@ instance of 'Functor'+contraFmapCF :: (ContraFunctor g, Functor f) => (b -> a) -> (g :. f) a -> (g :. f) b+contraFmapCF = inO.contraFmap.fmap +-- contraFmapCF h (O gf) = O (contraFmap (fmap h) gf)+ instance (Applicative g, Applicative f) => Applicative (g :. f) where pure = O . pure . pure (<*>) = (inO2.liftA2) (<*>)@@ -309,8 +379,6 @@ -{-- -- A first pass at monad composition. But now I've read "Composing -- Monads", and I know there's more to it. At least four different ways, -- all with conflicting Monad instances.@@ -321,44 +389,63 @@ class DistribM m n where distribM :: n (m a) -> m (n a) -instance (Monad m, Monad n, DistribM m n) => Monad (m :. n) where- return = O . return . return- e >>= f = joinMM (liftM f e)---- | 'join' for @(m :. n)@-joinMM :: (Monad m, Monad n, DistribM m n) =>- (m :. n) ((m :. n) a) -> (m :. n) a-joinMM = O . liftM join . join . liftM distribM . unO . liftM unO+-- | A candidate 'join' for @(m :. n)@+joinDistribM :: (Monad m, Monad n, DistribM m n) =>+ (m :. n) ((m :. n) a) -> (m :. n) a+joinDistribM = O . liftM join . join . liftM distribM . (liftM.liftM) unO . unO -- Derivation: -- -- (m :. n) ((m :. n) a)--- --> m (n (m (n a))) -- liftM unO -- --> m (n ((m :. n) a)) -- unO+-- --> m (n (m (n a))) -- (liftM.liftM) unO -- --> m (m (n (n a))) -- liftM distribM -- --> m (n (n a)) -- join -- --> m (n a) -- liftM join -- --> (m :. n) a -- O --}+-- | A candidate '(>>=)' for @(m :. n)@+bindDistribM :: (Functor m, Functor n, Monad m, Monad n, DistribM m n) =>+ (m :. n) a -> (a -> (m :. n) b) -> (m :. n) b+mn `bindDistribM` f = joinDistribM (fmap f mn) +returnDistribM :: (Monad m, Monad n) => a -> (m :. n) a+returnDistribM = O . return . return +-- Template for specialization:+-- +-- instance (Functor m, Functor n, Monad m, Monad n, DistribM m n) +-- => Monad (m :. n) where+-- return = returnDistribM+-- (>>=) = bindDistribM++-- | 'join'-like function for implicitly composed monads+joinMMT :: (Monad m, Monad n, Traversable n, Applicative m) =>+ m (n (m (n a))) -> m (n a)+joinMMT = fmap join . join . fmap sequenceA++-- | 'join'-like function for explicitly composed monads+joinComposeT :: (Monad m, Monad n, Traversable n, Applicative m) =>+ (m :. n) ((m :. n) a) -> (m :. n) a+joinComposeT = O . joinMMT . unO . fmap unO++ {---------------------------------------------------------- Unary\/binary composition ----------------------------------------------------------} -- | Composition of type constructors: unary with binary. Called -- "StaticArrow" in [1].-newtype OO f (~>) a b = OO { unOO :: f (a ~> b) }+newtype OO f j a b = OO { unOO :: f (a `j` b) } #if __GLASGOW_HASKELL__ >= 609-instance (Applicative f, Category (~>)) => Category (OO f (~>)) where+instance (Applicative f, Category cat) => Category (OO f cat) where id = OO (pure id) OO g . OO h = OO (liftA2 (.) g h) #endif -instance (Applicative f, Arrow (~>)) => Arrow (OO f (~>)) where+instance (Applicative f, Arrow arr) => Arrow (OO f arr) where #if __GLASGOW_HASKELL__ < 609 OO g >>> OO h = OO (liftA2 (>>>) g h) #endif@@ -490,39 +577,42 @@ ----------------------------------------------------------} -- | Flip type arguments-newtype Flip (~>) b a = Flip { unFlip :: a ~> b }+newtype Flip j b a = Flip { unFlip :: a `j` b } -- | @newtype@ bijection-biFlip :: (a ~> b) :<->: Flip (~>) b a+biFlip :: (a `j` b) :<->: Flip j b a biFlip = Bi Flip unFlip -- Apply unary function inside of a 'Flip' representation.-inFlip :: ((a~>b) -> (a' ~~> b')) -> (Flip (~>) b a -> Flip (~~>) b' a')+inFlip :: ((a `j` b) -> (a' `k` b')) -> (Flip j b a -> Flip k b' a') inFlip = unFlip ~> Flip -- Apply binary function inside of a 'Flip' representation.-inFlip2 :: ((a~>b) -> (a' ~~> b') -> (a'' ~~~> b''))- -> (Flip (~>) b a -> Flip (~~>) b' a' -> Flip (~~~>) b'' a'')+inFlip2 :: ((a `j` b) -> (a' `k` b') -> (a'' `l` b''))+ -> (Flip j b a -> Flip k b' a' -> Flip l b'' a'') inFlip2 f (Flip ar) = inFlip (f ar) -- Apply ternary function inside of a 'Flip' representation.-inFlip3 :: ((a~>b) -> (a' ~~> b') -> (a'' ~~~> b'') -> (a''' ~~~~> b'''))- -> (Flip (~>) b a -> Flip (~~>) b' a' -> Flip (~~~>) b'' a'' -> Flip (~~~~>) b''' a''')+inFlip3 :: ((a `j` b) -> (a' `k` b') -> (a'' `l` b'') -> (a''' `m` b'''))+ -> (Flip j b a -> Flip k b' a' -> Flip l b'' a'' -> Flip m b''' a''') inFlip3 f (Flip ar) = inFlip2 (f ar) -instance Arrow (~>) => Cofunctor (Flip (~>) b) where- cofmap h (Flip f) = Flip (arr h >>> f)+instance Arrow arr => ContraFunctor (Flip arr b) where+ contraFmap h (Flip f) = Flip (arr h >>> f) +instance (Applicative (j a), Sem.Semigroup o) => Sem.Semigroup (Flip j o a) where+ (<>) = inFlip2 (liftA2 (Sem.<>))+ -- Useful for (~>) = (->). Maybe others.-instance (Applicative ((~>) a), Monoid o) => Monoid (Flip (~>) o a) where+instance (Applicative (j a), Monoid o) => Monoid (Flip j o a) where mempty = Flip (pure mempty)- mappend = inFlip2 (liftA2 mappend)+ mappend = (<>) -- TODO: generalize (->) to (~>) with Applicative_f (~>) instance Monoid o => Monoid_f (Flip (->) o) where { mempty_f = mempty ; mappend_f = mappend } --- | (-> IO ()) as a 'Flip'. A Cofunctor.+-- | (-> IO ()) as a 'Flip'. A ContraFunctor. type OI = Flip (->) (IO ()) -- | Convert to an 'OI'.@@ -563,22 +653,42 @@ inApp2 h (App fa) = inApp (h fa) -- Example: App IO ()+instance (Applicative f, Sem.Semigroup m) => Sem.Semigroup (App f m) where+ (<>) = inApp2 (liftA2 (Sem.<>))+ instance (Applicative f, Monoid m) => Monoid (App f m) where mempty = App (pure mempty )- mappend = inApp2 (liftA2 mappend)+ mappend = (<>) -- App a `mappend` App b = App (liftA2 mappend a b) {----------------------------------------------------------- Identity -- TODO: eliminate in favor of Data.Traversable.Id+ Identity ----------------------------------------------------------} -- | Identity type constructor. Until there's a better place to find it. -- I'd use "Control.Monad.Identity", but I don't want to introduce a -- dependency on mtl just for Id.-newtype Id a = Id { unId :: a }+newtype Id a = Id a deriving ( Eq, Show, Ord+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702+ , Generic+#endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706+ , Generic1+#endif+ ) +-- Could define record field:+-- +-- newtype Id a = Id { unId :: a } deriving Show+-- +-- but then Show is uglier.++-- Extract value from an 'Id'+unId :: Id a -> a+unId (Id a) = a+ inId :: (a -> b) -> (Id a -> Id b) inId = unId ~> Id @@ -596,6 +706,22 @@ pure = Id (<*>) = inId2 ($) +instance Monad Id where+ return = pure+ Id x >>= f = f x++instance Foldable Id where+ foldMap f (Id a) = f a+ -- foldMap f = f . unId+ -- foldMap = (. unId)++instance Traversable Id where+ sequenceA (Id fa) = fmap Id fa++-- Id fa :: Id (f a)+-- fa :: f a+-- fmap Id fa = f (Id a)+ {---------------------------------------------------------- Unary constructor pairing ----------------------------------------------------------}@@ -604,6 +730,10 @@ newtype (f :*: g) a = Prod { unProd :: (f a, g a) } -- deriving (Show, Eq, Ord) +-- | Handy infix & curried 'Prod'+(*:*) :: f a -> g a -> (f :*: g) a+(*:*) = curry Prod+ -- | @newtype@ bijection biProd :: (f a, g a) :<->: (f :*: g) a biProd = Bi Prod unProd@@ -678,6 +808,10 @@ newtype (f ::*:: g) a b = Prodd { unProdd :: (f a b, g a b) } deriving (Show, Eq, Ord) +-- | Handy infix & curried 'Prodd'+(*::*) :: f a b -> g a b -> (f ::*:: g) a b+(*::*) = curry Prodd+ -- -- Remove the next three when GHC can derive them (6.8). -- instance (Show (f a b, g a b)) => Show ((f ::*:: g) a b) where@@ -724,47 +858,50 @@ -- | Arrow-like type between type constructors (doesn't enforce @Arrow -- (~>)@ here).-newtype Arrw (~>) f g a = Arrw { unArrw :: f a ~> g a } -- deriving Monoid+newtype Arrw j f g a = Arrw { unArrw :: f a `j` g a } -- deriving Monoid -- For ghc-6.6, use the "deriving" above, but for 6.8 use the "deriving" below. -deriving instance Monoid (f a ~> g a) => Monoid (Arrw (~>) f g a)+deriving instance Sem.Semigroup (f a `j` g a) => Sem.Semigroup (Arrw j f g a)+deriving instance Monoid (f a `j` g a) => Monoid (Arrw j f g a) -- Replace with generalized bijection? --- toArrw :: Arrow (~>) => (f a ~> b) -> (c ~> g a) -> ((b ~> c) -> Arrw (~>) f g a)+-- toArrw :: Arrow j => (f a ~> b) -> (c ~> g a) -> ((b ~> c) -> Arrw j f g a) -- toArrw fromF toG h = Arrw (fromF >>> h >>> toG) --- fromArrw :: Arrow (~>) => (b ~> f a) -> (g a ~> c) -> (Arrw (~>) f g a -> (b ~> c))+-- fromArrw :: Arrow j => (b ~> f a) -> (g a ~> c) -> (Arrw j f g a -> (b ~> c)) -- fromArrw toF fromG (Arrw h') = toF >>> h' >>> fromG -- | Apply unary function inside of @Arrw@ representation.-inArrw :: ((f a ~> g a) -> (f' a' ~> g' a'))- -> ((Arrw (~>) f g) a -> (Arrw (~>) f' g') a')+inArrw :: ((f a `j` g a) -> (f' a' `j` g' a'))+ -> ((Arrw j f g) a -> (Arrw j f' g') a') inArrw = unArrw ~> Arrw --- | Apply binary function inside of @Arrw (~>) f g@ representation.-inArrw2 :: ((f a ~> g a) -> (f' a' ~> g' a') -> (f'' a'' ~> g'' a''))- -> (Arrw (~>) f g a -> Arrw (~>) f' g' a' -> Arrw (~>) f'' g'' a'')+-- | Apply binary function inside of @Arrw j f g@ representation.+inArrw2 :: ((f a `j` g a) -> (f' a' `j` g' a') -> (f'' a'' `j` g'' a''))+ -> (Arrw j f g a -> Arrw j f' g' a' -> Arrw j f'' g'' a'') inArrw2 h (Arrw p) = inArrw (h p) --- | Apply ternary function inside of @Arrw (~>) f g@ representation.-inArrw3 :: ((f a ~> g a) -> (f' a' ~> g' a') -> (f'' a'' ~> g'' a'') -> (f''' a''' ~> g''' a'''))- -> ((Arrw (~>) f g) a -> (Arrw (~>) f' g') a' -> (Arrw (~>) f'' g'') a'' -> (Arrw (~>) f''' g''') a''')+-- | Apply ternary function inside of @Arrw j f g@ representation.+inArrw3 ::+ ((f a `j` g a) -> (f' a' `j` g' a') ->+ (f'' a'' `j` g'' a'') -> (f''' a''' `j` g''' a'''))+ -> ((Arrw j f g) a -> (Arrw j f' g') a' -> (Arrw j f'' g'') a'' -> (Arrw j f''' g''') a''') inArrw3 h (Arrw p) = inArrw2 (h p) --- Functor & Cofunctor instances. Beware use of 'arr', which is not+-- Functor & ContraFunctor instances. Beware use of 'arr', which is not -- available for some of my favorite arrows. -instance (Arrow (~>), Cofunctor f, Functor g) => Functor (Arrw (~>) f g) where- fmap h = inArrw $ \ fga -> arr (cofmap h) >>> fga >>> arr (fmap h)+instance (Arrow j, ContraFunctor f, Functor g) => Functor (Arrw j f g) where+ fmap h = inArrw $ \ fga -> arr (contraFmap h) >>> fga >>> arr (fmap h) -instance (Arrow (~>), Functor f, Cofunctor g) => Cofunctor (Arrw (~>) f g) where- cofmap h = inArrw $ \ fga -> arr (fmap h) >>> fga >>> arr (cofmap h)+instance (Arrow j, Functor f, ContraFunctor g) => ContraFunctor (Arrw j f g) where+ contraFmap h = inArrw $ \ fga -> arr (fmap h) >>> fga >>> arr (contraFmap h) -- Restated, -- --- cofmap h = inArrw $ (arr (fmap h) >>>) . (>>> arr (cofmap h))+-- contraFmap h = inArrw $ (arr (fmap h) >>>) . (>>> arr (contraFmap h)) -- 'Arrw' specialized to functions. type (:->:) = Arrw (->)@@ -807,9 +944,6 @@ ---- For Control.Applicative.Endo -- deriving instance Monoid o => Monoid (Const o a)-instance Monoid o => Monoid (Const o a) where- mempty = Const mempty- mappend = inConst2 mappend -- newtype Endo a = Endo { appEndo :: a -> a }
src/Control/Instances.hs view
@@ -1,28 +1,20 @@-{-# OPTIONS_GHC -fno-warn-orphans #-} ---------------------------------------------------------------------- -- | -- Module : Control.Instances -- Copyright : (c) Conal Elliott 2007 -- License : BSD3--- +-- -- Maintainer : conal@conal.net -- Stability : experimental -- Portability : portable--- +-- -- Some (orphan) instances that belong elsewhere (where they wouldn't be orphans). -- Add the following line to get these instances--- +-- -- > import Control.Instances ()--- +-- ---------------------------------------------------------------------- module Control.Instances () where -import Data.Monoid-import Control.Applicative----- Standard instance: Applicative functor applied to monoid-instance Monoid o => Monoid (IO o) where - mempty = pure mempty- mappend = liftA2 mappend+import Data.Orphans ()
src/Data/Bijection.hs view
@@ -33,7 +33,7 @@ infixr 2 ---> -- | A type of bijective arrows-data Bijection (~>) a b = Bi { biTo :: a ~> b, biFrom :: b ~> a }+data Bijection j a b = Bi { biTo :: a `j` b, biFrom :: b `j` a } -- | Bijective functions type a :<->: b = Bijection (->) a b@@ -41,20 +41,20 @@ -- | Bijective identity arrow. Warning: uses 'arr' on @(~>)@. If you -- have no 'arr', but you have a @DeepArrow@, you can instead use @Bi idA -- idA@.-idb :: Arrow (~>) => Bijection (~>) a a+idb :: Arrow j => Bijection j a a idb = Bi idA idA where idA = arr id -- | Inverse bijection-inverse :: Bijection (~>) a b -> Bijection (~>) b a+inverse :: Bijection j a b -> Bijection j b a inverse (Bi ab ba) = Bi ba ab #if __GLASGOW_HASKELL__ >= 609-instance Category (~>) => Category (Bijection (~>)) where+instance Category j => Category (Bijection j) where id = Bi id id Bi bc cb . Bi ab ba = Bi (bc . ab) (ba . cb) #endif -instance Arrow (~>) => Arrow (Bijection (~>)) where+instance Arrow j => Arrow (Bijection j) where #if __GLASGOW_HASKELL__ < 609 Bi ab ba >>> Bi bc cb = Bi (ab >>> bc) (cb >>> ba) #endif@@ -75,10 +75,15 @@ bimap (Bi ab ba) = Bi (fmap ab) (fmap ba) -- | Bijections on arrows.-(--->) :: Arrow (~>) => Bijection (~>) a b -> Bijection (~>) c d- -> (a ~> c) :<->: (b ~> d)+(--->) :: Arrow j => Bijection j a b -> Bijection j c d+ -> (a `j` c) :<->: (b `j` d) Bi ab ba ---> Bi cd dc = Bi (\ ac -> ba>>>ac>>>cd) (\ bd -> ab>>>bd>>>dc) +-- TODO: Rewrite (--->) via (~>). Currently would cause a module cycle+-- +-- Bi ab ba ---> Bi cd dc = Bi (ac ~> cd) (ab ~> dc)++ -- | Apply a function in an alternative (monomorphic) representation.-inBi :: Arrow (~>) => Bijection (~>) a b -> (a ~> a) -> (b ~> b)+inBi :: Arrow j => Bijection j a b -> (a `j` a) -> (b `j` b) inBi (Bi to from) aa = from >>> aa >>> to
src/Data/CxMonoid.hs view
@@ -16,6 +16,7 @@ module Data.CxMonoid (MonoidDict, CxMonoid(..), biCxMonoid) where import Data.Monoid (Monoid(..))+import qualified Data.Semigroup as Sem import Data.Bijection import Data.Title@@ -30,10 +31,13 @@ biCxMonoid :: (MonoidDict a -> a) :<->: CxMonoid a biCxMonoid = Bi CxMonoid unCxMonoid +instance Sem.Semigroup (CxMonoid a) where+ CxMonoid f <> CxMonoid g =+ CxMonoid (\ md@(_,op) -> f md `op` g md)+ instance Monoid (CxMonoid a) where mempty = CxMonoid (\ (e,_) -> e)- CxMonoid f `mappend` CxMonoid g =- CxMonoid (\ md@(_,op) -> f md `op` g md)+ mappend = (Sem.<>) -- Exploit the function instance of 'Title' instance Title a => Title (CxMonoid a) where
src/Data/Lambda.hs view
@@ -93,13 +93,13 @@ -- | 'lambda' with 'Arrw'. /Warning/: definition uses 'arr', so only -- use if your arrow has a working 'arr'.-arLambda :: (Arrow (~>), Unlambda f f', Lambda g g')- => LambdaTy (Arrw (~>) f g) (Arrw (~>) f' g')+arLambda :: (Arrow j, Unlambda f f', Lambda g g')+ => LambdaTy (Arrw j f g) (Arrw j f' g') arLambda = inArrw2 $ \ fga fgb -> arr unlambda >>> fga***fgb >>> arr (uncurry lambda) -instance (Arrow (~>), Unlambda f f', Lambda g g')- => Lambda (Arrw (~>) f g) (Arrw (~>) f' g')+instance (Arrow j, Unlambda f f', Lambda g g')+ => Lambda (Arrw j f g) (Arrw j f' g') where lambda = arLambda
src/Data/Pair.hs view
@@ -95,8 +95,8 @@ -- Standard instance, e.g., (~>) = (->) -- This one requires UndecidableInstances. Alternatively, specialize to -- (->) and other arrows as desired.-instance (Arrow (~>), Monoid_f (Flip (~>) o)) =>- Pair (Flip (~>) o) where pair = copair+instance (Arrow j, Monoid_f (Flip j o)) =>+ Pair (Flip j o) where pair = copair -- | Handy for 'Pair' instances apPair :: (Applicative h, Pair f) => PairTy (h :. f)@@ -108,12 +108,12 @@ -- | Pairing of 'Arrw' values. /Warning/: definition uses 'arr', so only -- use if your arrow has a working 'arr'.-arPair :: (Arrow (~>), Unpair f, Pair g) => PairTy (Arrw (~>) f g)+arPair :: (Arrow j, Unpair f, Pair g) => PairTy (Arrw j f g) arPair = inArrw2 $ \ fga fgb -> arr unpair >>> fga***fgb >>> arr (uncurry pair) -- Standard instance-instance (Arrow (~>), Unpair f, Pair g) => Pair (Arrw (~>) f g)+instance (Arrow j, Unpair f, Pair g) => Pair (Arrw j f g) where pair = arPair instance (Pair f, Pair g) => Pair (f :*: g) where@@ -159,11 +159,11 @@ ----------------------------------------------------------} -- | Dual to 'Unpair'.--- Especially handy for contravariant functors ('Cofunctor') . Use this+-- Especially handy for contravariant functors ('ContraFunctor') . Use this -- template (filling in @f@) : -- -- --- > instance Cofunctor f => Copair f where+-- > instance ContraFunctor f => Copair f where -- > { cofsts = cofmap fst ; cosnds = cofmap snd } class Copair f where@@ -175,8 +175,8 @@ cosnds = inConst id -- Standard instance for contravariant functors-instance Arrow (~>) => Copair (Flip (~>) o) where- { cofsts = cofmap fst ; cosnds = cofmap snd }+instance Arrow j => Copair (Flip j o) where+ { cofsts = contraFmap fst ; cosnds = contraFmap snd } instance (Functor h, Copair f) => Copair (h :. f) where cofsts = inO (fmap cofsts)
src/Data/Partial.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# OPTIONS_GHC -Wall #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} ---------------------------------------------------------------------- -- | -- Module : Data.Partial@@ -13,8 +14,8 @@ -- A monoid 'Partial' of partial values. See the [Teaser] and [Solution] blog -- posts. -- --- [Teaser]: <http://conal-elliott.blogspot.com/2007/07/type-for-partial-values.html>--- [Solution]: <http://conal-elliott.blogspot.com/2007/07/implementing-type-for-partial-values.html>+-- [Teaser]: <http://conal.net/blog/posts/a-type-for-partial-values>+-- [Solution]: <http://conal.net/blog/posts/implementing-a-type-for-partial-values> -- -- Also defines a 'FunAble' instance, so that @FunA Partial@ is an arrow. ----------------------------------------------------------------------
src/Data/Title.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleInstances, OverlappingInstances, TypeOperators, TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances, TypeOperators, TypeSynonymInstances #-} {-# OPTIONS_GHC -Wall #-} ---------------------------------------------------------------------- -- |@@ -40,7 +40,8 @@ instance Title_f g => Title_f (g :. f) where title_f str = inO (title_f str) -instance Title_f f => Title (f a) where title = title_f+instance {-# OVERLAPPABLE #-} Title_f f => Title (f a) where+ title = title_f instance Title String where title ttl str = (ttl ++ suffix ++ str)
src/Data/Zip.hs view
@@ -5,7 +5,9 @@ #else {-# OPTIONS_GHC -fenable-rewrite-rules #-} #endif+{-# OPTIONS_GHC -Wno-inline-rule-shadowing #-} + ---------------------------------------------------------------------- -- | -- Module : Data.Zip@@ -126,8 +128,8 @@ -- Standard instance, e.g., (~>) = (->) -- This one requires UndecidableInstances. Alternatively, specialize to -- (->) and other arrows as desired.-instance (Arrow (~>), Monoid_f (Flip (~>) o)) =>- Zip (Flip (~>) o) where zip = cozip+instance (Arrow j, Monoid_f (Flip j o)) =>+ Zip (Flip j o) where zip = cozip -- | Handy for 'Zip' instances apZip :: (Applicative h, Zip f) => ZipTy (h :. f)@@ -139,12 +141,12 @@ -- | Ziping of 'Arrw' values. /Warning/: definition uses 'arr', so only -- use if your arrow has a working 'arr'.-arZip :: (Arrow (~>), Unzip f, Zip g) => ZipTy (Arrw (~>) f g)+arZip :: (Arrow j, Unzip f, Zip g) => ZipTy (Arrw j f g) arZip = inArrw2 $ \ fga fgb -> arr unzip >>> fga***fgb >>> arr (uncurry zip) -- Standard instance-instance (Arrow (~>), Unzip f, Zip g) => Zip (Arrw (~>) f g)+instance (Arrow j, Unzip f, Zip g) => Zip (Arrw j f g) where zip = arZip instance (Zip f, Zip g) => Zip (f :*: g) where@@ -206,8 +208,8 @@ cosnds = inConst id -- Standard instance for contravariant functors-instance Arrow (~>) => Cozip (Flip (~>) o) where- { cofsts = cofmap fst ; cosnds = cofmap snd }+instance Arrow j => Cozip (Flip j o) where+ { cofsts = contraFmap fst ; cosnds = contraFmap snd } instance (Functor h, Cozip f) => Cozip (h :. f) where cofsts = inO (fmap cofsts)
− wikipage.tw
@@ -1,55 +0,0 @@-[[Category:Composition]]-[[Category:Applicative]]-[[Category:Libraries]]-[[Category:Packages]]-[[Category:Type-level programming]]--== Abstract ==--'''TypeCompose''' provides some classes & instances for forms of type composition, as well as some modules that haven't found another home.--Besides this wiki page, here are more ways to find out about TypeCompose:-* Visit the [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/TypeCompose Hackage page] for library documentation and to download & install.-* Or install with <tt>cabal install TypeCompose</tt>.-* Get the code repository: <tt>darcs get http://darcs.haskell.org/packages/TypeCompose</tt>.-<!--* See the [[TypeCompose/Versions| version history]].-->--== Type composition ==--The <hask>Control.Compose</hask> module includes-* Various type compositions (unary/unary, binary/unary, etc). Most are from [http://www.soi.city.ac.uk/~ross/papers/Applicative.html Applicative Programming with Effects]. In particular, <hask>g `O` f</hask> composes functors in to functors and applicative functors (AFs) into AFs. (In contrast, monads do not in general compose.) Composition makes AF-based programming simple and elegant, partly because we don't need an AF counterpart to monad transformers.-* Cofunctors (contravariant functors). Great for "consumer" types, just as functors suit "producer" (container) types. There are several composition options.-* Type argument flip. Handy for cofunctors: use <hask>Flip (->) o</hask>, for <hask>(-> o)</hask>.-* Constructor in pairs: <hask>(f a, g a)</hask>.-* Constructor in arrows/functions: <hask>f a ~> g a</hask>.--== Other features ==--=== Composable bijections ===--Given all the type constructors and compositions of them, I found myself writing some pretty awkward code to wrap & unwrap through multiple layers. Composable bijections help a lot.--The <hask>Data.Bijection</hask> module is inspired by [http://citeseer.ist.psu.edu/alimarine05there.html There and Back Again: Arrows for Invertible Programming], though done here in a less general setting.--=== Pair- & function-like types ===--The <hask>Data.Zip</hask> and <hask>Data.Lambda</hask> patterns emerged while working on [[DeepArrow]] and [[Eros]]. <hask>Data.Zip</hask> generalizes <hask>zip</hask> and <hask>unzip</hask> from <hask>[]</hask> to other functors. It also provides variants of type <hask>f a -> f (a,b)</hask> and <hask>f a -> f (a,b)</hask>. <hask>Data.Lambda</hask> is similar with classes for lambda-like constructions.--For example uses of <hask>Pair</hask> and <hask>Lambda</hask>, see [[TV]] and [[Eros]].--=== References ===--Monads with references. Direct rip-off from [http://citeseer.ist.psu.edu/473734.html Global Variables in Haskell].--=== Titling ===--For giving titles to things. I know it sounds kind of random. More useful than I first thought. Used in [[Phooey]], [[TV]], and [[Eros]].--=== Partial values ===--A monoid of partial values. See the [http://conal.net/blog/posts/a-type-for-partial-values/ teaser] and [http://conal.net/blog/posts/implementing-a-type-for-partial-values/ solution] blog-posts.--=== Context-dependent monoids ===--Bit of an oddball also. <hask>Data.CxMonoid</hask> defines a sort of meta-monoid, that can be supplied dynamically with choices of <hask>mempty</hask> and <hask>mappend</hask>. Used in [[Phooey]] (starting with version 1.3) so that layout could be a monoid but still vary in style.