diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for magmas
+
+## 0.0.1  -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,14 @@
+BSD 3-Clause License
+
+Copyright Christopher McKinlay (c) 2020
+
+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. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+
diff --git a/magmas.cabal b/magmas.cabal
new file mode 100644
--- /dev/null
+++ b/magmas.cabal
@@ -0,0 +1,34 @@
+name:                magmas
+version:             0.0.1
+synopsis:            Magma-like objects.
+description:         Magmas, quasigroups, loops and groups.
+homepage:            https://github.com/cmk/magmas
+license:             BSD3
+license-file:        LICENSE
+author:              Chris McKinlay
+maintainer:          chris.mckinlay@gmail.com
+category:            Math, Numerical
+stability:           Experimental
+build-type:          Simple
+tested-with:         GHC == 8.6.3
+extra-source-files:  ChangeLog.md
+cabal-version:       >=1.10
+
+library
+
+  hs-source-dirs:   src
+  default-language: Haskell2010
+
+  exposed-modules:
+      Data.Group
+    , Data.Magma
+
+  default-extensions:
+      Safe
+    , DefaultSignatures
+    , UndecidableInstances
+    , FlexibleContexts
+    , FlexibleInstances
+
+  build-depends:       
+      base           >= 4.10    && < 5.0
diff --git a/src/Data/Group.hs b/src/Data/Group.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Group.hs
@@ -0,0 +1,178 @@
+module Data.Group (
+    Group(..)
+  , Loop(..)
+  , Quasigroup(..)
+  , Monoid(..)
+  , mreplicate
+  , Semigroup(..)
+  , Magma(..)
+) where
+
+import safe Data.Magma
+import safe Data.Semigroup
+import safe Numeric.Natural
+
+--  x << y = x <> inv y
+--  inv x = mempty << x
+class (Loop a, Monoid a) => Group a where
+
+  inv :: a -> a
+  inv x = mempty << x
+
+  greplicate :: Integer -> a -> a
+  greplicate n a     
+      | n == 0 = mempty
+      | n > 0 = mreplicate (fromInteger n) a
+      | otherwise = mreplicate (fromInteger $ abs n) (inv a)
+
+instance (Semigroup a, Quasigroup (Maybe a)) => Group (Maybe a) where
+
+-- | A generalization of 'Data.List.replicate' to an arbitrary 'Monoid'. 
+--
+-- Adapted from <http://augustss.blogspot.com/2008/07/lost-and-found-if-i-write-108-in.html>.
+--
+mreplicate :: Monoid a => Natural -> a -> a
+mreplicate n a
+    | n == 0 = mempty
+    | otherwise = f a n
+    where
+        f x y 
+            | even y = f (x <> x) (y `quot` 2)
+            | y == 1 = x
+            | otherwise = g (x <> x) ((y - 1) `quot` 2) x
+        g x y z 
+            | even y = g (x <> x) (y `quot` 2) z
+            | y == 1 = x <> z
+            | otherwise = g (x <> x) ((y - 1) `quot` 2) (x <> z)
+{-# INLINE mreplicate #-}
+
+
+
+{-
+Every group is a loop, because a ∗ x = b if and only if x = a−1 ∗ b, and y ∗ a = b if and only if y = b ∗ a−1.
+The integers Z with subtraction (−) form a quasigroup.
+The nonzero rationals Q× (or the nonzero reals R×) with division (÷) form a quasigroup.
+https://en.wikipedia.org/wiki/Mathematics_of_Sudoku#Sudokus_from_group_tables
+-}
+class Quasigroup a => Loop a where
+
+  lempty :: a
+  default lempty :: Monoid a => a
+  lempty = mempty
+
+  lreplicate :: Natural -> a -> a
+  default lreplicate :: Group a => Natural -> a -> a
+  lreplicate n = mreplicate n . inv
+
+instance (Semigroup a, Quasigroup (Maybe a)) => Loop (Maybe a)
+
+{-
+Idempotent total symmetric quasigroups are precisely (i.e. in a bijection with) Steiner triples, so such a quasigroup is also called a Steiner quasigroup, and sometimes the latter is even abbreviated as squag; the term sloop is defined similarly for a Steiner quasigroup that is also a loop. Without idempotency, total symmetric quasigroups correspond to the geometric notion of extended Steiner triple, also called Generalized Elliptic Cubic Curve (GECC). 
+
+< https://en.wikipedia.org/wiki/Steiner_system >
+type Steiner a = (Symmetric a, IdempotentMagma a)
+type Sloop a = (Steiner a, Loop a)
+
+A quasigroup (Q, <<) is called totally anti-symmetric if for all c, x, y ∈ Q, both of the following implications hold:
+
+    (c << x) << y == (c << y) << x ==> x == y
+    x << y == y << x ==> x == y
+
+It is called weakly totally anti-symmetric if only the first implication holds.[5]
+
+This property is required, for example, in the < https://en.wikipedia.org/wiki/Damm_algorithm Damm algorithm >. 
+class Quasigroup a => Antisymmetric a
+
+
+-- https://en.wikipedia.org/wiki/Bol_loop
+-- x << (y << (x << z)) = (x << (y << x)) << z     for each x, y and z in Q (a left Bol loop)
+class Loop a => LeftBol a
+
+-- ((z << x) << y) << x = z << ((x << y) << x)     for each x, y and z in Q (a right Bol loop)
+class Loop a => RightBol a
+
+A loop that is both a left and right Bol loop is a Moufang loop. 
+This is equivalent to any one of the following single Moufang identities holding for all x, y, z:
+
+x << (y << (x << z)) = ((x << y) << x) << z,
+z << (x << (y << x)) = ((z << x) << y) << x,
+(x << y) << (z << x) = x << ((y << z) << x), or
+(x << y) << (z << x) = (x << (y << z)) << x.
+
+-- The nonzero octonions form a nonassociative Moufang loop under multiplication.
+class (LeftBol a, RightBol a) => Moufang a
+
+
+< https://en.wikipedia.org/wiki/Planar_ternary_ring >
+
+-- The structure ( R , ++ ) is a loop with identity element /zero'/. 
+-- The set R 0 = R ∖ { 0 } is closed under this multiplication. The structure ( R 0 , ** ) {\displaystyle (R_{0},\otimes )} (R_{{0}},\otimes ) is also a loop, with identity element 1. 
+class Ternary a where
+  t :: a -> a -> a -> a
+  zero' :: a
+  one' :: a
+a ++ b = t a one' b
+a ** b = t a b zero'
+
+-- ? type Planar a = ((Additive-Ternary) a, (Multiplicative-Ternary) a)
+
+-- | < https://en.wikipedia.org/wiki/Planar_ternary_ring#Linear_PTR >
+--
+-- @ 't' a b c = (a '#' b) '%' c @
+--
+-- ? type Linear a = ((Additive-Loop) a, (Multiplicative-Loop) a)
+
+instance Ternary a => (Additive-Loop) a where
+-}
+
+{-
+-- A quasigroup is semisymmetric if the following equivalent identities hold:
+
+    x << y = y // x,
+    y << x = x \\ y,
+    x = (y << x) << y,
+    x = y << (x << y).
+
+--class Quasigroup a => Semisymmetric a
+
+
+A narrower class that is a totally symmetric quasigroup (sometimes abbreviated TS-quasigroup) in which all conjugates coincide as one operation: xy = x / y = x \ y. Another way to define (the same notion of) totally symmetric quasigroup is as a semisymmetric quasigroup which also is commutative, i.e. xy = yx.
+
+-- x << y = x // y = x \\ y.
+
+--type Symmetric a = (Semisymmetric a, AbelianMagma a)
+
+Idempotent total symmetric quasigroups are precisely (i.e. in a bijection with) Steiner triples, so such a quasigroup is also called a Steiner quasigroup, and sometimes the latter is even abbreviated as squag; the term sloop is defined similarly for a Steiner quasigroup that is also a loop. Without idempotency, total symmetric quasigroups correspond to the geometric notion of extended Steiner triple, also called Generalized Elliptic Cubic Curve (GECC). 
+
+< https://en.wikipedia.org/wiki/Steiner_system >
+
+--type Steiner a = (Symmetric a, IdempotentMagma a)
+--type Sloop a = (Steiner a, Loop a)
+
+A quasigroup (Q, <<) is called totally anti-symmetric if for all c, x, y ∈ Q, both of the following implications hold:
+
+    (c << x) << y == (c << y) << x ==> x == y
+    x << y == y << x ==> x == y
+
+It is called weakly totally anti-symmetric if only the first implication holds.[5]
+
+This property is required, for example, in the < https://en.wikipedia.org/wiki/Damm_algorithm Damm algorithm >. 
+--class Quasigroup a => Antisymmetric a
+-}
+
+
+-- (<<) has the < https://en.wikipedia.org/wiki/Latin_square_property >.
+-- The unique solutions to these equations are written x = a \\ b and y = b // a. The operations '\\' and '//' are called, respectively, left and right division. 
+
+-- https://en.wikipedia.org/wiki/Quasigroup
+-- in a group (//) = (\\) = (<>)
+class Magma a => Quasigroup a where
+  (//) :: a -> a -> a
+  default (//) :: Semigroup a => a -> a -> a
+  (//) = (<>)
+
+  (\\) :: a -> a -> a
+  default (\\) :: Semigroup a => a -> a -> a
+  (\\) = (<>)
+
+
diff --git a/src/Data/Magma.hs b/src/Data/Magma.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Magma.hs
@@ -0,0 +1,21 @@
+module Data.Magma where
+
+-- (<<) has the < https://en.wikipedia.org/wiki/Latin_square_property >.
+{-
+
+https://en.wikipedia.org/wiki/Magma_(algebra)
+https://en.wikipedia.org/wiki/Alternativity
+https://en.wikipedia.org/wiki/Power_associativity
+https://en.wikipedia.org/wiki/Medial_magma
+https://en.wikipedia.org/wiki/Unipotent
+-}
+
+
+infixl 6 <<
+
+-- When /a/ is a 'Group' we must have:
+-- @ x '<<' y = x '<>' 'inv' y @
+class Magma a where
+  (<<) :: a -> a -> a
+
+--instance Magma a => Magma (Maybe a)
