diff --git a/Graphics/OpenSCAD.hs b/Graphics/OpenSCAD.hs
--- a/Graphics/OpenSCAD.hs
+++ b/Graphics/OpenSCAD.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,	FunctionalDependencies #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
 
 {- |
 Module      : Graphics.OpenSCAD
@@ -120,7 +120,7 @@
   -- ** 'Facet's.
   var, fn, fs, fa, def,
   -- ** General convenience functions
-  diam, draw, drawL,
+  diam, draw, drawL, (#),
   module Colours)
 
 where
@@ -129,6 +129,8 @@
 import Data.Colour.Names as Colours
 import Data.Colour.SRGB (channelRed, channelBlue, channelGreen, toSRGB)
 import Data.List (elemIndices, nub, intercalate)
+import Data.List.NonEmpty (toList)
+import Data.Semigroup (Semigroup((<>), sconcat), Monoid(mconcat, mempty, mappend))
 import System.FilePath (FilePath)
 
 -- A vector in 2 or 3-space. They are used in transformations of
@@ -249,7 +251,7 @@
 -- the points, it now needs to be in an extra level of 'List'.
 polygon ::  Int -> [[Vector2d]] -> Model2d
 polygon convexity paths = Shape . Polygon convexity points
-                  $ map (concatMap (\p -> elemIndices p points)) paths
+                  $ map (concatMap (`elemIndices` points)) paths
   where points = nub $ concat paths
 
 -- | 'offset' a 'Model2d's edges by @offset /delta join/@.
@@ -263,7 +265,7 @@
 
 -- | Create a box with @cube /x-size y-size z-size/@
 box :: Double -> Double -> Double -> Model3d
-box x y z= Solid $ Box x y z
+box x y z = Solid $ Box x y z
 
 -- | A convenience function for creating a cube as a 'box' with all
 -- sides the same length.
@@ -292,7 +294,7 @@
 polyhedron ::  Int -> [[Vector3d]] -> Model3d
 polyhedron convexity paths = Solid . Polyhedron convexity points $ sides sin
   where points = nub $ concat paths
-        sin = map (concatMap (\p -> elemIndices p points)) paths
+        sin = map (concatMap (`elemIndices` points)) paths
         sides ss | any ((> 3) . length) ss  = Faces sin
                  | all ((== 3) . length) ss = Triangles sin
                  | otherwise = error "All faces must have at least 3 sides."
@@ -465,12 +467,12 @@
 rSolid (ToSolid s) = render s
 
 -- render a list of vectors as an Openscad vector of vectors.
-rVectorL vs = "[" ++ (intercalate "," $ map rVector vs) ++ "]"
+rVectorL vs = "[" ++ intercalate "," (map rVector vs) ++ "]"
 
 -- render a Sides.
 rSides (Faces vs) = ",faces=" ++ rListL vs
 rSides (Triangles vs) = ",triangles=" ++ rListL vs
-rListL vs = "[" ++ (intercalate "," $ map show vs) ++ "]"
+rListL vs = "[" ++ intercalate "," (map show vs) ++ "]"
 
 -- | A convenience function to render a list of 'Model's by taking
 -- their union.
@@ -529,3 +531,17 @@
 diam :: Double -> Double
 diam = (/ 2)
 
+-- Now, let Haskell work it's magic
+instance Vector v => Semigroup (Model v) where
+  a <> b = union [a, b]
+  sconcat = union . toList
+
+instance Vector v => Monoid (Model v) where
+  mempty = Solid $ Box 0 0 0
+  mappend a b = union [a, b]
+  mconcat = union
+
+-- | You can use '(#)' to write transformations in a more readable postfix form, 
+--   cube 3 # color red # translate (-3, -3, -3)
+infixl 8 #
+(#) = flip ($)
diff --git a/Graphics/OpenSCAD/Unicode.hs b/Graphics/OpenSCAD/Unicode.hs
--- a/Graphics/OpenSCAD/Unicode.hs
+++ b/Graphics/OpenSCAD/Unicode.hs
@@ -11,6 +11,7 @@
 
 module Graphics.OpenSCAD.Unicode where
 
+import Data.Semigroup ((<>))
 import Graphics.OpenSCAD
 
 infixl 6 ∪
@@ -22,7 +23,7 @@
 --
 -- U+222A, UNION
 (∪) :: Vector v => Model v -> Model v -> Model v
-a ∪ b = union [a, b]
+(∪) = (<>)
 
 -- | (&#x2229;) = 'intersection'
 --
diff --git a/OpenSCAD.cabal b/OpenSCAD.cabal
--- a/OpenSCAD.cabal
+++ b/OpenSCAD.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                OpenSCAD
-version:             0.2.1.0
+version:             0.2.1.1
 synopsis:            ADT wrapper and renderer for OpenSCAD models.
 description:         An algebraic data type for describing OpenSCAD models,
                      functions to make building such models easier, and
@@ -22,14 +22,24 @@
   exposed-modules:     Graphics.OpenSCAD, Graphics.OpenSCAD.Unicode
   -- other-modules:       
   other-extensions:    UnicodeSyntax
-  build-depends:       base >=4.6 && <4.8, colour >=2.3 && <2.4, filepath >=1.3 && <1.4
+  build-depends:       base >=4.6 && <4.8,
+                       colour >=2.3 && <2.4,
+                       filepath >=1.3 && <1.4,
+                       semigroups >= 0.15 && < 1.0
   -- hs-source-dirs:      
   default-language:    Haskell2010
 
 Test-Suite Units
   type:        exitcode-stdio-1.0
   main-is:     UnitTest.hs
-  build-depends: base >=4.6 && <4.8, colour >=2.3 && <2.4, filepath >=1.3 && <1.4, HUnit >=1.2 && <1.4, Cabal >= 1.18 && < 1.21, test-framework-hunit >=0.3 && < 0.5, test-framework >=0.8 && <1.0
+  build-depends: base >=4.6 && <4.8,
+                 colour >=2.3 && <2.4,
+                 filepath >=1.3 && <1.4,
+                 HUnit >=1.2 && <1.4,
+                 Cabal >= 1.18,
+                 test-framework-hunit >=0.3 && < 0.5,
+                 test-framework >=0.8 && < 1.0,
+                 semigroups >= 0.15 && < 1.0
   default-language:    Haskell2010
 
 source-repository head
@@ -39,4 +49,4 @@
 source-repository this
   type:           fossil
   location:       https://chiselapp.com/user/mwm/repository/OpenSCAD/
-  tag:            0.2.1
+  tag:            0.2.1.1
diff --git a/UnitTest.hs b/UnitTest.hs
--- a/UnitTest.hs
+++ b/UnitTest.hs
@@ -8,6 +8,8 @@
 
 import Graphics.OpenSCAD
 import Data.Colour (withOpacity)
+import Data.List.NonEmpty (fromList)
+import Data.Semigroup (sconcat)
 
 sw = concat . words
 st n e a = testCase n $ (sw e) @=?(sw $ render a)
@@ -203,6 +205,48 @@
        (var (fa 5) [sphere 2 $ fa 5]),
     st "facet 3" "assign($fs=0.1){sphere(2.0,$fs=0.1);}"
        (var (fs 0.1) [sphere 2 $ fs 0.1])
+    ],
+
+
+  testGroup "Combinations" [
+    st "union" "union(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (union [cube 1, sphere 1.1 $ fs 0.1]),
+    st "difference" "difference(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (difference (cube 1) . sphere 1.1 $ fs 0.1),
+    st "intersection" "intersection(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (intersection [cube 1, sphere 1.1 $ fs 0.1]),
+    st "minkowski"
+       "minkowski(){cube([10.0,10.0,10.0]);cylinder(r=2.0,h=1.1,$fn=50);}"
+       (minkowski [cube 10, cylinder 2 1.1 $ fn 50]),
+    st "hull" "hull(){translate([15.0,10.0])circle(10.0);circle(10.0);}"
+       (hull [circle 10 def # translate (15, 10), circle 10 def])
+    ],
+
+  testGroup "Haskell" [
+    st "# 3d" "translate([-3.0,-3.0,-3.0])color([1.0,0.0,0.0])cube([3.0,3.0,3.0]);"
+       (cube 3 # color red # translate (-3, -3, -3)),
+    st "# 2d"
+       "translate([3.0,3.0])color([1.0,0.6470588235294119,0.0])square([2.0,2.0]);"
+       (square 2 # color orange # translate (3, 3)),
+    st "Monoid 1 3d" "union(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (cube 1 <> sphere 1.1 (fs 0.1)),
+    st "Monoid 1 2d" "union(){square([1.0,1.0]);circle(1.1,$fs=0.1);}"
+       (square 1 <> circle 1.1 (fs 0.1)),
+    st "Monoid 2 3d" "union(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (mconcat [cube 1, sphere 1.1 $ fs 0.1]),
+    st "Monoid 2 2d" "union(){square([1.0,1.0]);circle(1.1,$fs=0.1);}"
+       (mconcat [square 1, circle 1.1 $ fs 0.1]),
+    st "Semigroup 1 3d" "cube([0.0,0.0,0.0]);" (solid mempty),
+    -- should we export a "shape" function?
+    st "Semigroup 1 2d" "cube([0.0,0.0,0.0]);" (mempty :: Model2d),
+    st "Semigroup 2 3d" "union(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (mappend (cube 1) $ sphere 1.1 (fs 0.1)),
+    st "Semigroup 2 2d" "union(){square([1.0,1.0]);circle(1.1,$fs=0.1);}"
+       (mappend (square 1) $ circle 1.1 (fs 0.1)),
+    st "Semigroup 3 3d" "union(){cube([1.0,1.0,1.0]);sphere(1.1,$fs=0.1);}"
+       (sconcat $ fromList [cube 1, sphere 1.1 $ fs 0.1]),
+    st "Semigroup 3 2d" "union(){square([1.0,1.0]);circle(1.1,$fs=0.1);}"
+       (sconcat $ fromList [square 1, circle 1.1 $ fs 0.1])
     ]
   ]
 
