diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,40 @@
+
+## symantic-base-0.3.0.20211007 (2021-10-07)
+
+### Interface
+
+* Add `(<.)` and `(.>)` to class `ProductFunctor`.
+* Add class `Inferable`.
+* Add classes `Emptyable` and `Semigroupable`.
+* Add `CurryN` to the root import.
+* Add class `SumFunctor`.
+* Add instance `Category Iso`.
+* Change `(==)` to curryed form.
+* Change to `infixr` classes `ProductFunctor` and `SumFunctor`.
+* Fix class `Voidable`.
+* Fix class `Dicurryable`.
+* Move some `Abstractable` methods to `Functionable`.
+* Rename module `Symantic.{Lang => Class}`.
+* Rename term `{def => define}`.
+* Update release `version`.
+
+### Documentation
+
+* Add `ChangeLog.md`.
+* Rename {hut => code}.sourcephile.fr.
+
+### Implementation
+
+* Cleanup formatting a bit.
+* Cleanup useless import.
+
+### Build
+
+* Add tool `git-chglog` for generating `ChangeLog.md`.
+* Add tool `reuse` for copyright linting.
+* Ignore more local-only files.
+* Improve linting.
+* Remove nix input `flake-utils`.
+* Remove lingering Stack file.
+* Update nix input `nixpkgs`.
+
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,11 @@
+override GHCID_OPTIONS += --no-height-limit --reverse-errors 
 override REPL_OPTIONS += -ignore-dot-ghci
-override GHCID_OPTIONS += --no-height-limit --reverse-errors
 
 cabal := $(wildcard *.cabal)
 package := $(notdir ./$(cabal:.cabal=))
 version := $(shell sed -ne 's/^version: *\(.*\)/\1/p' $(cabal))
 project := $(patsubst %.cabal,%,$(cabal))
+cabal_builddir ?= dist-newstyle
 
 all: build
 build:
@@ -14,33 +15,49 @@
 repl:
 	cabal repl $(CABAL_REPL_FLAGS) $(project)
 ghcid:
-	ghcid $(GHCID_OPTIONS) -c 'cabal repl $(CABAL_REPL_FLAGS) $(project) $(addprefix --repl-options ,$(REPL_OPTIONS))'
+	ghcid $(GHCID_OPTIONS) --command 'cabal repl -fno-code $(CABAL_REPL_FLAGS) $(project) $(addprefix --repl-options ,$(REPL_OPTIONS))'
 
 doc:
 	cabal haddock --haddock-css ocean --haddock-hyperlink-source
 
-tag:
-	git tag --merged | grep -Fqx "$(package)-$(version)" || \
-	git tag -f -s -m "$(package) v$(version)" $(package)-$(version)
+.PHONY: ChangeLog.md
+ChangeLog.md:
+	! git tag --merged | grep -Fqx $(package)-$(version)
+	git diff --exit-code
+	git tag -f $(package)-$(version)
+	git-chglog --output $@.new --tag-filter-pattern '$(package)-.*' $(package)-$(version)
+	touch $@
+	cat $@ >>$@.new
+	mv -f $@.new $@
+	git tag -d $(package)-$(version)
+	git add '$@'
+	git commit -m 'doc: update `$@`'
+tag: ChangeLog.md
+	git tag -s -m $(package)-$(version) $(package)-$(version)
 
 tar:
+	git diff --exit-code
 	reuse lint
 	cabal sdist
 	cabal haddock --haddock-for-hackage --enable-doc
 upload: LANG=C
 upload: tar
-	cabal upload $(CABAL_UPLOAD_FLAGS) dist-newstyle/sdist/$(package)-$(version).tar.gz
-	cabal upload $(CABAL_UPLOAD_FLAGS) --documentation dist-newstyle/$(package)-$(version)-docs.tar.gz
+	git tag --merged | grep -Fqx $(package)-$(version)
+	git push --follow-tags $(GIT_PUSH_FLAGS)
+	cabal upload $(CABAL_UPLOAD_FLAGS) "$(cabal_builddir)"/sdist/$(package)-$(version).tar.gz
+	cabal upload $(CABAL_UPLOAD_FLAGS) --documentation "$(cabal_builddir)"/$(package)-$(version)-docs.tar.gz
 %/publish: CABAL_UPLOAD_FLAGS+=--publish
 %/publish: %
 	
 publish: upload/publish
 
-nix-build:
-	nix -L build
-nix-relock:
-	nix flake update --recreate-lock-file
-nix-repl:
-	nix -L develop --command cabal repl $(CABAL_REPL_FLAGS)
-nix-shell:
-	nix -L develop
+.PHONY: .hlint.yaml
+.hlint.yaml: $(shell find src -name '*.hs' -not -name 'HLint.hs')
+	sed -i -e '/^# BEGIN: generated hints/,/^# END: generated hints/d' $@
+	echo >>$@ '# BEGIN: generated hints'
+	hlint --find . | grep -- '- fixity:' | sort -u >>$@
+	echo >>$@ '# END: generated hints'
+lint: .hlint.yaml
+	if hlint --quiet --report=hlint.html -XNoCPP $(HLINT_FLAGS) .; \
+	then rm -f hlint.html; \
+	else sensible-browser ./hlint.html & fi
diff --git a/default.nix b/default.nix
--- a/default.nix
+++ b/default.nix
@@ -2,6 +2,7 @@
 , inputs ? {}
 , ghc ? null
 , withHoogle ? false
+, ...
 }:
 let
   haskellPackages =
@@ -20,8 +21,8 @@
       hs.ghcid
       hs.haskell-language-server
       hs.hlint
-    ];
-    buildInputs = [
+      pkgs.git-chglog
+      pkgs.reuse
     ];
     inherit withHoogle;
   };
diff --git a/flake.lock b/flake.lock
--- a/flake.lock
+++ b/flake.lock
@@ -1,24 +1,9 @@
 {
   "nodes": {
-    "flake-utils": {
-      "locked": {
-        "lastModified": 1623875721,
-        "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
     "nixpkgs": {
       "locked": {
-        "narHash": "sha256-r3EoB5BEXlDDDm6zZ571l3GQQTV+ENxis3QQF33WzrQ=",
-        "path": "/nix/store/95j1q84ajdn4ry10rywngn2jhasjjzlz-nixpkgs-patched",
+        "narHash": "sha256-1XuSYfeI9j4jBnJo2Au1OKaPzfq7HUl4YPqxE5JvrN0=",
+        "path": "/nix/store/q1aqjzvpwwb3crfv0awr60x63s6xfb66-nixpkgs-patched",
         "type": "path"
       },
       "original": {
@@ -28,7 +13,6 @@
     },
     "root": {
       "inputs": {
-        "flake-utils": "flake-utils",
         "nixpkgs": "nixpkgs"
       }
     }
diff --git a/flake.nix b/flake.nix
--- a/flake.nix
+++ b/flake.nix
@@ -1,13 +1,14 @@
 {
 inputs.nixpkgs.url = "flake:nixpkgs";
-#inputs.nixpkgs.url = "github:NixOS/nixpkgs";
-inputs.flake-utils.url = "github:numtide/flake-utils";
-outputs = inputs:
-  inputs.flake-utils.lib.eachDefaultSystem (system: let
+outputs = inputs: let
+  lib = inputs.nixpkgs.lib;
+  forAllSystems = f: lib.genAttrs lib.systems.supported.hydra (system: f {
+    inherit inputs system;
     pkgs = inputs.nixpkgs.legacyPackages.${system};
-    in {
-      defaultPackage = import ./default.nix { inherit pkgs; };
-      devShell = (import ./default.nix { inherit pkgs; }).shell;
-    }
-  );
+  });
+  in
+  rec {
+    defaultPackage = forAllSystems (import ./default.nix);
+    devShell = lib.mapAttrs (_: x: x.shell) defaultPackage;
+  };
 }
diff --git a/src/Symantic.hs b/src/Symantic.hs
--- a/src/Symantic.hs
+++ b/src/Symantic.hs
@@ -1,16 +1,18 @@
 module Symantic
- ( module Symantic.Data
+ ( module Symantic.Class
+ , module Symantic.CurryN
+ , module Symantic.Data
  , module Symantic.Derive
- , module Symantic.Lang
  , module Symantic.ObserveSharing
  , module Symantic.Optimize
  , module Symantic.Reify
  , module Symantic.View
  ) where
 
+import Symantic.Class
+import Symantic.CurryN
 import Symantic.Data
 import Symantic.Derive
-import Symantic.Lang
 import Symantic.ObserveSharing
 import Symantic.Optimize
 import Symantic.Reify
diff --git a/src/Symantic/ADT.hs b/src/Symantic/ADT.hs
--- a/src/Symantic/ADT.hs
+++ b/src/Symantic/ADT.hs
@@ -1,7 +1,6 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE EmptyCase #-}
 {-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE UndecidableInstances #-}
@@ -84,12 +83,12 @@
   -- into the @(':+:')@ (balanced) binary tree of 'Rep',
   -- using continuation passing-style for performance.
   repOfEithers ::
-   EoT (ListOfRepSums a ss) ->
-   -- the 'a' 'Rep' is the current alternative in the 'EoT'
-   (a x -> r) ->
-   -- the 'a' 'Rep' is a following alternative in the 'EoT'
-   (EoT ss -> r) ->
-   r
+    EoT (ListOfRepSums a ss) ->
+    -- the 'a' 'Rep' is the current alternative in the 'EoT'
+    (a x -> r) ->
+    -- the 'a' 'Rep' is a following alternative in the 'EoT'
+    (EoT ss -> r) ->
+    r
 instance (RepOfEithers a (ListOfRepSums b ss), RepOfEithers b ss) => RepOfEithers (a:+:b) ss where
   repOfEithers eot ok ko =
     -- try to parse 'a' on the current 'eot'
@@ -107,10 +106,10 @@
 instance RepOfTuples a '[] => RepOfEithers (M1 C c a) (ps ': ss) where
   repOfEithers eot ok ko =
     case eot of
-     -- 'EoT' is a leaf, and 'Rep' too: parsing succeeds
-     Left ts -> ok $ M1 $ repOfTuples @a @'[] ts const
-     -- 'EoT' is a node, but 'Rep' is a leaf: parsing fails
-     Right ss -> ko ss
+      -- 'EoT' is a leaf, and 'Rep' too: parsing succeeds
+      Left ts -> ok $ M1 $ repOfTuples @a @'[] ts const
+      -- 'EoT' is a node, but 'Rep' is a leaf: parsing fails
+      Right ss -> ko ss
 instance RepOfTuples a '[] => RepOfEithers (M1 C c a) '[] where
   repOfEithers eot ok _ko = ok $ M1 $ repOfTuples @_ @'[] eot const
 instance RepOfEithers V1 ss where
@@ -122,8 +121,8 @@
   -- into the @(':*:')@ (balanced) binary tree of 'Rep',
   -- using continuation passing-style for performance.
   repOfTuples ::
-   Tuples (ListOfRepProducts a xs) ->
-   (a x -> Tuples xs -> r) -> r
+    Tuples (ListOfRepProducts a xs) ->
+    (a x -> Tuples xs -> r) -> r
 instance (RepOfTuples a (ListOfRepProducts b ps), RepOfTuples b ps) => RepOfTuples (a:*:b) ps where
   repOfTuples ts k =
     -- uncons 'a'
@@ -161,8 +160,8 @@
 instance (EithersOfRep a (ListOfRepSums b ss), EithersOfRep b ss) =>
  EithersOfRep (a:+:b) ss where
   eithersOfRepL = \case
-   L1 a -> eithersOfRepL @a @(ListOfRepSums b ss) a
-   R1 b -> eithersOfRepR @a @(ListOfRepSums b ss) (eithersOfRepL @b @ss b)
+    L1 a -> eithersOfRepL @a @(ListOfRepSums b ss) a
+    R1 b -> eithersOfRepR @a @(ListOfRepSums b ss) (eithersOfRepL @b @ss b)
   eithersOfRepR ss = eithersOfRepR @a @(ListOfRepSums b ss) (eithersOfRepR @b @ss ss)
 instance EithersOfRep a ss => EithersOfRep (M1 D c a) ss where
   eithersOfRepL (M1 a) = eithersOfRepL @a @ss a
diff --git a/src/Symantic/Class.hs b/src/Symantic/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Symantic/Class.hs
@@ -0,0 +1,428 @@
+{-# LANGUAGE DataKinds #-} -- For ReprKind
+{-# LANGUAGE PatternSynonyms #-} -- For (:!:)
+{-# LANGUAGE TypeFamilyDependencies #-} -- For Permutation
+{-# LANGUAGE UndecidableInstances #-} -- For Permutation
+module Symantic.Class where
+
+import Data.Bool (Bool(..))
+import Data.Char (Char)
+import Data.Either (Either(..))
+import Data.Eq (Eq)
+import Data.Int (Int)
+import Data.Kind (Type)
+import Data.Maybe (Maybe(..), fromJust)
+import Data.Proxy (Proxy(..))
+import Data.Semigroup (Semigroup)
+import Data.String (String)
+import GHC.Generics (Generic)
+import Numeric.Natural (Natural)
+import qualified Control.Category as Cat
+import qualified Data.Function as Fun
+import qualified Data.Tuple as Tuple
+
+import Symantic.Derive
+import Symantic.ADT
+import Symantic.CurryN
+
+-- * Type 'ReprKind'
+type ReprKind = Type -> Type
+
+-- * Class 'Abstractable'
+class Abstractable repr where
+  -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style.
+  lam :: (repr a -> repr b) -> repr (a->b)
+  -- | Like 'lam' but whose argument is used only once,
+  -- hence safe to beta-reduce (inline) without duplicating work.
+  lam1 :: (repr a -> repr b) -> repr (a->b)
+  var :: repr a -> repr a
+  -- | Application, aka. unabstract.
+  (.@) :: repr (a->b) -> repr a -> repr b; infixl 9 .@
+  lam f = liftDerived (lam (derive Fun.. f Fun.. liftDerived))
+  lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
+  var = liftDerived1 var
+  (.@) = liftDerived2 (.@)
+  default lam ::
+    FromDerived Abstractable repr => Derivable repr =>
+    (repr a -> repr b) -> repr (a->b)
+  default lam1 ::
+    FromDerived Abstractable repr => Derivable repr =>
+    (repr a -> repr b) -> repr (a->b)
+  default var ::
+    FromDerived1 Abstractable repr =>
+    repr a -> repr a
+  default (.@) ::
+    FromDerived2 Abstractable repr =>
+    repr (a->b) -> repr a -> repr b
+
+-- ** Class 'Functionable'
+class Functionable repr where
+  const :: repr (a -> b -> a)
+  flip :: repr ((a -> b -> c) -> b -> a -> c)
+  id :: repr (a->a)
+  (.) :: repr ((b->c) -> (a->b) -> a -> c); infixr 9 .
+  ($) :: repr ((a->b) -> a -> b); infixr 0 $
+  const = liftDerived const
+  flip = liftDerived flip
+  id = liftDerived id
+  (.) = liftDerived (.)
+  ($) = liftDerived ($)
+  default const ::
+    FromDerived Functionable repr =>
+    repr (a -> b -> a)
+  default flip ::
+    FromDerived Functionable repr =>
+    repr ((a -> b -> c) -> b -> a -> c)
+  default id ::
+    FromDerived Functionable repr =>
+    repr (a->a)
+  default (.) ::
+    FromDerived Functionable repr =>
+    repr ((b->c) -> (a->b) -> a -> c)
+  default ($) ::
+    FromDerived Functionable repr =>
+    repr ((a->b) -> a -> b)
+
+-- * Class 'Anythingable'
+class Anythingable repr where
+  anything :: repr a -> repr a
+  anything = Fun.id
+
+-- * Class 'Bottomable'
+class Bottomable repr where
+  bottom :: repr a
+
+-- * Class 'Constantable'
+class Constantable c repr where
+  constant :: c -> repr c
+  constant = liftDerived Fun.. constant
+  default constant ::
+    FromDerived (Constantable c) repr =>
+    c -> repr c
+
+-- * Class 'Eitherable'
+class Eitherable repr where
+  left :: repr (l -> Either l r)
+  right :: repr (r -> Either l r)
+  left = liftDerived left
+  right = liftDerived right
+  default left ::
+    FromDerived Eitherable repr =>
+    repr (l -> Either l r)
+  default right ::
+    FromDerived Eitherable repr =>
+    repr (r -> Either l r)
+
+-- * Class 'Equalable'
+class Equalable repr where
+  equal :: Eq a => repr (a -> a -> Bool)
+  equal = liftDerived equal
+  default equal ::
+    FromDerived Equalable repr =>
+    Eq a => repr (a -> a -> Bool)
+
+infix 4 `equal`, ==
+(==) ::
+  Abstractable repr => Equalable repr => Eq a =>
+  repr a -> repr a -> repr Bool
+(==) x y = equal .@ x .@ y
+
+-- * Class 'IfThenElseable'
+class IfThenElseable repr where
+  ifThenElse :: repr Bool -> repr a -> repr a -> repr a
+  ifThenElse = liftDerived3 ifThenElse
+  default ifThenElse ::
+    FromDerived3 IfThenElseable repr =>
+    repr Bool -> repr a -> repr a -> repr a
+
+-- * Class 'Inferable'
+class Inferable a repr where
+  infer :: repr a
+  default infer :: FromDerived (Inferable a) repr => repr a
+  infer = liftDerived infer
+
+unit :: Inferable () repr => repr ()
+unit = infer
+bool :: Inferable Bool repr => repr Bool
+bool = infer
+char :: Inferable Char repr => repr Char
+char = infer
+int :: Inferable Int repr => repr Int
+int = infer
+natural :: Inferable Natural repr => repr Natural
+natural = infer
+string :: Inferable String repr => repr String
+string = infer
+
+-- * Class 'Listable'
+class Listable repr where
+  cons :: repr (a -> [a] -> [a])
+  nil :: repr [a]
+  cons = liftDerived cons
+  nil = liftDerived nil
+  default cons ::
+    FromDerived Listable repr =>
+    repr (a -> [a] -> [a])
+  default nil ::
+    FromDerived Listable repr =>
+    repr [a]
+
+-- * Class 'Maybeable'
+class Maybeable repr where
+  nothing :: repr (Maybe a)
+  just :: repr (a -> Maybe a)
+  nothing = liftDerived nothing
+  just = liftDerived just
+  default nothing ::
+    FromDerived Maybeable repr =>
+    repr (Maybe a)
+  default just ::
+    FromDerived Maybeable repr =>
+    repr (a -> Maybe a)
+
+-- * Class 'IsoFunctor'
+class IsoFunctor repr where
+  (<%>) :: Iso a b -> repr a -> repr b; infixl 4 <%>
+  (<%>) iso = liftDerived1 (iso <%>)
+  default (<%>) ::
+    FromDerived1 IsoFunctor repr =>
+    Iso a b -> repr a -> repr b
+
+-- ** Type 'Iso'
+data Iso a b = Iso { a2b :: a->b, b2a :: b->a }
+instance Cat.Category Iso where
+  id = Iso Cat.id Cat.id
+  f . g = Iso (a2b f Cat.. a2b g) (b2a g Cat.. b2a f)
+
+-- * Class 'ProductFunctor'
+-- | Beware that this is an @infixr@,
+-- not @infixl@ like to 'Control.Applicative.<*>';
+-- this is to follow what is expected by 'ADT'.
+class ProductFunctor repr where
+  (<.>) :: repr a -> repr b -> repr (a, b); infixr 4 <.>
+  (<.>) = liftDerived2 (<.>)
+  default (<.>) ::
+    FromDerived2 ProductFunctor repr =>
+    repr a -> repr b -> repr (a, b)
+  (<.) :: repr a -> repr () -> repr a; infixr 4 <.
+  ra <. rb = Iso Tuple.fst (, ()) <%> (ra <.> rb)
+  default (<.) :: IsoFunctor repr => repr a -> repr () -> repr a
+  (.>) :: repr () -> repr a -> repr a; infixr 4 .>
+  ra .> rb = Iso Tuple.snd (() ,) <%> (ra <.> rb)
+  default (.>) :: IsoFunctor repr => repr () -> repr a -> repr a
+
+-- * Class 'SumFunctor'
+-- | Beware that this is an @infixr@,
+-- not @infixl@ like to 'Control.Applicative.<|>';
+-- this is to follow what is expected by 'ADT'.
+class SumFunctor repr where
+  (<+>) :: repr a -> repr b -> repr (Either a b); infixr 3 <+>
+  (<+>) = liftDerived2 (<+>)
+  default (<+>) ::
+    FromDerived2 SumFunctor repr =>
+    repr a -> repr b -> repr (Either a b)
+
+-- * Class 'AlternativeFunctor'
+-- | Beware that this is an @infixr@,
+-- not @infixl@ like to 'Control.Applicative.<|>';
+-- this is to follow what is expected by 'ADT'.
+class AlternativeFunctor repr where
+  (<|>) :: repr a -> repr a -> repr a; infixr 3 <|>
+  (<|>) = liftDerived2 (<|>)
+  default (<|>) ::
+    FromDerived2 AlternativeFunctor repr =>
+    repr a -> repr a -> repr a
+
+-- * Class 'Dicurryable'
+class Dicurryable repr where
+  dicurry ::
+    CurryN args =>
+    proxy args ->
+    (args-..->a) -> -- construction
+    (a->Tuples args) -> -- destruction
+    repr (Tuples args) ->
+    repr a
+  dicurry args constr destr = liftDerived1 (dicurry args constr destr)
+  default dicurry ::
+    FromDerived1 Dicurryable repr =>
+    CurryN args =>
+    proxy args ->
+    (args-..->a) ->
+    (a->Tuples args) ->
+    repr (Tuples args) ->
+    repr a
+
+construct ::
+  forall args a repr.
+  Dicurryable repr =>
+  Generic a =>
+  EoTOfRep a =>
+  CurryN args =>
+  Tuples args ~ EoT (ADT a) =>
+  (args ~ Args (args-..->a)) =>
+  (args-..->a) ->
+  repr (Tuples args) ->
+  repr a
+construct f = dicurry (Proxy::Proxy args) f eotOfadt
+
+adt ::
+  forall adt repr.
+  IsoFunctor repr =>
+  Generic adt =>
+  RepOfEoT adt =>
+  EoTOfRep adt =>
+  repr (EoT (ADT adt)) ->
+  repr adt
+adt = (<%>) (Iso adtOfeot eotOfadt)
+
+-- * Class 'Monoidable'
+class
+  ( Emptyable repr
+  , Semigroupable repr
+  ) => Monoidable repr
+instance
+  ( Emptyable repr
+  , Semigroupable repr
+  ) => Monoidable repr
+
+-- ** Class 'Emptyable'
+class Emptyable repr where
+  empty :: repr a
+  empty = liftDerived empty
+  default empty ::
+    FromDerived Emptyable repr =>
+    repr a
+
+-- ** Class 'Semigroupable'
+class Semigroupable repr where
+  concat :: Semigroup a => repr (a -> a -> a)
+  concat = liftDerived concat
+  default concat ::
+    FromDerived Semigroupable repr =>
+    Semigroup a =>
+    repr (a -> a -> a)
+
+infixr 6 `concat`, <>
+(<>) ::
+  Abstractable repr => Semigroupable repr => Semigroup a =>
+  repr a -> repr a -> repr a
+(<>) x y = concat .@ x .@ y
+
+-- ** Class 'Optionable'
+class Optionable repr where
+  option :: repr a -> repr a
+  optional :: repr a -> repr (Maybe a)
+  option = liftDerived1 option
+  optional = liftDerived1 optional
+  default option ::
+    FromDerived1 Optionable repr =>
+    repr a -> repr a
+  default optional ::
+    FromDerived1 Optionable repr =>
+    repr a -> repr (Maybe a)
+
+-- * Class 'Repeatable'
+class Repeatable repr where
+  many0 :: repr a -> repr [a]
+  many1 :: repr a -> repr [a]
+  many0 = liftDerived1 many0
+  many1 = liftDerived1 many1
+  default many0 ::
+    FromDerived1 Repeatable repr =>
+    repr a -> repr [a]
+  default many1 ::
+    FromDerived1 Repeatable repr =>
+    repr a -> repr [a]
+
+-- * Class 'Permutable'
+class Permutable repr where
+  -- Use @TypeFamilyDependencies@ to help type-inference infer @(repr)@.
+  type Permutation (repr:: ReprKind) = (r :: ReprKind) | r -> repr
+  type Permutation repr = Permutation (Derived repr)
+  permutable :: Permutation repr a -> repr a
+  perm :: repr a -> Permutation repr a
+  noPerm :: Permutation repr ()
+  permWithDefault :: a -> repr a -> Permutation repr a
+  optionalPerm ::
+    Eitherable repr => IsoFunctor repr => Permutable repr =>
+    repr a -> Permutation repr (Maybe a)
+  optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
+
+(<&>) ::
+  Permutable repr =>
+  ProductFunctor (Permutation repr) =>
+  repr a ->
+  Permutation repr b ->
+  Permutation repr (a, b)
+x <&> y = perm x <.> y
+infixr 4 <&>
+{-# INLINE (<&>)  #-}
+
+(<?&>) ::
+  Eitherable repr =>
+  IsoFunctor repr =>
+  Permutable repr =>
+  ProductFunctor (Permutation repr) =>
+  repr a ->
+  Permutation repr b ->
+  Permutation repr (Maybe a, b)
+x <?&> y = optionalPerm x <.> y
+infixr 4 <?&>
+{-# INLINE (<?&>) #-}
+
+(<*&>) ::
+  Eitherable repr =>
+  Repeatable repr =>
+  IsoFunctor repr =>
+  Permutable repr =>
+  ProductFunctor (Permutation repr) =>
+  repr a ->
+  Permutation repr b ->
+  Permutation repr ([a],b)
+x <*&> y = permWithDefault [] (many1 x) <.> y
+infixr 4 <*&>
+{-# INLINE (<*&>) #-}
+
+(<+&>) ::
+  Eitherable repr =>
+  Repeatable repr =>
+  IsoFunctor repr =>
+  Permutable repr =>
+  ProductFunctor (Permutation repr) =>
+  repr a ->
+  Permutation repr b ->
+  Permutation repr ([a], b)
+x <+&> y = perm (many1 x) <.> y
+infixr 4 <+&>
+{-# INLINE (<+&>) #-}
+
+-- * Class 'Routable'
+class Routable repr where
+  (<!>) :: repr a -> repr b -> repr (a, b); infixr 4 <!>
+  (<!>) = liftDerived2 (<!>)
+  default (<!>) ::
+    FromDerived2 Routable repr =>
+    repr a -> repr b -> repr (a, b)
+
+-- | Like @(,)@ but @infixr@.
+-- Mostly useful for clarity when using 'Routable'.
+pattern (:!:) :: a -> b -> (a, b)
+pattern a:!:b <- (a, b)
+  where a:!:b = (a, b)
+infixr 4 :!:
+
+-- * Class 'Voidable'
+-- | FIXME: this class should likely be removed
+class Voidable repr where
+  void :: a -> repr a -> repr ()
+  void = liftDerived1 Fun.. void
+  default void ::
+    FromDerived1 Voidable repr =>
+    a -> repr a -> repr ()
+
+-- * Class 'Substractable'
+class Substractable repr where
+  (<->) :: repr a -> repr b -> repr a; infixr 3 <->
+  (<->) = liftDerived2 (<->)
+  default (<->) ::
+    FromDerived2 Substractable repr =>
+    repr a -> repr b -> repr a
diff --git a/src/Symantic/Data.hs b/src/Symantic/Data.hs
--- a/src/Symantic/Data.hs
+++ b/src/Symantic/Data.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE ViewPatterns #-}
 module Symantic.Data where
 
@@ -11,12 +10,13 @@
 import Data.Either (Either)
 import Data.Kind (Constraint)
 import Data.Maybe (Maybe)
+import Data.Semigroup (Semigroup)
 import Type.Reflection (Typeable, (:~~:)(..), eqTypeRep, typeRep)
 import qualified Data.Eq as Eq
-import qualified Data.Maybe as Maybe
 import qualified Data.Function as Fun
+import qualified Data.Maybe as Maybe
 
-import Symantic.Lang
+import Symantic.Class
 import Symantic.Derive
 
 -- * Type 'SomeData'
@@ -79,6 +79,11 @@
   lam f = SomeData (Lam f)
   lam1 f = SomeData (Lam1 f)
   var = Fun.id
+
+-- Functionable
+instance
+  ( Abstractable repr
+  ) => Functionable (SomeData repr) where
   ($) = lam1 (\f -> lam1 (\x -> f .@ x))
   (.) = lam1 (\f -> lam1 (\g -> lam1 (\x -> f .@ (g .@ x))))
   const = lam1 (\x -> lam1 (\_y -> x))
@@ -90,8 +95,7 @@
   Anything :: repr a -> Data Anythingable repr a
 instance
   ( Anythingable repr
-  ) =>
-  Derivable (Data Anythingable repr) where
+  ) => Derivable (Data Anythingable repr) where
   derive = \case
     Anything x -> anything x
 instance Anythingable (SomeData repr)
@@ -146,6 +150,33 @@
   equal = SomeData Equal
 instance Equalable (Data Equalable repr) where
   equal = Equal
+
+-- Emptyable
+data instance Data Emptyable repr a where
+  Empty :: Data Emptyable repr a
+instance Emptyable repr => Derivable (Data Emptyable repr) where
+  derive = \case
+    Empty -> empty
+instance
+  ( Emptyable repr
+  ) => Emptyable (SomeData repr) where
+  empty = SomeData Empty
+instance Emptyable (Data Emptyable repr) where
+  empty = Empty
+
+-- Semigroupable
+data instance Data Semigroupable repr a where
+  Concat :: Semigroup a => Data Semigroupable repr (a -> a -> a)
+infixr 4 `Concat`
+instance Semigroupable repr => Derivable (Data Semigroupable repr) where
+  derive = \case
+    Concat -> concat
+instance
+  ( Semigroupable repr
+  ) => Semigroupable (SomeData repr) where
+  concat = SomeData Concat
+instance Semigroupable (Data Semigroupable repr) where
+  concat = Concat
 
 -- IfThenElseable
 data instance Data IfThenElseable repr a where
diff --git a/src/Symantic/Derive.hs b/src/Symantic/Derive.hs
--- a/src/Symantic/Derive.hs
+++ b/src/Symantic/Derive.hs
@@ -11,7 +11,7 @@
 type family Derived (repr :: Type -> Type) :: Type -> Type
 
 -- * Class 'Derivable'
--- | Derivable an interpreter to a another interpreter
+-- | Derive an interpreter to a another interpreter
 -- determined by the 'Derived' open type family.
 -- This is mostly useful when running the interpreter stack,
 -- but also when going back from an initial encoding to a final one.
diff --git a/src/Symantic/Lang.hs b/src/Symantic/Lang.hs
deleted file mode 100644
--- a/src/Symantic/Lang.hs
+++ /dev/null
@@ -1,356 +0,0 @@
-{-# LANGUAGE DataKinds #-} -- For ReprKind
-{-# LANGUAGE PatternSynonyms #-} -- For (:!:)
-{-# LANGUAGE TypeFamilyDependencies #-} -- For Permutation
-{-# LANGUAGE UndecidableInstances #-} -- For Permutation
-module Symantic.Lang where
-
-import Data.Bool (Bool(..))
-import Data.Char (Char)
-import Data.Either (Either(..))
-import Data.Eq (Eq)
-import Data.Kind (Type)
-import Data.Maybe (Maybe(..), fromJust)
-import Data.Proxy (Proxy(..))
-import GHC.Generics (Generic)
-import qualified Data.Function as Fun
-
-import Symantic.Derive
-import Symantic.ADT
-import Symantic.CurryN
-
--- * Type 'ReprKind'
-type ReprKind = Type -> Type
-
--- * Class 'Abstractable'
-class Abstractable repr where
-  -- | Application, aka. unabstract.
-  (.@) :: repr (a->b) -> repr a -> repr b; infixl 9 .@
-  -- | Lambda term abstraction, in HOAS (Higher-Order Abstract Syntax) style.
-  lam :: (repr a -> repr b) -> repr (a->b)
-  -- | Like 'lam' but whose argument is used only once,
-  -- hence safe to beta-reduce (inline) without duplicating work.
-  lam1 :: (repr a -> repr b) -> repr (a->b)
-  const :: repr (a -> b -> a)
-  flip :: repr ((a -> b -> c) -> b -> a -> c)
-  id :: repr (a->a)
-  (.) :: repr ((b->c) -> (a->b) -> a -> c); infixr 9 .
-  ($) :: repr ((a->b) -> a -> b); infixr 0 $
-  var :: repr a -> repr a
-  (.@) = liftDerived2 (.@)
-  lam f = liftDerived (lam (derive Fun.. f Fun.. liftDerived))
-  lam1 f = liftDerived (lam1 (derive Fun.. f Fun.. liftDerived))
-  const = liftDerived const
-  flip = liftDerived flip
-  id = liftDerived id
-  (.) = liftDerived (.)
-  ($) = liftDerived ($)
-  var = liftDerived1 var
-  default (.@) ::
-    FromDerived2 Abstractable repr =>
-    repr (a->b) -> repr a -> repr b
-  default lam ::
-    FromDerived Abstractable repr => Derivable repr =>
-    (repr a -> repr b) -> repr (a->b)
-  default lam1 ::
-    FromDerived Abstractable repr => Derivable repr =>
-    (repr a -> repr b) -> repr (a->b)
-  default const ::
-    FromDerived Abstractable repr =>
-    repr (a -> b -> a)
-  default flip ::
-    FromDerived Abstractable repr =>
-    repr ((a -> b -> c) -> b -> a -> c)
-  default id ::
-    FromDerived Abstractable repr =>
-    repr (a->a)
-  default (.) ::
-    FromDerived Abstractable repr =>
-    repr ((b->c) -> (a->b) -> a -> c)
-  default ($) ::
-    FromDerived Abstractable repr =>
-    repr ((a->b) -> a -> b)
-  default var ::
-    FromDerived1 Abstractable repr =>
-    repr a -> repr a
-
--- * Class 'Anythingable'
-class Anythingable repr where
-  anything :: repr a -> repr a
-  anything = Fun.id
-
--- * Class 'Bottomable'
-class Bottomable repr where
-  bottom :: repr a
-
--- * Class 'Constantable'
-class Constantable c repr where
-  constant :: c -> repr c
-  constant = liftDerived Fun.. constant
-  default constant ::
-    FromDerived (Constantable c) repr =>
-    c -> repr c
-
-bool :: Constantable Bool repr => Bool -> repr Bool
-bool = constant @Bool
-char :: Constantable Char repr => Char -> repr Char
-char = constant @Char
-unit :: Constantable () repr => repr ()
-unit = constant @() ()
-
--- * Class 'Eitherable'
-class Eitherable repr where
-  left :: repr (l -> Either l r)
-  right :: repr (r -> Either l r)
-  left = liftDerived left
-  right = liftDerived right
-  default left ::
-    FromDerived Eitherable repr =>
-    repr (l -> Either l r)
-  default right ::
-    FromDerived Eitherable repr =>
-    repr (r -> Either l r)
-
--- * Class 'Equalable'
-class Equalable repr where
-  equal :: Eq a => repr (a -> a -> Bool)
-  equal = liftDerived equal
-  default equal ::
-    FromDerived Equalable repr =>
-    Eq a => repr (a -> a -> Bool)
-
-infix 4 `equal`, ==
-(==) :: (Abstractable repr, Equalable repr, Eq a) => repr (a -> a -> Bool)
-(==) = lam (\x -> lam (\y -> equal .@ x .@ y))
-
--- * Class 'IfThenElseable'
-class IfThenElseable repr where
-  ifThenElse :: repr Bool -> repr a -> repr a -> repr a
-  ifThenElse = liftDerived3 ifThenElse
-  default ifThenElse ::
-    FromDerived3 IfThenElseable repr =>
-    repr Bool -> repr a -> repr a -> repr a
-
--- * Class 'Listable'
-class Listable repr where
-  cons :: repr (a -> [a] -> [a])
-  nil :: repr [a]
-  cons = liftDerived cons
-  nil = liftDerived nil
-  default cons ::
-    FromDerived Listable repr =>
-    repr (a -> [a] -> [a])
-  default nil ::
-    FromDerived Listable repr =>
-    repr [a]
-
--- * Class 'Maybeable'
-class Maybeable repr where
-  nothing :: repr (Maybe a)
-  just :: repr (a -> Maybe a)
-  nothing = liftDerived nothing
-  just = liftDerived just
-  default nothing ::
-    FromDerived Maybeable repr =>
-    repr (Maybe a)
-  default just ::
-    FromDerived Maybeable repr =>
-    repr (a -> Maybe a)
-
--- * Class 'IsoFunctor'
-class IsoFunctor repr where
-  (<%>) :: Iso a b -> repr a -> repr b
-  (<%>) iso = liftDerived1 (iso <%>)
-  default (<%>) ::
-    FromDerived1 IsoFunctor repr =>
-    Iso a b -> repr a -> repr b
-
--- ** Type 'Iso'
-data Iso a b = Iso { a2b :: a->b, b2a :: b->a }
-
--- * Class 'ProductFunctor'
-class ProductFunctor repr where
-  (<.>) :: repr a -> repr b -> repr (a, b)
-  (<.>) = liftDerived2 (<.>)
-  default (<.>) ::
-    FromDerived2 ProductFunctor repr =>
-    repr a -> repr b -> repr (a, b)
-
--- * Class 'AlternativeFunctor'
-class AlternativeFunctor repr where
-  (<+>) :: repr a -> repr a -> repr a
-  (<+>) = liftDerived2 (<+>)
-  default (<+>) ::
-    FromDerived2 AlternativeFunctor repr =>
-    repr a -> repr a -> repr a
-
--- * Class 'Dicurryable'
-class Dicurryable repr where
-  dicurry ::
-    CurryN args =>
-    proxy args ->
-    (args-..->r) -> -- construction
-    (r->Tuples args) -> -- destruction
-    repr (args-..->k) ->
-    repr (r->k)
-  dicurry args constr destr = liftDerived1 (dicurry args constr destr)
-  default dicurry ::
-    FromDerived1 Dicurryable repr =>
-    CurryN args =>
-    proxy args ->
-    (args-..->r) ->
-    (r->Tuples args) ->
-    repr (args-..->k) ->
-    repr (r->k)
-
-construct ::
-  forall args a k repr.
-  Dicurryable repr =>
-  Generic a =>
-  EoTOfRep a =>
-  CurryN args =>
-  Tuples args ~ EoT (ADT a) =>
-  (args ~ Args (args-..->a)) =>
-  (args-..->a) ->
-  repr (args-..->k) ->
-  repr (a -> k)
-construct f = dicurry (Proxy::Proxy args) f eotOfadt
-
-adt ::
-  forall adt repr.
-  IsoFunctor repr =>
-  Generic adt =>
-  RepOfEoT adt =>
-  EoTOfRep adt =>
-  repr (EoT (ADT adt)) ->
-  repr adt
-adt = (<%>) (Iso adtOfeot eotOfadt)
-
--- ** Class 'Emptyable'
-class Emptyable repr where
-  empty :: repr a
-  empty = liftDerived empty
-  default empty ::
-    FromDerived Emptyable repr =>
-    repr a
-
--- ** Class 'Optionable'
-class Optionable repr where
-  option :: repr a -> repr a
-  optional :: repr a -> repr (Maybe a)
-  option = liftDerived1 option
-  optional = liftDerived1 optional
-  default option ::
-    FromDerived1 Optionable repr =>
-    repr a -> repr a
-  default optional ::
-    FromDerived1 Optionable repr =>
-    repr a -> repr (Maybe a)
-
--- * Class 'Repeatable'
-class Repeatable repr where
-  many0 :: repr a -> repr [a]
-  many1 :: repr a -> repr [a]
-  many0 = liftDerived1 many0
-  many1 = liftDerived1 many1
-  default many0 ::
-    FromDerived1 Repeatable repr =>
-    repr a -> repr [a]
-  default many1 ::
-    FromDerived1 Repeatable repr =>
-    repr a -> repr [a]
-
--- * Class 'Permutable'
-class Permutable repr where
-  -- Use @TypeFamilyDependencies@ to help type-inference infer @(repr)@.
-  type Permutation (repr:: ReprKind) = (r :: ReprKind) | r -> repr
-  type Permutation repr = Permutation (Derived repr)
-  permutable :: Permutation repr a -> repr a
-  perm :: repr a -> Permutation repr a
-  noPerm :: Permutation repr ()
-  permWithDefault :: a -> repr a -> Permutation repr a
-  optionalPerm ::
-    Eitherable repr => IsoFunctor repr => Permutable repr =>
-    repr a -> Permutation repr (Maybe a)
-  optionalPerm = permWithDefault Nothing Fun.. (<%>) (Iso Just fromJust)
-
-(<&>) ::
-  Permutable repr =>
-  ProductFunctor (Permutation repr) =>
-  repr a ->
-  Permutation repr b ->
-  Permutation repr (a, b)
-x <&> y = perm x <.> y
-
-(<?&>) ::
-  Eitherable repr =>
-  IsoFunctor repr =>
-  Permutable repr =>
-  ProductFunctor (Permutation repr) =>
-  repr a ->
-  Permutation repr b ->
-  Permutation repr (Maybe a, b)
-x <?&> y = optionalPerm x <.> y
-
-(<*&>) ::
-  Eitherable repr =>
-  Repeatable repr =>
-  IsoFunctor repr =>
-  Permutable repr =>
-  ProductFunctor (Permutation repr) =>
-  repr a ->
-  Permutation repr b ->
-  Permutation repr ([a],b)
-x <*&> y = permWithDefault [] (many1 x) <.> y
-
-(<+&>) ::
-  Eitherable repr =>
-  Repeatable repr =>
-  IsoFunctor repr =>
-  Permutable repr =>
-  ProductFunctor (Permutation repr) =>
-  repr a ->
-  Permutation repr b ->
-  Permutation repr ([a],b)
-x <+&> y = perm (many1 x) <.> y
-
-infixr 4 <&>
-infixr 4 <?&>
-infixr 4 <*&>
-infixr 4 <+&>
-
-{-# INLINE (<&>)  #-}
-{-# INLINE (<?&>) #-}
-{-# INLINE (<*&>) #-}
-{-# INLINE (<+&>) #-}
-
--- * Class 'Routable'
-class Routable repr where
-  (<!>) :: repr a -> repr b -> repr (a, b)
-  (<!>) = liftDerived2 (<!>)
-  default (<!>) ::
-    FromDerived2 Routable repr =>
-    repr a -> repr b -> repr (a,b)
-
--- | Like @(,)@ but @infixr@.
--- Mostly useful for clarity when using 'Routable'.
-pattern (:!:) :: a -> b -> (a,b)
-pattern a:!:b <- (a,b)
-  where a:!:b = (a,b)
-infixr 3 :!:
-
--- * Class 'Voidable'
-class Voidable repr where
-  void :: repr a -> repr ()
-  void = liftDerived1 void
-  default void ::
-    FromDerived1 Voidable repr =>
-    repr a -> repr ()
-
--- * Class 'Substractable'
-class Substractable repr where
-  (<->) :: repr a -> repr b -> repr a
-  (<->) = liftDerived2 (<->)
-  default (<->) ::
-    FromDerived2 Substractable repr =>
-    repr a -> repr b -> repr a
-infixr 3 <->
diff --git a/src/Symantic/ObserveSharing.hs b/src/Symantic/ObserveSharing.hs
--- a/src/Symantic/ObserveSharing.hs
+++ b/src/Symantic/ObserveSharing.hs
@@ -19,7 +19,6 @@
 import Data.Maybe (Maybe(..), isNothing)
 import Data.Monoid (Monoid(..))
 import Data.Ord (Ord(..))
-import Data.String (String)
 -- import GHC.Exts (Int(..))
 -- import GHC.Prim (unsafeCoerce#)
 import GHC.StableName (StableName(..), makeStableName, hashStableName, eqStableName)
@@ -44,7 +43,7 @@
   -- | @('ref' isRec letName)@ is a reference to @(letName)@.
   -- It is introduced by 'observeSharing'.
   -- @(isRec)@ is 'True' iif. this 'ref'erence is recursive,
-  -- ie. appears within its 'def'inition.
+  -- ie. appears within its 'define'.
   --
   -- TODO: index 'letName' with 'a' to enable dependent-map
   ref :: Bool -> letName -> repr a
@@ -56,15 +55,15 @@
 -- * Class 'Definable'
 -- | This class is not for end-users like usual symantic operators.
 -- There should be not need to use it outside this module,
--- because used 'def'initions are gathered in 'Letsable'.
+-- because used 'define's are gathered in 'Letsable'.
 class Definable letName repr where
-  -- | @('def' letName sub)@ let-binds @(letName)@ to be equal to @(sub)@.
+  -- | @('define' letName sub)@ let-binds @(letName)@ to be equal to @(sub)@.
   -- This is a temporary node either replaced
   -- by 'ref' and an entry in 'lets''s 'LetBindings',
   -- or removed when no 'ref'erence is made to it.
-  def :: letName -> repr a -> repr a
-  def name = liftDerived1 (def name)
-  default def ::
+  define :: letName -> repr a -> repr a
+  define name = liftDerived1 (define name)
+  default define ::
     FromDerived1 (Definable letName) repr =>
     letName -> repr a -> repr a
 
@@ -112,7 +111,7 @@
 -- See [Type-safe observable sharing in Haskell](https://doi.org/10.1145/1596638.1596653)
 --
 -- Beware not to apply 'observeSharing' more than once on the same term
--- otherwise some 'def' introduced by the first call
+-- otherwise some 'define' introduced by the first call
 -- would be removed by the second call.
 observeSharing ::
   Eq letName =>
@@ -198,7 +197,7 @@
           -- (would be in a preceding sibling branch, not in parentNames).
     MT.lift $ MT.put st{ oss_refs = seen }
     if isNothing seenBefore
-      then MT.local (HS.insert nodeName) (def letName <$> m)
+      then MT.local (HS.insert nodeName) (define letName <$> m)
       else return $ ref False letName
 
 type instance Derived (ObserveSharing letName repr) = FinalizeSharing letName repr
@@ -255,13 +254,13 @@
 instance Referenceable letName (ObserveSharing letName repr) where
   ref = error "[BUG]: observeSharing MUST NOT be applied twice"
 instance Definable letName (ObserveSharing letName repr) where
-  def = error "[BUG]: observeSharing MUST NOT be applied twice"
+  define = error "[BUG]: observeSharing MUST NOT be applied twice"
 instance Letsable letName (ObserveSharing letName repr) where
   lets = error "[BUG]: observeSharing MUST NOT be applied twice"
 
 -- * Type 'FinalizeSharing'
--- | Remove 'def' when non-recursive or unused
--- or replace it by 'ref', moving 'def's to the top.
+-- | Remove 'define' when non-recursive or unused
+-- or replace it by 'ref', moving 'define's to the top.
 newtype FinalizeSharing letName repr a = FinalizeSharing { unFinalizeSharing ::
   MT.ReaderT (HS.HashSet letName)
     (MT.Writer (LetBindings letName repr))
@@ -305,23 +304,23 @@
   , Hashable letName
   , Show letName
   ) => Definable letName (FinalizeSharing letName repr) where
-  def name body = FinalizeSharing $ do
+  define name body = FinalizeSharing $ do
     refs <- MT.ask
     let (repr, defs) =
           MT.runWriter $ MT.runReaderT (unFinalizeSharing body) refs
     if name `HS.member` refs
       then do
-        -- This 'def' is 'ref'erenced: move it into the result,
+        -- This 'define' is 'ref'erenced: move it into the result,
         -- to put it in scope even when some 'ref' to it exists outside of 'body'
         -- (which can happen when a body-expression is shared),
         -- and replace it by a 'ref'.
         MT.lift $ MT.tell $ HM.insert name (SomeLet repr) defs
         return $ ref False name
       else
-        -- Remove this unreferenced 'def' node.
+        -- Remove this unreferenced 'define' node.
         unFinalizeSharing body
 
--- ** Class 'Letsable'
+-- * Class 'Letsable'
 class Letsable letName repr where
   -- | @('lets' defs x)@ let-binds @(defs)@ in @(x)@.
   lets :: LetBindings letName repr -> repr a -> repr a
@@ -331,10 +330,10 @@
     FromDerived1 (Letsable letName) repr =>
     LetBindings letName repr -> repr a -> repr a
 
--- *** Type 'SomeLet'
+-- ** Type 'SomeLet'
 data SomeLet repr = forall a. SomeLet (repr a)
 
--- *** Type 'LetBindings'
+-- ** Type 'LetBindings'
 type LetBindings letName repr = HM.HashMap letName (SomeLet repr)
 
 {-
@@ -354,7 +353,7 @@
     unFinalizeSharing x
 -}
 
--- *** Type 'OpenRecs'
+-- ** Type 'OpenRecs'
 -- | Mutually recursive terms, in open recursion style.
 type OpenRecs letName a = LetRecs letName (OpenRec letName a)
 -- | Mutually recursive term, in open recursion style.
diff --git a/src/Symantic/Optimize.hs b/src/Symantic/Optimize.hs
--- a/src/Symantic/Optimize.hs
+++ b/src/Symantic/Optimize.hs
@@ -3,7 +3,7 @@
 import Data.Bool (Bool)
 import qualified Data.Function as Fun
 
-import Symantic.Lang
+import Symantic.Class
 import Symantic.Data
 
 -- | Beta-reduce the left-most outer-most lambda abstraction (aka. normal-order reduction),
diff --git a/src/Symantic/Reify.hs b/src/Symantic/Reify.hs
--- a/src/Symantic/Reify.hs
+++ b/src/Symantic/Reify.hs
@@ -7,7 +7,7 @@
 import qualified Data.Function as Fun
 import qualified Language.Haskell.TH as TH
 
-import Symantic.Lang (Abstractable(..))
+import Symantic.Class (Abstractable(..))
 
 -- | 'ReifyReflect' witnesses the duality between @meta@ and @(repr a)@.
 --  It indicates which type variables in @a@ are not to be instantiated
@@ -43,7 +43,6 @@
 base = ReifyReflect{reify = Fun.id, reflect = Fun.id}
 
 -- | The inductive case : the arrow type.
--- 'reify' and 'reflect' are built together inductively.
 infixr 8 -->
 (-->) :: Abstractable repr =>
          ReifyReflect repr m1 o1 -> ReifyReflect repr m2 o2 ->
diff --git a/src/Symantic/View.hs b/src/Symantic/View.hs
--- a/src/Symantic/View.hs
+++ b/src/Symantic/View.hs
@@ -9,10 +9,10 @@
 import qualified Data.Function as Fun
 import qualified Prelude
 
-import Symantic.Fixity
-import Symantic.Lang
+import Symantic.Class
 import Symantic.Data
 import Symantic.Derive
+import Symantic.Fixity
 
 data View a where
   View :: (ViewEnv -> ShowS) -> View a
diff --git a/symantic-base.cabal b/symantic-base.cabal
--- a/symantic-base.cabal
+++ b/symantic-base.cabal
@@ -1,8 +1,8 @@
 cabal-version: 3.0
 name: symantic-base
-maintainer: mailto:~julm/symantic-base@todo.hut.sourcephile.fr
-bug-reports: https://todo.hut.sourcephile.fr/~julm/symantic-base
-homepage: https://git.hut.sourcephile.fr/~julm/symantic-base
+maintainer: mailto:~julm/symantic-base@todo.code.sourcephile.fr
+bug-reports: https://todo.code.sourcephile.fr/~julm/symantic-base
+homepage: https://git.code.sourcephile.fr/~julm/symantic-base
 author: Julien Moutinho <julm+symantic-base@sourcephile.fr>
 copyright: Julien Moutinho <julm+symantic-base@sourcephile.fr>
 license: AGPL-3.0-or-later
@@ -10,7 +10,7 @@
 -- PVP:  +-+------- breaking API changes
 --       | | +----- non-breaking API additions
 --       | | | +--- code changes with no API change
-version: 0.2.0.20210831
+version: 0.3.0.20211007
 stability: experimental
 category: Data Structures
 synopsis: Basic symantics combinators for Embedded Domain-Specific Languages (EDSL)
@@ -18,7 +18,7 @@
   This is a work-in-progress collection of basic tagless-final combinators,
   along with some advanced utilities to exploit them.
 
-  * @Symantic.Lang@
+  * @Symantic.Class@
     gathers commonly used tagless-final combinators
     (the syntax part of symantics).
   * @Symantic.Data@ is an interpreter enabling to pattern-match on combinators,
@@ -52,6 +52,7 @@
 build-type: Simple
 tested-with: GHC==8.10.4
 extra-doc-files:
+  ChangeLog.md
 extra-source-files:
   cabal.project
   default.nix
@@ -63,18 +64,18 @@
 
 source-repository head
   type: git
-  location: https://git.hut.sourcephile.fr/~julm/symantic-base
+  location: https://git.code.sourcephile.fr/~julm/symantic-base
 
 library
   hs-source-dirs: src
   exposed-modules:
     Symantic
     Symantic.ADT
+    Symantic.Class
     Symantic.CurryN
     Symantic.Data
     Symantic.Derive
     Symantic.Fixity
-    Symantic.Lang
     Symantic.ObserveSharing
     Symantic.Optimize
     Symantic.Reify
@@ -102,9 +103,9 @@
     -Wpartial-fields
     -fprint-potential-instances
   build-depends:
-      base >= 4.10 && < 5,
-      containers,
-      hashable,
-      template-haskell,
-      transformers,
-      unordered-containers
+    base >= 4.10 && < 5,
+    containers,
+    hashable,
+    template-haskell,
+    transformers,
+    unordered-containers
