diff --git a/src/core/Type.js b/src/core/Type.js
new file mode 100644
index 0000000..79ebce2
--- /dev/null
+++ b/src/core/Type.js
@@ -0,0 +1,5 @@
+export class Type {
+   constructor(f) {
+      this.test = f
+   }
+}
diff --git a/src/core/TypeDispatcher.js b/src/core/TypeDispatcher.js
new file mode 100644
index 0000000..fe3334d
--- /dev/null
+++ b/src/core/TypeDispatcher.js
@@ -0,0 +1,37 @@
+import {Type} from './Type.js'
+import {Implementations, isPlainObject} from './helpers.js'
+
+export class TypeDispatcher {
+   constructor(...specs) {
+      for (const spec of specs) this.merge(spec)
+   }
+
+   merge(spec) {
+      if (!spec) return
+      if (typeof spec != 'object') {
+         throw new TypeError(
+            `TypeDispatcher specifications must be objects, not '${spec}'.`)
+      }
+      for (const key in spec) {
+         const val = spec[key]
+         if (val instanceof Type) {
+            console.log(`Pretending to install type ${key}: ${val}`)
+            continue
+         }
+         if (val instanceof Implementations) {
+            console.log(`Pretending to install implementations for ${key}`)
+            console.log(`  --> ${val}`)
+            continue
+         }
+         if (typeof val === 'function') {
+            console.log(`Pretend install of catchall implementation for ${key}`)
+            continue
+         }
+         if (isPlainObject(val)) {
+            this.merge(val)
+            continue
+         }
+         console.log(`Pretend install of catchall value for ${key}: ${val}`)
+      }
+   }
+}
diff --git a/src/core/helpers.js b/src/core/helpers.js
new file mode 100644
index 0000000..107eccd
--- /dev/null
+++ b/src/core/helpers.js
@@ -0,0 +1,27 @@
+import {Type} from './Type.js'
+
+export class Implementations {
+   constructor(imps) {
+      this.patterns = new Map()
+      for (let i = 0; i < imps.length; ++i) {
+         let pattern = imps[i++]
+         if (!Array.isArray(pattern)) pattern = [pattern]
+         if (!pattern.every(item => item instanceof Type)) {
+            throw new TypeError(
+               `Implementation pattern ${pattern} contains non-Type entry`)
+         }
+         this.patterns.set(pattern, imps[i])
+      }
+   }
+}
+
+export const onType = (...imps) => new Implementations(imps)
+
+export const Returns = (type, f) => (f.returns = type, f)
+
+export const isPlainObject = (obj) => {
+   if (typeof obj !== 'object') return false
+   if (!obj) return false // excludes null
+   const proto = Object.getPrototypeOf(obj)
+   return !proto || proto === Object.prototype
+}
diff --git a/src/nanomath.js b/src/nanomath.js
index 662e1ba..bd956fe 100644
--- a/src/nanomath.js
+++ b/src/nanomath.js
@@ -1,7 +1,6 @@
+import {TypeDispatcher} from './core/TypeDispatcher.js'
 import {numbers} from './numbers.js'
 
-for (const key in numbers) {
-    for (const subkey in numbers[key]) {
-        console.log(`${key}.${subkey} =`, numbers[key][subkey])
-    }
-}
+const math = new TypeDispatcher(numbers)
+
+export default math
diff --git a/src/number/Number.js b/src/number/Number.js
index 93f5837..00167b0 100644
--- a/src/number/Number.js
+++ b/src/number/Number.js
@@ -1,3 +1,3 @@
-export const Number = {
-   test: n => typeof n === 'number'
-}
+import {Type} from '../core/Type.js'
+
+export const Number = new Type(n => typeof n === 'number')
diff --git a/src/number/arithmetic.js b/src/number/arithmetic.js
index ebb26b7..b47eff2 100644
--- a/src/number/arithmetic.js
+++ b/src/number/arithmetic.js
@@ -1,4 +1,4 @@
-import {plain} from './tools.js'
+import {plain} from './helpers.js'
 
 export const abs = plain(Math.abs)
 export const absquare = plain(a => a*a)
diff --git a/src/number/helpers.js b/src/number/helpers.js
new file mode 100644
index 0000000..14fba17
--- /dev/null
+++ b/src/number/helpers.js
@@ -0,0 +1,5 @@
+import {Returns, onType} from '../core/helpers.js'
+import {Number} from './Number.js'
+
+export const plain = f => onType(
+   Array(f.length).fill(Number), Returns(Number, f))
diff --git a/src/number/tools.js b/src/number/tools.js
deleted file mode 100644
index da9fe1e..0000000
--- a/src/number/tools.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import {Number} from "./Number.js"
-
-export const plain = f =>
-   [Array(f.length).fill(Number), {returns: Number, behavior: f}]
diff --git a/src/number/type.js b/src/number/type.js
index eb241fe..4a963c9 100644
--- a/src/number/type.js
+++ b/src/number/type.js
@@ -1,4 +1,4 @@
-import {plain} from './tools.js'
+import {plain} from './helpers.js'
 
 // Not much to do so far when there is only one type
 export const number = plain(a => a)
diff --git a/src/number/utils.js b/src/number/utils.js
index d6b18bb..783d6c3 100644
--- a/src/number/utils.js
+++ b/src/number/utils.js
@@ -1,3 +1,3 @@
-import {plain} from './tools.js'
+import {plain} from './helpers.js'
 
 export const clone = plain(a => a)