diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for variadic-function
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Boris Lykah (c) 2021
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * 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.
+
+    * Neither the name of Boris Lykah nor the names of other
+      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
+OWNER 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,52 @@
+# variadic-function
+
+Create and transform functions with variable arity.
+
+### How to use
+
+The core of the library is the `Function` class. Use `createFunction` to make a function with a variable number of arguments. Use `transformFunction` to access the arguments and change the result of any function.
+
+
+```haskell
+constN :: Function f args a EmptyConstraint
+       => a -> f
+constN a = createFunction
+  -- The arguments are not constrained
+  (undefined :: p EmptyConstraint)
+  -- Combine argument with accumulator. Here we just ignore the argument
+  const
+  -- Ignore the accumulator and return `a` as a result
+  (const a)
+  -- Accumulator for combining with the arguments.
+  -- We don't take any information from the arguments, so it is just ()
+  ()
+
+composeN :: (Function f args b EmptyConstraint, Function g args a EmptyConstraint)
+         => (a -> b) -> g -> f
+composeN f = transformFunction
+  -- The arguments are not constrained
+  (undefined :: p EmptyConstraint)
+  -- Ignore arguments
+  const
+  -- Ignore the accumulator and apply f to result of the original function `g`
+  (\_ r -> f r)
+  -- Composition does not use the accumulator either, so it is ()
+  ()
+
+Here is a more complex example that constrains arguments and uses the accumulator:
+
+```haskell
+sumN :: forall r f args. (Function f args r ((~) r), Num r)
+     => f
+sumN = createFunction
+  -- The argument must be the same type as the function result. 
+  -- To be able to mention `r` in here, the function signature 
+  -- has `forall` and ScopedTypeVariables is enabled.
+  (undefined :: proxy ((~) r))
+  -- Add argument to the accumulator
+  (+)
+  -- Return accumulator as the result
+  id
+  -- The initial value of accumulator
+  0
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/src/Data/Function/Variadic.hs b/src/Data/Function/Variadic.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Function/Variadic.hs
@@ -0,0 +1,91 @@
+module Data.Function.Variadic
+  ( -- * Decomposition and creation of functions
+    Function (..),
+    ConstructFunction,
+    DeconstructFunction,
+
+    -- * Helper classes for argument constraints
+    EmptyConstraint,
+    type (&),
+  )
+where
+
+import Data.Kind (Type)
+
+-- | Toolkit for creating and transforming functions with a variable number of arguments.
+-- Its parameters are function, list of its arguments, its result, and `argC`
+-- that constraints all arguments of the function.
+class
+  (ConstructFunction args r ~ f, DeconstructFunction f ~ '(args, r)) =>
+  Function f args r argC
+  where
+  -- | Create a new function
+  --
+  -- === __Example usage__
+  --
+  -- >>> printf :: Function Show f args String => f
+  -- >>> printf = createFunction (Proxy :: Proxy Show) (\acc a -> acc <> show a) id ""
+  -- >>> printf "hello" () :: String
+  -- "hello()"
+  createFunction ::
+    -- | Required for unambiguous choice of Function instance
+    proxy argC ->
+    -- | Combine arguments with accumulator
+    (forall a. argC a => acc -> a -> acc) ->
+    -- | Make result of the function
+    (acc -> r) ->
+    -- | Accumulator
+    acc ->
+    f
+
+  -- | Create a function with the same arguments as given one but may have a different result.
+  transformFunction ::
+    -- | Required for unambiguous choice of the Function instance
+    proxy argC ->
+    -- | Combine arguments with accumulator
+    (forall a. argC a => acc -> a -> acc) ->
+    -- | Create result of the `f` function using accumulator and the result of the function to transform
+    (acc -> r0 -> r) ->
+    -- | Accumulator
+    acc ->
+    -- | The function to transform
+    ConstructFunction args r0 ->
+    -- | The new function
+    f
+
+-- | Extract list of arguments and the result from the function.
+type family DeconstructFunction (f :: Type) :: ([Type], Type) where
+  DeconstructFunction (a -> f) = MapFst ((:) a) (DeconstructFunction f)
+  DeconstructFunction x = '( '[], x)
+
+type family MapFst (f :: k1 -> k1) (tuple :: (k1, k2)) where
+  MapFst f '(a, b) = '(f a, b)
+
+-- | Given the types of function arguments and its result, make a type of a function.
+type family ConstructFunction (args :: [Type]) (r :: Type) where
+  ConstructFunction '[] r = r
+  ConstructFunction (a : args) r = a -> ConstructFunction args r
+
+instance
+  ('( '[], r) ~ DeconstructFunction r) =>
+  Function r '[] r argC
+  where
+  createFunction _ _ fr r = fr r
+  transformFunction _ _ fr acc r = fr acc r
+
+instance
+  (Function f args r argC, argC a) =>
+  Function (a -> f) (a : args) r argC
+  where
+  createFunction pArgC fa fr acc = createFunction pArgC fa fr . fa acc
+  transformFunction pArgC fa fr acc f = \a -> transformFunction pArgC fa fr (fa acc a) (f a)
+
+-- | When the arguments are not constrained, use this as the argC parameter of `Function`.
+class EmptyConstraint a
+
+instance EmptyConstraint a
+
+-- | Combine constraints. For example, @Function f args x (Show & Num)@.
+class (f x, g x) => (&) f g (x :: k)
+
+instance (f x, g x) => (&) f g x
diff --git a/src/Data/Function/Variadic/Utils.hs b/src/Data/Function/Variadic/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Function/Variadic/Utils.hs
@@ -0,0 +1,33 @@
+module Data.Function.Variadic.Utils
+  ( composeN,
+    constN,
+    mappendN,
+  )
+where
+
+import Data.Function.Variadic
+
+-- | Function composition for an arbitrary number of arguments.
+--
+-- >>> (show `composeN` \a b c -> (a + b + c :: Int)) 1 2 3
+-- "6"
+composeN :: (Function f args b EmptyConstraint, Function g args a EmptyConstraint) => (a -> b) -> g -> f
+composeN f = transformFunction (undefined :: p EmptyConstraint) const (\_ r -> f r) ()
+
+-- | Constant function for an arbitrary number of arguments.
+--
+-- @
+-- let const2 = constN :: x -> a -> b -> x
+-- @
+--
+-- >>> zipWith3 (constN 1) [1..10] [1..5] ["a", "b", "c"] :: [Int]
+-- [1,1,1]
+constN :: Function f args a EmptyConstraint => a -> f
+constN a = createFunction (undefined :: p EmptyConstraint) const (const a) ()
+
+-- | Append multiple monoid values. It is similar to `mconcat` but takes the values as arguments rather than list elements.
+--
+-- >>> mappendN [1, 2] [3] [4, 5] :: [Int]
+-- [1,2,3,4,5]
+mappendN :: forall r f args. (Function f args r ((~) r), Monoid r) => f
+mappendN = createFunction (undefined :: proxy ((~) r)) mappend id mempty
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE TypeApplications #-}
+
+import Data.Function.Variadic
+import Data.Function.Variadic.Utils
+import Test.Hspec
+
+main :: IO ()
+main = hspec $ do
+  describe "Variadic function" $ do
+    it "transforms function" $ do
+      let f :: Int -> Int -> Int -> String
+          f = show `composeN` \a b c -> a + b + c
+      f 1 2 3 `shouldBe` "6"
+    it "transforms function with inferred type" $ do
+      let f = show `composeN` \a b c -> (a + b + c :: Int)
+      f 1 2 3 `shouldBe` "6"
diff --git a/variadic-function.cabal b/variadic-function.cabal
new file mode 100644
--- /dev/null
+++ b/variadic-function.cabal
@@ -0,0 +1,76 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.34.4.
+--
+-- see: https://github.com/sol/hpack
+
+name:           variadic-function
+version:        0.1.0.0
+synopsis:       Create and transform functions with variable arity.
+description:    Please see the README on GitHub at <https://github.com/lykahb/variadic-function#readme>
+category:       Data, Functions
+homepage:       https://github.com/lykahb/variadic-function#readme
+bug-reports:    https://github.com/lykahb/variadic-function/issues
+author:         Boris Lykah
+maintainer:     lykahb@gmail.com
+copyright:      2021 Boris Lykah
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/lykahb/variadic-function
+
+library
+  exposed-modules:
+      Data.Function.Variadic
+      Data.Function.Variadic.Utils
+  other-modules:
+      Paths_variadic_function
+  hs-source-dirs:
+      src
+  default-extensions:
+      ConstraintKinds
+      DataKinds
+      FlexibleContexts
+      FlexibleInstances
+      MultiParamTypeClasses
+      PolyKinds
+      RankNTypes
+      TypeFamilies
+      TypeOperators
+      UndecidableInstances
+      UndecidableSuperClasses
+  build-depends:
+      base >=4.7 && <5
+  default-language: Haskell2010
+
+test-suite variadic-function-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_variadic_function
+  hs-source-dirs:
+      test
+  default-extensions:
+      ConstraintKinds
+      DataKinds
+      FlexibleContexts
+      FlexibleInstances
+      MultiParamTypeClasses
+      PolyKinds
+      RankNTypes
+      TypeFamilies
+      TypeOperators
+      UndecidableInstances
+      UndecidableSuperClasses
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , hspec
+    , variadic-function
+  default-language: Haskell2010
