diff --git a/FuncVarPattern.h b/FuncVarPattern.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5df46e0f0fb653b826a4567fbcc426f159411d3
--- /dev/null
+++ b/FuncVarPattern.h
@@ -0,0 +1,227 @@
+#ifndef fvp_FuncVarPattern_HH
+#define fvp_FuncVarPattern_HH
+#include <array>
+#include <cmath>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+// See the excellent Fluentcpp blog series on strong types.
+// https://www.fluentcpp.com/2017/05/23/strong-types-inheriting-functionalities-from-underlying/
+#include "NamedType/named_type.hpp"
+
+// function variable pattern = fvp
+namespace fvp {
+
+  using namespace fluent;
+
+  //@{
+  /** Helpers.
+   */
+  template <typename T>
+  struct is_tuple_impl : std::false_type {};
+  template <typename... Ts>
+  struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
+  template <typename T>
+  struct is_tuple : is_tuple_impl<std::decay_t<T>> {};
+  //@}
+
+  /** Named strong type helper.
+   *
+   */
+  template <typename Tag>
+  using Var = NamedType<double, Tag, Addable, Multiplicable, Printable,
+                        ImplicitlyConvertibleTo<double>::templ>;
+
+  /** Forward declaration of mixin.
+   *
+   */
+  template <typename>
+  struct ConstructedFunctionSet;
+
+  /** FunctionSet: new variables defined by functions.
+   *
+   *  \param FVars should be a FVariables template class.
+   *  \param Fs    is a tuple of lambdas that calculate values of NewVars_t
+   * types.
+   *
+   */
+  template <typename FVars, typename Fs,
+            typename = typename std::enable_if<is_tuple<Fs>::value>::type>
+  struct FunctionSet : FVars {
+    using IndependentVariables_t = typename FVars::IndependentVariables_t;
+    using InputVars_t            = typename FVars::InputVars_t;
+    using NewVars_t              = typename FVars::NewVars_t;
+    using Vars_t                 = typename FVars::Vars_t;
+    using VariableFuncs_t        = Fs;
+
+    static const size_t N_input_vars = FVars::N_input_vars;
+    static const size_t N_new_vars   = FVars::N_new_vars;
+    static const size_t N_vars       = FVars::N_vars;
+
+    VariableFuncs_t functions;
+
+    FunctionSet(const FVars& u, const Fs& f) : FVars(u), functions(f) {}
+    FunctionSet(const FunctionSet& fs) : FVars(fs), functions(fs.functions) {}
+
+    // void Print() const {}
+
+    constexpr Vars_t ComputeValues(const IndependentVariables_t& v) const {
+      if constexpr (std::is_same<IndependentVariables_t, InputVars_t>::value) {
+        return std::tuple_cat(v, ComputeNewVars(v));
+      } else {
+        auto vars = FVars::input_variable_set.ComputeValues(v);
+        return std::tuple_cat(vars, ComputeNewVars(vars));
+      }
+    }
+
+    template <std::size_t I, typename F, typename Args>
+    static constexpr auto eval_vars2(const F& f, const Args& a) {
+      using Return_t = typename std::tuple_element<I, NewVars_t>::type;
+      return Return_t{f(a)};
+    }
+    template <typename Funcs, typename Args, std::size_t... I>
+    static constexpr auto eval_vars(const Funcs& f, const Args& a, std::index_sequence<I...>) {
+      return std::make_tuple(eval_vars2<I>(std::get<I>(f), a)...);
+    }
+    constexpr auto ComputeNewVars(const InputVars_t& v) const {
+      return eval_vars(functions, v, std::make_index_sequence<N_new_vars>{});
+    }
+    constexpr auto operator()(const InputVars_t& v) const { return ComputeNewVars(v); }
+  };
+
+  /** Definable Function Variables.
+   *
+   *  Used to construct a FunctionSet from lambdas and wraps the lambda
+   *  arguments with a set of standard variables.
+   *
+   * \param FVars Function variables.
+   * \param Mixin Mixin which adds the ability to declare/define more variables
+   * to FVariables..
+   *
+   */
+  template <typename FVars, template <typename> class Mixin>
+  struct Definable : FVars {
+    using InputVars_t = typename FVars::InputVars_t;
+    using NewVars_t   = typename FVars::NewVars_t;
+    // using FVars::Print;
+
+    template <typename... Ts>
+    Definable(Ts&&... t) : FVars(std::forward<Ts>(t)...) {}
+
+    template <typename... Funcs>
+    constexpr auto operator()(const Funcs&... fs) const noexcept {
+      return t2t_impl(*this, std::make_tuple(fs...), std::make_index_sequence<sizeof...(fs)>{});
+    }
+
+    template <typename TUP, std::size_t... I>
+    static constexpr auto t2t_impl(const Definable<FVars, Mixin>& fd, const TUP& t,
+                                   std::index_sequence<I...>) noexcept {
+      constexpr auto l_wrap = [](const auto& f) constexpr {
+        return [&](const InputVars_t& args) { return f(args); };
+      };
+      using type = decltype(std::make_tuple(l_wrap(std::get<I>(t))...));
+      return Mixin<FunctionSet<FVars, type>>(FVars{fd}, std::make_tuple(l_wrap(std::get<I>(t))...));
+    }
+  };
+
+  /** Function Variables (to be defined with a lambda).
+   *
+   *  \param VarSet     is the previously defined variables
+   *  \param NewVars... is a pack of new types computed from the InputVars.
+   *
+   *  Note the functions relating the new to the old have not yet been
+   * specified..
+   *
+   */
+  template <typename VarSet, typename... NewVars>
+  struct FVariables {
+    using VarSet_t               = VarSet;
+    using IndependentVariables_t = typename VarSet::IndependentVariables_t;
+    using InputVars_t            = typename VarSet::Vars_t;
+    using NewVars_t              = std::tuple<NewVars...>;
+    using Vars_t = decltype(std::tuple_cat(std::declval<InputVars_t>(), std::declval<NewVars_t>()));
+    static const size_t N_input_vars = std::tuple_size<InputVars_t>::value;
+    static const size_t N_new_vars   = std::tuple_size<NewVars_t>::value;
+    static const size_t N_vars       = std::tuple_size<Vars_t>::value;
+
+    VarSet_t input_variable_set;
+
+    FVariables() noexcept {}
+    FVariables(const VarSet& f) noexcept : input_variable_set(f) {}
+    FVariables(const FVariables& t) noexcept : input_variable_set(t.input_variable_set) {}
+
+    // void Print() const {
+    //  // std::cout << __PRETTY_FUNCTION__ << "\n";
+    //}
+  };
+
+  /** Function variable specialization where the variable is an independent variable nad thus has no
+   * lambda to calculate it. The pack Vs should be left empty.
+   */
+  template <typename... InVars, typename... Vs>
+  struct FVariables<std::tuple<InVars...>, Vs...> {
+    using IndependentVariables_t = std::tuple<InVars...>;
+    using InputVars_t            = IndependentVariables_t;
+    using NewVars_t              = std::tuple<Vs...>;
+    using Vars_t = decltype(std::tuple_cat(std::declval<InputVars_t>(), std::declval<NewVars_t>()));
+    static const size_t N_input_vars = std::tuple_size<InputVars_t>::value;
+    static const size_t N_new_vars   = std::tuple_size<NewVars_t>::value;
+    static const size_t N_vars       = std::tuple_size<Vars_t>::value;
+
+    constexpr FVariables() noexcept {}
+
+    // void Print() const {
+    //  // std::cout << __PRETTY_FUNCTION__ << "\n";
+    //}
+  };
+
+  /** Mixin class for FunctionSet that adds the ability to add more variables.
+   * \param M is a FunctionSet< FV<FS,NewVars>, lambdas... >
+   */
+  template <typename M>
+  struct ConstructedFunctionSet : M {
+
+    ConstructedFunctionSet(const ConstructedFunctionSet& fs) : M(fs) {}
+
+    template <typename... Ts>
+    constexpr ConstructedFunctionSet(Ts&&... t) noexcept : M(std::forward<Ts>(t)...) {}
+
+    template <typename... Vs>
+    constexpr auto make_vars() const noexcept {
+      return Definable<FVariables<M, Vs...>, ConstructedFunctionSet>(M(*this));
+    }
+    template <typename... Vs, typename... Fs>
+    constexpr auto add(const Fs&... fs) const noexcept {
+      return make_vars<Vs...>()(fs...);
+    }
+  };
+
+  template <typename T, typename... Vs>
+  auto make_vars() {
+    return Definable<FVariables<T, Vs...>, ConstructedFunctionSet>{};
+  }
+
+  /** Helper making independent vars using FVariables specialization.
+   */
+  template <typename... Vs>
+  auto make_independent_vars() {
+    return Definable<FVariables<std::tuple<Vs...>>, ConstructedFunctionSet>{}();
+  }
+
+  template <class...>
+  struct is_FunctionSet : public std::false_type {};
+
+  template <class... Vs>
+  struct is_FunctionSet<ConstructedFunctionSet<Vs...>> : public std::true_type {};
+
+  template <class... Vs>
+  struct is_FunctionSet<FunctionSet<Vs...>> : public std::true_type {};
+
+} // namespace fvp
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2098abdb2775b1186a4983c9b102eb6294e20c70
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+all : func_pattern kinematics
+
+func_pattern : func_pattern.cxx
+	g++ -o test -std=c++17  func_pattern.cxx -I.
+
+test_asm_O3 : func_pattern.cxx
+	g++ -S -o test3.asm -std=c++17  func_pattern.cxx -I. -O3
+
+test_asm_O0 : func_pattern.cxx
+	g++ -S -o test0.asm -std=c++17  func_pattern.cxx -I. -O0
+
+kinematics : FuncVarPattern.h kinematics.cxx
+	g++ -o kinematics -std=c++17  kinematics.cxx -I. -O3
+
+kinematics_O0 : FuncVarPattern.h kinematics.cxx
+	g++ -S -o kinematics0.asm -std=c++17  kinematics.cxx -I. -O0
+
+kinematics_O3 : FuncVarPattern.h kinematics.cxx
+	g++ -S -o kinematics3.asm -std=c++17  kinematics.cxx -I. -O3
+
+
+clean:
+	rm -f kinematics
+	rm -f test
+	rm -f test0.asm
+	rm -f test3.asm
+	rm -f kinematics0.asm
+	rm -f kinematics3.asm
+
+
diff --git a/kinematics.cxx b/kinematics.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ae6d7efd621a4ab520d0d08945d13dca1780d47c
--- /dev/null
+++ b/kinematics.cxx
@@ -0,0 +1,77 @@
+#include "FuncVarPattern.h"
+
+
+int main() {
+  using namespace fvp;
+
+  // Note in the future meta classes might help with the type/tag declarations
+  using E_beam_v  = Var<struct E_beam_tag>;
+  using E_prime_v = Var<struct E_prime_tag>;
+  using theta_v   = Var<struct theta_tag>;
+
+  using Q2_v = Var<struct Q2_tag>;
+  using nu_v = Var<struct nu_tag>;
+  using x_v  = Var<struct x_tag>;
+  using y_v  = Var<struct y_tag>;
+  using W_v  = Var<struct W_tag>;
+
+  double M_p = 0.938;
+
+  auto measured_vars = make_independent_vars<E_beam_v, E_prime_v, theta_v>();
+
+  auto dis_kine_vars = measured_vars
+  .add<Q2_v, nu_v>(
+      [](const auto& v) constexpr {
+        const auto&  E0    = std::get<E_beam_v>(v);
+        const auto&  Ep    = std::get<E_prime_v>(v);
+        const auto&  th    = std::get<theta_v>(v);
+        const double M_p = 0.938;
+        const double sinth = std::sin(th / 2.0);
+        return 4.0 * E0 * Ep * sinth * sinth;
+      },
+      [](const auto& v) constexpr {
+        const auto& E0 = std::get<E_beam_v>(v);
+        const auto& Ep = std::get<E_prime_v>(v);
+        return E0 - Ep;
+      }) // note that we are chaining here.
+  .add<x_v, y_v>(
+      [](const auto& v) constexpr {
+        // calculate x
+        const auto&  Q2    = std::get<Q2_v>(v);
+        const auto&  nu    = std::get<nu_v>(v);
+        //std::cout << Q2 << "\n";
+        //std::cout << nu << "\n";
+        double M_p = 0.938;
+        return Q2/(2.0*M_p*nu);
+      },
+      [](const auto& v) constexpr {
+        //calculate y
+        const auto& E0 = std::get<E_beam_v>(v);
+        const auto& nu = std::get<nu_v>(v);
+        return nu/E0;
+      })
+  .add<W_v>(
+      [](const auto& v) constexpr {
+        // calculate W
+        const double M_p = 0.938;
+        const auto&  Q2    = std::get<Q2_v>(v);
+        const auto&  nu    = std::get<nu_v>(v);
+        return std::sqrt(M_p*M_p - Q2 + 2.0*M_p*nu);
+      });
+
+  auto input = std::make_tuple(E_beam_v{10.6}, E_prime_v{4.7}, theta_v{17.0*M_PI/180.0});
+
+  auto dis_values = dis_kine_vars.ComputeValues(input);
+
+  // could probably make this better, like: dis_values.get<x_v>()
+  std::cout << " E0  = " << std::get<E_beam_v>(dis_values) << "\n";
+  std::cout << " E'  = " << std::get<E_prime_v>(dis_values) << "\n";
+  std::cout << " th  = " << std::get<theta_v>(dis_values)*180.0/M_PI << "\n";
+  std::cout << " Q2  = " << std::get<Q2_v>(dis_values) << "\n";
+  std::cout << " x   = " << std::get<x_v>(dis_values) << "\n";
+  std::cout << " W   = " << std::get<W_v>(dis_values) << "\n";
+  std::cout << " y   = " << std::get<y_v>(dis_values) << "\n";
+  std::cout << " nu  = " << std::get<nu_v>(dis_values) << "\n";
+
+}
+